Adding patch_seam q3map2 regression test. Probably not fixable, but good to
[xonotic/netradiant.git] / libs / str.h
1 /*
2 Copyright (c) 2001, Loki software, inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification, 
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list 
9 of conditions and the following disclaimer.
10
11 Redistributions in binary form must reproduce the above copyright notice, this
12 list of conditions and the following disclaimer in the documentation and/or
13 other materials provided with the distribution.
14
15 Neither the name of Loki software nor the names of its contributors may be used 
16 to endorse or promote products derived from this software without specific prior 
17 written permission. 
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
22 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY 
23 DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
29 */
30
31 #ifndef __STR__
32 #define __STR__
33
34 //
35 // class Str
36 // loose replacement for CString from MFC
37 //
38
39 #include <string.h>
40 #include <ctype.h>
41 #include <stdarg.h>
42
43 #ifdef __APPLE__
44   #ifdef NULL
45     #undef NULL
46     #define NULL 0
47   #endif
48 #endif
49
50
51 #ifdef _WIN32
52 #define strcasecmp strcmpi
53 #endif
54
55 // NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
56 //   causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
57 //   Q_StrDup should be used now, using a #define __StrDup for easy transition
58
59 #define __StrDup Q_StrDup
60
61 inline char* Q_StrDup( char* _pStr ) {
62         const char* pStr = _pStr;
63         if ( pStr == NULL ) {           
64                 pStr = "";
65         }
66
67         return strcpy( new char[ strlen( pStr ) + 1 ], pStr );
68 }
69
70 inline char* Q_StrDup( const char* pStr ) {
71         if ( pStr == NULL ) {
72                 pStr = "";
73         }
74
75         return strcpy( new char[strlen(pStr)+1], pStr );
76 }
77
78 #if defined (__linux__) || defined (__APPLE__)
79 #define strcmpi strcasecmp
80 #define stricmp strcasecmp
81 #define strnicmp strncasecmp
82
83 inline char* strlwr(char* string)
84 {
85   char *cp;
86   for (cp = string; *cp; ++cp)
87   {
88     if ('A' <= *cp && *cp <= 'Z')
89       *cp += 'a' - 'A';
90   }
91
92   return string;
93 }
94
95 inline char* strupr(char* string)
96 {
97   char *cp;
98   for (cp = string; *cp; ++cp)
99   {
100     if ('a' <= *cp && *cp <= 'z')
101       *cp += 'A' - 'a';
102   }
103
104   return string;
105 }
106 #endif
107
108 static char *g_pStrWork = NULL;
109
110 class Str
111 {
112 protected:
113   bool m_bIgnoreCase;
114   char *m_pStr;
115
116 public:
117   Str()
118   {
119     m_bIgnoreCase = true;
120     m_pStr = new char[1];
121     m_pStr[0] = '\0';
122   }
123
124   Str(char *p)
125   {
126     m_bIgnoreCase = true;
127     m_pStr = __StrDup(p);
128   }
129
130   Str(const char *p)
131   {
132     m_bIgnoreCase = true;
133     m_pStr = __StrDup(p);
134   }
135
136   Str(const unsigned char *p)
137   {
138     m_bIgnoreCase = true;
139     m_pStr = __StrDup((const char *)p);
140   }
141
142   Str(const char c)
143   {
144     m_bIgnoreCase = true;
145     m_pStr = new char[2];
146     m_pStr[0] = c;
147     m_pStr[1] = '\0';    
148   }
149
150   const char* GetBuffer() const
151   {
152     return m_pStr;
153   }
154
155   Str(const Str &s)
156   {
157     m_bIgnoreCase = true;
158     m_pStr = __StrDup(s.GetBuffer());
159   }
160
161   void Deallocate()
162   {
163     delete []m_pStr;
164     m_pStr = NULL;
165   }
166
167   void Allocate(int n)
168   {
169     Deallocate();
170     m_pStr = new char[n];
171   }
172
173   void MakeEmpty()
174   {
175     Deallocate();
176     m_pStr = __StrDup("");
177   }
178
179   virtual ~Str()
180   {
181     Deallocate();
182     // NOTE TTimo: someone explain this g_pStrWork to me?
183     if (g_pStrWork)
184       delete []g_pStrWork;
185     g_pStrWork = NULL;
186   }
187
188   void MakeLower()
189   {
190     if (m_pStr)
191     {
192       strlwr(m_pStr);
193     }
194   }
195
196   void MakeUpper()
197   {
198     if (m_pStr)
199     {
200       strupr(m_pStr);
201     }
202   }
203
204   void TrimRight()
205     {
206       char* lpsz = m_pStr;
207       char* lpszLast = NULL;
208       while (*lpsz != '\0')
209       {
210         if (isspace(*lpsz))
211         {
212           if (lpszLast == NULL)
213             lpszLast = lpsz;
214         }
215         else
216           lpszLast = NULL;
217         lpsz++;
218       }
219  
220       if (lpszLast != NULL)
221       {
222         // truncate at trailing space start
223         *lpszLast = '\0';
224       }
225     }
226
227   void TrimLeft()
228     {
229       // find first non-space character
230       char* lpsz = m_pStr;
231       while (isspace(*lpsz))
232         lpsz++;
233  
234       // fix up data and length
235       int nDataLength = GetLength() - (lpsz - m_pStr);
236       memmove(m_pStr, lpsz, (nDataLength+1));
237     }
238
239   int Find(const char *p)
240   {
241     char *pf = strstr(m_pStr, p);
242     return (pf) ? (pf - m_pStr) : -1;
243   }
244
245   // search starting at a given offset
246   int Find(const char *p, int offset)
247   {
248     char *pf = strstr(m_pStr+offset, p);
249     return (pf) ? (pf - m_pStr) : -1;
250   }
251
252   int Find(const char ch)
253   {
254     char *pf = strchr (m_pStr, ch);
255     return (pf) ? (pf - m_pStr) : -1;
256   }
257
258   int ReverseFind(const char ch)
259   {
260     char *pf = strrchr(m_pStr, ch);
261     return (pf) ? (pf - m_pStr) : -1;
262   }
263
264   int Compare (const char* str) const
265   {
266     return strcmp (m_pStr, str);
267   }
268   
269   int CompareNoCase (const char* str) const
270   {
271     return strcasecmp (m_pStr, str);
272   }
273
274   int GetLength()
275   {
276     return (m_pStr) ? strlen(m_pStr) : 0;
277   }
278
279   const char* Left(int n)
280   {
281     delete []g_pStrWork;
282     if (n > 0)
283     {
284       g_pStrWork = new char[n+1];
285       strncpy(g_pStrWork, m_pStr, n);
286       g_pStrWork[n] = '\0';
287     }
288     else
289     {
290       g_pStrWork = new char[1];
291       g_pStrWork[0] = '\0';
292     }
293     return g_pStrWork;
294   }
295
296   const char* Right(int n)
297   {
298     delete []g_pStrWork;
299     if (n > 0)
300     {
301       g_pStrWork = new char[n+1];
302       int nStart = GetLength() - n;
303       strncpy(g_pStrWork, &m_pStr[nStart], n);
304       g_pStrWork[n] = '\0';
305     }
306     else
307     {
308       g_pStrWork = new char[1];
309       g_pStrWork[0] = '\0';
310     }
311     return g_pStrWork;
312   }
313
314   const char* Mid(int nFirst) const
315     {
316       return Mid(nFirst, strlen (m_pStr) - nFirst);
317     }
318
319   const char* Mid(int first, int n) const
320   {
321     delete []g_pStrWork;
322     if (n > 0)
323     {
324       g_pStrWork = new char[n+1];
325       strncpy(g_pStrWork, m_pStr+first, n);
326       g_pStrWork[n] = '\0';
327     }
328     else
329     {
330       g_pStrWork = new char[1];
331       g_pStrWork[0] = '\0';
332     }
333     return g_pStrWork;
334   }
335
336 #ifdef __G_LIB_H__
337   void Format(const char* fmt, ...)
338   {
339     va_list args;
340     char *buffer;
341   
342     va_start (args, fmt);
343     buffer = g_strdup_vprintf (fmt, args);
344     va_end (args);
345
346     delete[] m_pStr;
347     m_pStr = __StrDup(buffer);
348     g_free (buffer);
349   }
350 #else
351   void Format(const char* fmt, ...)
352   {
353     va_list args;
354     m_pStr = new char[1024];
355
356     va_start (args, fmt);
357     vsprintf (m_pStr, fmt, args);
358     va_end (args);
359   }
360 #endif
361
362   void SetAt(int n, char ch)
363   {
364     if (n >= 0 && n < GetLength ())
365       m_pStr[n] = ch;
366   }
367
368         // NOTE: unlike CString, this looses the pointer
369   void ReleaseBuffer(int n = -1)
370   {
371     if (n == -1)
372       n = GetLength ();
373
374     char* tmp = m_pStr;
375     tmp[n] = '\0';
376     m_pStr = __StrDup(tmp);
377     delete []tmp;
378   }
379
380   char* GetBufferSetLength(int n)
381   {
382     if (n < 0)
383       n = 0;
384
385     char *p = new char[n+1];
386     strncpy (p, m_pStr, n);
387                 p[n] = '\0';
388     delete []m_pStr;
389     m_pStr = p;
390     return m_pStr;
391   }
392
393   //  char& operator *() { return *m_pStr; }
394   //  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
395   operator void*() { return m_pStr; }
396   operator char*() { return m_pStr; }
397   operator const char*(){ return reinterpret_cast<const char*>(m_pStr); }
398   operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); }
399   operator const unsigned char*() { return reinterpret_cast<const unsigned char*>(m_pStr); }
400   Str& operator =(const Str& rhs)
401   {
402     if (&rhs != this)
403     {
404       delete[] m_pStr;
405       m_pStr = __StrDup(rhs.m_pStr);
406     }
407     return *this;
408   }
409   
410   Str& operator =(const char* pStr)
411   {
412     if (m_pStr != pStr)
413     {
414       delete[] m_pStr;
415       m_pStr = __StrDup(pStr);
416     }
417     return *this;
418   }
419
420   Str& operator +=(const char ch)
421   {
422     int len = GetLength ();
423     char *p = new char[len + 1 + 1];
424
425     if (m_pStr)
426     {
427       strcpy(p, m_pStr);
428       delete[] m_pStr;
429     }
430
431     m_pStr = p;
432     m_pStr[len] = ch;
433     m_pStr[len+1] = '\0';
434
435     return *this;
436   }
437
438   Str& operator +=(const char *pStr)
439   {
440     if (pStr)
441     {
442       if (m_pStr)
443       {
444         char *p = new char[strlen(m_pStr) + strlen(pStr) + 1];
445         strcpy(p, m_pStr);
446         strcat(p, pStr);
447         delete[] m_pStr;
448         m_pStr = p;
449       }
450       else
451       {
452         m_pStr = __StrDup(pStr);
453       }
454     }
455     return *this;
456   }
457   
458
459   bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; }
460   bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
461   bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
462   bool operator !=(Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) != 0 : strcmp(m_pStr, rhs.m_pStr) != 0; }
463   bool operator !=(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }
464   bool operator !=(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }
465   bool operator <(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) < 0 : strcmp(m_pStr, rhs.m_pStr) < 0; }
466   bool operator <(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }
467   bool operator <(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }
468   bool operator >(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) > 0 : strcmp(m_pStr, rhs.m_pStr) > 0; }
469   bool operator >(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }
470   bool operator >(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }
471   char& operator [](int nIndex) { return m_pStr[nIndex]; }
472   char& operator [](int nIndex) const { return m_pStr[nIndex]; }
473   const char GetAt (int nIndex) { return m_pStr[nIndex]; }
474 };
475
476
477
478 #endif