Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / wdlstring.h
blobaefdbbc8b300985a183b96a6db040e4dd39e6e6b
1 /*
2 WDL - wdlstring.h
3 Copyright (C) 2005 and later, Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
25 This file provides a simple class for variable-length string manipulation.
26 It provides only the simplest features, and does not do anything confusing like
27 operator overloading. It uses a WDL_HeapBuf for internal storage.
29 Actually: there are WDL_String and WDL_FastString -- the latter's Get() returns const char, and tracks
30 the length of the string, which is often faster. Because of this, you are not permitted to directly modify
31 the buffer returned by Get().
36 #ifndef _WDL_STRING_H_
37 #define _WDL_STRING_H_
39 #include "heapbuf.h"
40 #include <stdio.h>
41 #include <stdarg.h>
43 #ifndef WDL_STRING_IMPL_ONLY
44 class WDL_String
46 public:
47 #ifdef WDL_STRING_INTF_ONLY
48 void Set(const char *str, int maxlen=0);
49 void Set(const WDL_String *str, int maxlen=0);
50 void Append(const char *str, int maxlen=0);
51 void Append(const WDL_String *str, int maxlen=0);
52 void DeleteSub(int position, int len);
53 void Insert(const char *str, int position, int maxlen=0);
54 void Insert(const WDL_String *str, int position, int maxlen=0);
55 bool SetLen(int length, bool resizeDown=false); // returns true on success
56 void Ellipsize(int minlen, int maxlen);
57 const char *get_filepart() const; // returns whole string if no dir chars
58 const char *get_fileext() const; // returns ".ext" or end of string "" if no extension
59 bool remove_fileext(); // returns true if extension was removed
60 char remove_filepart(bool keepTrailingSlash=false); // returns dir character used, or zero if string emptied
61 int remove_trailing_dirchars(); // returns trailing dirchar count removed, will not convert "/" into ""
63 void SetAppendFormattedArgs(bool append, int maxlen, const char* fmt, va_list arglist);
64 void WDL_VARARG_WARN(printf,3,4) SetFormatted(int maxlen, const char *fmt, ...);
65 void WDL_VARARG_WARN(printf,3,4) AppendFormatted(int maxlen, const char *fmt, ...);
66 #endif
68 const char *Get() const { return m_hb.GetSize()?(char*)m_hb.Get():""; }
70 #ifdef WDL_STRING_FASTSUB_DEFINED
71 int GetLength() const { int a = m_hb.GetSize(); return a>0?a-1:0; }
73 // for binary-safe manipulations
74 void SetRaw(const char *str, int len) { __doSet(0,str,len,0); }
75 void AppendRaw(const char *str, int len) { __doSet(GetLength(),str,len,0); }
76 void InsertRaw(const char *str, int position, int ilen)
78 const int srclen = GetLength();
79 if (position<0) position=0;
80 else if (position>srclen) position=srclen;
81 if (ilen>0) __doSet(position,str,ilen,srclen-position);
84 #else
85 char *Get()
87 if (m_hb.GetSize()) return (char *)m_hb.Get();
88 static char c; c=0; return &c; // don't return "", in case it gets written to.
90 int GetLength() const { return m_hb.GetSize()?(int)strlen((const char*)m_hb.Get()):0; }
91 #endif
93 explicit WDL_String(int hbgran) : m_hb(hbgran WDL_HEAPBUF_TRACEPARM("WDL_String(4)")) { }
94 explicit WDL_String(const char *initial=NULL, int initial_len=0) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String"))
96 if (initial) Set(initial,initial_len);
98 WDL_String(const WDL_String &s) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String(2)")) { Set(&s); }
99 WDL_String(const WDL_String *s) : m_hb(128 WDL_HEAPBUF_TRACEPARM("WDL_String(3)")) { if (s && s != this) Set(s); }
100 ~WDL_String() { }
101 #endif // ! WDL_STRING_IMPL_ONLY
103 #ifndef WDL_STRING_INTF_ONLY
104 #ifdef WDL_STRING_IMPL_ONLY
105 #define WDL_STRING_FUNCPREFIX WDL_String::
106 #define WDL_STRING_DEFPARM(x)
107 #else
108 #define WDL_STRING_FUNCPREFIX
109 #define WDL_STRING_DEFPARM(x) =(x)
110 #endif
112 void WDL_STRING_FUNCPREFIX Set(const char *str, int maxlen WDL_STRING_DEFPARM(0))
114 int s=0;
115 if (str)
117 if (maxlen>0) while (s < maxlen && str[s]) s++;
118 else s=(int)strlen(str);
120 __doSet(0,str,s,0);
123 void WDL_STRING_FUNCPREFIX Set(const WDL_String *str, int maxlen WDL_STRING_DEFPARM(0))
125 #ifdef WDL_STRING_FASTSUB_DEFINED
126 int s = str ? str->GetLength() : 0;
127 if (maxlen>0 && maxlen<s) s=maxlen;
129 __doSet(0,str?str->Get():NULL,s,0);
130 #else
131 Set(str?str->Get():NULL, maxlen); // might be faster: "partial" strlen
132 #endif
135 void WDL_STRING_FUNCPREFIX Append(const char *str, int maxlen WDL_STRING_DEFPARM(0))
137 int s=0;
138 if (str)
140 if (maxlen>0) while (s < maxlen && str[s]) s++;
141 else s=(int)strlen(str);
144 __doSet(GetLength(),str,s,0);
147 void WDL_STRING_FUNCPREFIX Append(const WDL_String *str, int maxlen WDL_STRING_DEFPARM(0))
149 #ifdef WDL_STRING_FASTSUB_DEFINED
150 int s = str ? str->GetLength() : 0;
151 if (maxlen>0 && maxlen<s) s=maxlen;
153 __doSet(GetLength(),str?str->Get():NULL,s,0);
154 #else
155 Append(str?str->Get():NULL, maxlen); // might be faster: "partial" strlen
156 #endif
159 void WDL_STRING_FUNCPREFIX DeleteSub(int position, int len)
161 int l=m_hb.GetSize()-1;
162 char *p=(char *)m_hb.Get();
163 if (l<0 || !*p || position < 0 || position >= l) return;
164 if (position+len > l) len=l-position;
165 if (len>0)
167 memmove(p+position,p+position+len,l-position-len+1);
168 m_hb.Resize(l+1-len,false);
172 void WDL_STRING_FUNCPREFIX Insert(const char *str, int position, int maxlen WDL_STRING_DEFPARM(0))
174 int ilen=0;
175 if (str)
177 if (maxlen>0) while (ilen < maxlen && str[ilen]) ilen++;
178 else ilen=(int)strlen(str);
181 const int srclen = GetLength();
182 if (position<0) position=0;
183 else if (position>srclen) position=srclen;
184 if (ilen>0) __doSet(position,str,ilen,srclen-position);
187 void WDL_STRING_FUNCPREFIX Insert(const WDL_String *str, int position, int maxlen WDL_STRING_DEFPARM(0))
189 #ifdef WDL_STRING_FASTSUB_DEFINED
190 int ilen = str ? str->GetLength() : 0;
191 if (maxlen>0 && maxlen<ilen) ilen=maxlen;
193 const int srclen = m_hb.GetSize()>0 ? m_hb.GetSize()-1 : 0;
194 if (position<0) position=0;
195 else if (position>srclen) position=srclen;
196 if (ilen>0) __doSet(position,str->Get(),ilen,srclen-position);
197 #else
198 Insert(str?str->Get():NULL, position, maxlen); // might be faster: "partial" strlen
199 #endif
202 bool WDL_STRING_FUNCPREFIX SetLen(int length, bool resizeDown WDL_STRING_DEFPARM(false))
204 #ifdef WDL_STRING_FASTSUB_DEFINED
205 int osz = m_hb.GetSize()-1;
206 if (osz<0)osz=0;
207 #endif
208 if (length < 0) length=0;
209 char *b=(char*)m_hb.ResizeOK(length+1,resizeDown);
210 if (b)
212 #ifdef WDL_STRING_FASTSUB_DEFINED
213 const int fill = length-osz;
214 if (fill > 0) memset(b+osz,' ',fill);
215 #endif
216 b[length]=0;
217 return true;
219 return false;
222 void WDL_STRING_FUNCPREFIX SetAppendFormattedArgs(bool append, int maxlen, const char* fmt, va_list arglist)
224 int offs = append ? GetLength() : 0;
225 char *b= (char*) m_hb.ResizeOK(offs+maxlen+1,false);
227 if (!b) return;
229 b+=offs;
231 #ifdef _WIN32
232 int written = _vsnprintf(b, maxlen+1, fmt, arglist);
233 if (written < 0 || written>=maxlen) b[written=b[0]?maxlen:0]=0;
234 #else
235 int written = vsnprintf(b, maxlen+1, fmt, arglist);
236 if (written > maxlen) written=maxlen;
237 #endif
239 m_hb.Resize(offs + written + 1,false);
242 void WDL_VARARG_WARN(printf,3,4) WDL_STRING_FUNCPREFIX SetFormatted(int maxlen, const char *fmt, ...)
244 va_list arglist;
245 va_start(arglist, fmt);
246 SetAppendFormattedArgs(false,maxlen,fmt,arglist);
247 va_end(arglist);
250 void WDL_VARARG_WARN(printf,3,4) WDL_STRING_FUNCPREFIX AppendFormatted(int maxlen, const char *fmt, ...)
252 va_list arglist;
253 va_start(arglist, fmt);
254 SetAppendFormattedArgs(true,maxlen,fmt,arglist);
255 va_end(arglist);
258 void WDL_STRING_FUNCPREFIX Ellipsize(int minlen, int maxlen)
260 if (maxlen >= 4 && m_hb.GetSize() && GetLength() > maxlen)
262 if (minlen<0) minlen=0;
263 char *b = (char *)m_hb.Get();
264 int i;
265 for (i = maxlen-4; i >= minlen; --i)
267 if (b[i] == ' ')
269 memcpy(b+i, "...",4);
270 m_hb.Resize(i+4,false);
271 break;
274 if (i < minlen && maxlen >= 4)
276 memcpy(b+maxlen-4, "...",4);
277 m_hb.Resize(maxlen,false);
281 const char * WDL_STRING_FUNCPREFIX get_filepart() const // returns whole string if no dir chars
283 const char *s = Get();
284 const char *p = s + GetLength() - 1;
285 while (p >= s && !WDL_IS_DIRCHAR(*p)) --p;
286 return p + 1;
288 const char * WDL_STRING_FUNCPREFIX get_fileext() const // returns ".ext" or end of string "" if no extension
290 const char *s = Get();
291 const char *endp = s + GetLength();
292 const char *p = endp - 1;
293 while (p >= s && !WDL_IS_DIRCHAR(*p))
295 if (*p == '.') return p;
296 --p;
298 return endp;
300 bool WDL_STRING_FUNCPREFIX remove_fileext() // returns true if extension was removed
302 const char *str = Get();
303 int pos = GetLength() - 1;
304 while (pos >= 0)
306 char c = str[pos];
307 if (WDL_IS_DIRCHAR(c)) break;
308 if (c == '.')
310 SetLen(pos);
311 return true;
313 --pos;
315 return false;
318 char WDL_STRING_FUNCPREFIX remove_filepart(bool keepTrailingSlash WDL_STRING_DEFPARM(false)) // returns directory character used, or 0 if string emptied
320 char rv=0;
321 const char *str = Get();
322 int pos = GetLength() - 1;
323 while (pos > 0)
325 char c = str[pos];
326 if (WDL_IS_DIRCHAR(c))
328 rv=c;
329 if (keepTrailingSlash) ++pos;
330 break;
332 --pos;
334 SetLen(pos);
335 return rv;
338 int WDL_STRING_FUNCPREFIX remove_trailing_dirchars() // returns trailing dirchar count removed
340 int cnt = 0;
341 const char *str = Get();
342 const int l = GetLength()-1;
343 while (cnt < l)
345 char c = str[l - cnt];
346 if (!WDL_IS_DIRCHAR(c)) break;
347 ++cnt;
349 if (cnt > 0) SetLen(l + 1 - cnt);
350 return cnt;
352 #ifndef WDL_STRING_IMPL_ONLY
353 private:
354 #endif
355 void WDL_STRING_FUNCPREFIX __doSet(int offs, const char *str, int len, int trailkeep)
357 // if non-empty, or (empty and allocated and Set() rather than append/insert), then allow update, otherwise do nothing
358 if (len==0 && !trailkeep && !offs)
360 #ifdef WDL_STRING_FREE_ON_CLEAR
361 m_hb.Resize(0,true);
362 #else
363 char *p = (char *)m_hb.Resize(1,false);
364 if (p) *p=0;
365 #endif
367 else if (len>0 && offs >= 0)
369 const int oldsz = m_hb.GetSize();
370 const int newsz=offs+len+trailkeep+1;
371 if (newsz-oldsz > 0)
373 const char *oldb = (const char *)m_hb.Get();
374 const char *newb = (const char *)m_hb.Resize(newsz,false); // resize up if necessary
376 // in case str overlaps with input, keep it valid
377 if (str && newb != oldb && str >= oldb && str < oldb+oldsz) str = newb + (str - oldb);
380 if (m_hb.GetSize() >= newsz)
382 char *newbuf = (char *)m_hb.Get();
383 if (trailkeep>0) memmove(newbuf+offs+len,newbuf+offs,trailkeep);
384 if (str) memmove(newbuf+offs,str,len);
385 newbuf[newsz-1]=0;
387 // resize down if necessary
388 if (newsz < oldsz) m_hb.Resize(newsz,false);
393 #undef WDL_STRING_FUNCPREFIX
394 #undef WDL_STRING_DEFPARM
395 #endif // ! WDL_STRING_INTF_ONLY
397 #ifndef WDL_STRING_IMPL_ONLY
399 private:
400 #ifdef WDL_STRING_INTF_ONLY
401 void __doSet(int offs, const char *str, int len, int trailkeep);
402 #endif
404 WDL_HeapBuf m_hb;
406 #endif
408 #ifndef WDL_STRING_FASTSUB_DEFINED
409 #undef _WDL_STRING_H_
410 #define WDL_STRING_FASTSUB_DEFINED
411 #define WDL_String WDL_FastString
412 #include "wdlstring.h"
413 #undef WDL_STRING_FASTSUB_DEFINED
414 #undef WDL_String
415 #endif
417 #endif