Files
tlib/oversampling/WDL/wdlstring.h
2024-05-24 13:28:31 +02:00

428 lines
13 KiB
C++

/*
WDL - wdlstring.h
Copyright (C) 2005 and later, Cockos Incorporated
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
This file provides a simple class for variable-length string manipulation.
It provides only the simplest features, and does not do anything confusing like
operator overloading. It uses a WDL_HeapBuf for internal storage.
Actually: there are WDL_String and WDL_FastString -- the latter's Get() returns const char, and tracks
the length of the string, which is often faster. Because of this, you are not permitted to directly modify
the buffer returned by Get().
*/
#ifndef _WDL_STRING_H_
#define _WDL_STRING_H_
#include "heapbuf.h"
#include <stdio.h>
#include <stdarg.h>
#ifndef WDL_STRING_IMPL_ONLY
class WDL_String
{
public:
#ifdef WDL_STRING_INTF_ONLY
void Set(const char *str, int maxlen=0);
void Set(const WDL_String *str, int maxlen=0);
void Append(const char *str, int maxlen=0);
void Append(const WDL_String *str, int maxlen=0);
void DeleteSub(int position, int len);
void Insert(const char *str, int position, int maxlen=0);
void Insert(const WDL_String *str, int position, int maxlen=0);
#ifdef WDL_STRING_FASTSUB_DEFINED
bool SetLen(int length, bool resizeDown=false, char fillchar=' '); // returns true on success
#else
bool SetLen(int length, bool resizeDown=false); // returns true on success
#endif
void Ellipsize(int minlen, int maxlen);
const char *get_filepart() const; // returns whole string if no dir chars
const char *get_fileext() const; // returns ".ext" or end of string "" if no extension
bool remove_fileext(); // returns true if extension was removed
char remove_filepart(bool keepTrailingSlash=false); // returns dir character used, or zero if string emptied
int remove_trailing_dirchars(); // returns trailing dirchar count removed, will not convert "/" into ""
void SetAppendFormattedArgs(bool append, int maxlen, const char* fmt, va_list arglist);
void WDL_VARARG_WARN(printf,3,4) SetFormatted(int maxlen, const char *fmt, ...);
void WDL_VARARG_WARN(printf,3,4) AppendFormatted(int maxlen, const char *fmt, ...);
#endif
const char *Get() const { return m_hb.GetSize()?(char*)m_hb.Get():""; }
#ifdef WDL_STRING_FASTSUB_DEFINED
int GetLength() const { int a = m_hb.GetSize(); return a>0?a-1:0; }
// for binary-safe manipulations
void SetRaw(const char *str, int len) { __doSet(0,str,len,0); }
void AppendRaw(const char *str, int len) { __doSet(GetLength(),str,len,0); }
void InsertRaw(const char *str, int position, int ilen)
{
const int srclen = GetLength();
if (position<0) position=0;
else if (position>srclen) position=srclen;
if (ilen>0) __doSet(position,str,ilen,srclen-position);
}
#else
char *Get()
{
if (m_hb.GetSize()) return (char *)m_hb.Get();
static char c; c=0; return &c; // don't return "", in case it gets written to.
}
int GetLength() const { return m_hb.GetSize()?(int)strlen((const char*)m_hb.Get()):0; }
#endif
explicit WDL_String(int hbgran) : m_hb(hbgran WDL_HEAPBUF_TRACEPARM("WDL_String(4)")) { }
explicit WDL_String(const char *initial=NULL, int initial_len=0) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String"))
{
if (initial) Set(initial,initial_len);
}
WDL_String(const WDL_String &s) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String(2)")) { Set(&s); }
WDL_String(const WDL_String *s) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String(3)")) { if (s && s != this) Set(s); }
~WDL_String() { }
#endif // ! WDL_STRING_IMPL_ONLY
#ifndef WDL_STRING_INTF_ONLY
#ifdef WDL_STRING_IMPL_ONLY
#define WDL_STRING_FUNCPREFIX WDL_String::
#define WDL_STRING_DEFPARM(x)
#else
#define WDL_STRING_FUNCPREFIX
#define WDL_STRING_DEFPARM(x) =(x)
#endif
void WDL_STRING_FUNCPREFIX Set(const char *str, int maxlen WDL_STRING_DEFPARM(0))
{
int s=0;
if (str)
{
if (maxlen>0) while (s < maxlen && str[s]) s++;
else s=(int)strlen(str);
}
__doSet(0,str,s,0);
}
void WDL_STRING_FUNCPREFIX Set(const WDL_String *str, int maxlen WDL_STRING_DEFPARM(0))
{
#ifdef WDL_STRING_FASTSUB_DEFINED
int s = str ? str->GetLength() : 0;
if (maxlen>0 && maxlen<s) s=maxlen;
__doSet(0,str?str->Get():NULL,s,0);
#else
Set(str?str->Get():NULL, maxlen); // might be faster: "partial" strlen
#endif
}
void WDL_STRING_FUNCPREFIX Append(const char *str, int maxlen WDL_STRING_DEFPARM(0))
{
int s=0;
if (str)
{
if (maxlen>0) while (s < maxlen && str[s]) s++;
else s=(int)strlen(str);
}
__doSet(GetLength(),str,s,0);
}
void WDL_STRING_FUNCPREFIX Append(const WDL_String *str, int maxlen WDL_STRING_DEFPARM(0))
{
#ifdef WDL_STRING_FASTSUB_DEFINED
int s = str ? str->GetLength() : 0;
if (maxlen>0 && maxlen<s) s=maxlen;
__doSet(GetLength(),str?str->Get():NULL,s,0);
#else
Append(str?str->Get():NULL, maxlen); // might be faster: "partial" strlen
#endif
}
void WDL_STRING_FUNCPREFIX DeleteSub(int position, int len)
{
int l=m_hb.GetSize()-1;
char *p=(char *)m_hb.Get();
if (l<0 || !*p || position < 0 || position >= l) return;
if (position+len > l) len=l-position;
if (len>0)
{
memmove(p+position,p+position+len,l-position-len+1);
m_hb.Resize(l+1-len,false);
}
}
void WDL_STRING_FUNCPREFIX Insert(const char *str, int position, int maxlen WDL_STRING_DEFPARM(0))
{
int ilen=0;
if (str)
{
if (maxlen>0) while (ilen < maxlen && str[ilen]) ilen++;
else ilen=(int)strlen(str);
}
const int srclen = GetLength();
if (position<0) position=0;
else if (position>srclen) position=srclen;
if (ilen>0) __doSet(position,str,ilen,srclen-position);
}
void WDL_STRING_FUNCPREFIX Insert(const WDL_String *str, int position, int maxlen WDL_STRING_DEFPARM(0))
{
#ifdef WDL_STRING_FASTSUB_DEFINED
int ilen = str ? str->GetLength() : 0;
if (maxlen>0 && maxlen<ilen) ilen=maxlen;
const int srclen = m_hb.GetSize()>0 ? m_hb.GetSize()-1 : 0;
if (position<0) position=0;
else if (position>srclen) position=srclen;
if (ilen>0) __doSet(position,str->Get(),ilen,srclen-position);
#else
Insert(str?str->Get():NULL, position, maxlen); // might be faster: "partial" strlen
#endif
}
bool WDL_STRING_FUNCPREFIX SetLen(int length, bool resizeDown WDL_STRING_DEFPARM(false)
#ifdef WDL_STRING_FASTSUB_DEFINED
, char fillchar WDL_STRING_DEFPARM(' ')
#endif
)
{
#ifdef WDL_STRING_FASTSUB_DEFINED
int osz = m_hb.GetSize()-1;
if (osz<0)osz=0;
#endif
if (length < 0) length=0;
char *b=(char*)m_hb.ResizeOK(length+1,resizeDown);
if (b)
{
#ifdef WDL_STRING_FASTSUB_DEFINED
const int fill = length-osz;
if (fill > 0) memset(b+osz,fillchar,fill);
#endif
b[length]=0;
return true;
}
return false;
}
void WDL_STRING_FUNCPREFIX SetAppendFormattedArgs(bool append, int maxlen, const char* fmt, va_list arglist)
{
int offs = append ? GetLength() : 0;
char *b= (char*) m_hb.ResizeOK(offs+maxlen+1,false);
if (!b) return;
b+=offs;
#ifdef _WIN32
int written = _vsnprintf(b, maxlen+1, fmt, arglist);
if (written < 0 || written>=maxlen) b[written=b[0]?maxlen:0]=0;
#else
int written = vsnprintf(b, maxlen+1, fmt, arglist);
if (written > maxlen) written=maxlen;
#endif
m_hb.Resize(offs + written + 1,false);
}
void WDL_VARARG_WARN(printf,3,4) WDL_STRING_FUNCPREFIX SetFormatted(int maxlen, const char *fmt, ...)
{
va_list arglist;
va_start(arglist, fmt);
SetAppendFormattedArgs(false,maxlen,fmt,arglist);
va_end(arglist);
}
void WDL_VARARG_WARN(printf,3,4) WDL_STRING_FUNCPREFIX AppendFormatted(int maxlen, const char *fmt, ...)
{
va_list arglist;
va_start(arglist, fmt);
SetAppendFormattedArgs(true,maxlen,fmt,arglist);
va_end(arglist);
}
void WDL_STRING_FUNCPREFIX Ellipsize(int minlen, int maxlen)
{
if (maxlen >= 4 && m_hb.GetSize() && GetLength() > maxlen)
{
if (minlen<0) minlen=0;
char *b = (char *)m_hb.Get();
int i;
for (i = maxlen-4; i >= minlen; --i)
{
if (b[i] == ' ')
{
memcpy(b+i, "...",4);
m_hb.Resize(i+4,false);
break;
}
}
if (i < minlen && maxlen >= 4)
{
memcpy(b+maxlen-4, "...",4);
m_hb.Resize(maxlen,false);
}
}
}
const char * WDL_STRING_FUNCPREFIX get_filepart() const // returns whole string if no dir chars
{
const char *s = Get();
const char *p = s + GetLength() - 1;
while (p >= s && !WDL_IS_DIRCHAR(*p)) --p;
return p + 1;
}
const char * WDL_STRING_FUNCPREFIX get_fileext() const // returns ".ext" or end of string "" if no extension
{
const char *s = Get();
const char *endp = s + GetLength();
const char *p = endp - 1;
while (p >= s && !WDL_IS_DIRCHAR(*p))
{
if (*p == '.') return p;
--p;
}
return endp;
}
bool WDL_STRING_FUNCPREFIX remove_fileext() // returns true if extension was removed
{
const char *str = Get();
int pos = GetLength() - 1;
while (pos >= 0)
{
char c = str[pos];
if (WDL_IS_DIRCHAR(c)) break;
if (c == '.')
{
SetLen(pos);
return true;
}
--pos;
}
return false;
}
char WDL_STRING_FUNCPREFIX remove_filepart(bool keepTrailingSlash WDL_STRING_DEFPARM(false)) // returns directory character used, or 0 if string emptied
{
char rv=0;
const char *str = Get();
int pos = GetLength() - 1;
while (pos > 0)
{
char c = str[pos];
if (WDL_IS_DIRCHAR(c))
{
rv=c;
if (keepTrailingSlash) ++pos;
break;
}
--pos;
}
SetLen(pos);
return rv;
}
int WDL_STRING_FUNCPREFIX remove_trailing_dirchars() // returns trailing dirchar count removed
{
int cnt = 0;
const char *str = Get();
const int l = GetLength()-1;
while (cnt < l)
{
char c = str[l - cnt];
if (!WDL_IS_DIRCHAR(c)) break;
++cnt;
}
if (cnt > 0) SetLen(l + 1 - cnt);
return cnt;
}
#ifndef WDL_STRING_IMPL_ONLY
private:
#endif
void WDL_STRING_FUNCPREFIX __doSet(int offs, const char *str, int len, int trailkeep)
{
// if non-empty, or (empty and allocated and Set() rather than append/insert), then allow update, otherwise do nothing
if (len==0 && !trailkeep && !offs)
{
#ifdef WDL_STRING_FREE_ON_CLEAR
m_hb.Resize(0,true);
#else
char *p = (char *)m_hb.Resize(1,false);
if (p) *p=0;
#endif
}
else if (len>0 && offs >= 0)
{
const int oldsz = m_hb.GetSize();
const int newsz=offs+len+trailkeep+1;
const int growamt = newsz-oldsz;
if (growamt > 0)
{
const char *oldb = (const char *)m_hb.Get();
const char *newb = (const char *)m_hb.Resize(newsz,false); // resize up if necessary
// in case str overlaps with input, keep it valid
if (str && newb != oldb && str >= oldb && str < oldb+oldsz) str = newb + (str - oldb);
}
if (m_hb.GetSize() >= newsz)
{
char *newbuf = (char *)m_hb.Get();
if (trailkeep>0) memmove(newbuf+offs+len,newbuf+offs,trailkeep);
if (str) memmove(newbuf+offs,str,len);
newbuf[newsz-1]=0;
// resize down if necessary
if (growamt < 0) m_hb.Resize(newsz,false);
}
}
}
#undef WDL_STRING_FUNCPREFIX
#undef WDL_STRING_DEFPARM
#endif // ! WDL_STRING_INTF_ONLY
#ifndef WDL_STRING_IMPL_ONLY
private:
#ifdef WDL_STRING_INTF_ONLY
void __doSet(int offs, const char *str, int len, int trailkeep);
#endif
WDL_HeapBuf m_hb;
};
#endif
#ifndef WDL_STRING_FASTSUB_DEFINED
#undef _WDL_STRING_H_
#define WDL_STRING_FASTSUB_DEFINED
#define WDL_String WDL_FastString
#include "wdlstring.h"
#undef WDL_STRING_FASTSUB_DEFINED
#undef WDL_String
#endif
#endif