]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/str.h
basic architecture for game configuration at runtime. writes out a .game, no sanity...
[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 {
63   if (pStr == NULL)
64     pStr = "";
65
66   return strcpy(new char[strlen(pStr)+1], pStr); 
67 }
68
69 inline char* Q_StrDup(const char* pStr)
70
71   if (pStr == NULL)
72     pStr = "";
73
74   return strcpy(new char[strlen(pStr)+1], pStr); 
75 }
76
77 #if defined (__linux__) || defined (__APPLE__)
78 #define strcmpi strcasecmp
79 #define stricmp strcasecmp
80 #define strnicmp strncasecmp
81
82 inline char* strlwr(char* string)
83 {
84   char *cp;
85   for (cp = string; *cp; ++cp)
86   {
87     if ('A' <= *cp && *cp <= 'Z')
88       *cp += 'a' - 'A';
89   }
90
91   return string;
92 }
93
94 inline char* strupr(char* string)
95 {
96   char *cp;
97   for (cp = string; *cp; ++cp)
98   {
99     if ('a' <= *cp && *cp <= 'z')
100       *cp += 'A' - 'a';
101   }
102
103   return string;
104 }
105 #endif
106
107 static char *g_pStrWork = NULL;
108
109 class Str
110 {
111 protected:
112   bool m_bIgnoreCase;
113   char *m_pStr;
114
115 public:
116   Str()
117   {
118     m_bIgnoreCase = true;
119     m_pStr = new char[1];
120     m_pStr[0] = '\0';
121   }
122
123   Str(char *p)
124   {
125     m_bIgnoreCase = true;
126     m_pStr = __StrDup(p);
127   }
128
129   Str(const char *p)
130   {
131     m_bIgnoreCase = true;
132     m_pStr = __StrDup(p);
133   }
134
135   Str(const unsigned char *p)
136   {
137     m_bIgnoreCase = true;
138     m_pStr = __StrDup((const char *)p);
139   }
140
141   Str(const char c)
142   {
143     m_bIgnoreCase = true;
144     m_pStr = new char[2];
145     m_pStr[0] = c;
146     m_pStr[1] = '\0';    
147   }
148
149   const char* GetBuffer() const
150   {
151     return m_pStr;
152   }
153
154   Str(const Str &s)
155   {
156     m_bIgnoreCase = true;
157     m_pStr = __StrDup(s.GetBuffer());
158   }
159
160   void Deallocate()
161   {
162     delete []m_pStr;
163     m_pStr = NULL;
164   }
165
166   void Allocate(int n)
167   {
168     Deallocate();
169     m_pStr = new char[n];
170   }
171
172   void MakeEmpty()
173   {
174     Deallocate();
175     m_pStr = __StrDup("");
176   }
177
178   virtual ~Str()
179   {
180     Deallocate();
181     // NOTE TTimo: someone explain this g_pStrWork to me?
182     if (g_pStrWork)
183       delete []g_pStrWork;
184     g_pStrWork = NULL;
185   }
186
187   void MakeLower()
188   {
189     if (m_pStr)
190     {
191       strlwr(m_pStr);
192     }
193   }
194
195   void MakeUpper()
196   {
197     if (m_pStr)
198     {
199       strupr(m_pStr);
200     }
201   }
202
203   void TrimRight()
204     {
205       char* lpsz = m_pStr;
206       char* lpszLast = NULL;
207       while (*lpsz != '\0')
208       {
209         if (isspace(*lpsz))
210         {
211           if (lpszLast == NULL)
212             lpszLast = lpsz;
213         }
214         else
215           lpszLast = NULL;
216         lpsz++;
217       }
218  
219       if (lpszLast != NULL)
220       {
221         // truncate at trailing space start
222         *lpszLast = '\0';
223       }
224     }
225
226   void TrimLeft()
227     {
228       // find first non-space character
229       char* lpsz = m_pStr;
230       while (isspace(*lpsz))
231         lpsz++;
232  
233       // fix up data and length
234       int nDataLength = GetLength() - (lpsz - m_pStr);
235       memmove(m_pStr, lpsz, (nDataLength+1));
236     }
237
238   int Find(const char *p)
239   {
240     char *pf = strstr(m_pStr, p);
241     return (pf) ? (pf - m_pStr) : -1;
242   }
243
244   // search starting at a given offset
245   int Find(const char *p, int offset)
246   {
247     char *pf = strstr(m_pStr+offset, p);
248     return (pf) ? (pf - m_pStr) : -1;
249   }
250
251   int Find(const char ch)
252   {
253     char *pf = strchr (m_pStr, ch);
254     return (pf) ? (pf - m_pStr) : -1;
255   }
256
257   int ReverseFind(const char ch)
258   {
259     char *pf = strrchr(m_pStr, ch);
260     return (pf) ? (pf - m_pStr) : -1;
261   }
262
263   int Compare (const char* str) const
264   {
265     return strcmp (m_pStr, str);
266   }
267   
268   int CompareNoCase (const char* str) const
269   {
270     return strcasecmp (m_pStr, str);
271   }
272
273   int GetLength()
274   {
275     return (m_pStr) ? strlen(m_pStr) : 0;
276   }
277
278   const char* Left(int n)
279   {
280     delete []g_pStrWork;
281     if (n > 0)
282     {
283       g_pStrWork = new char[n+1];
284       strncpy(g_pStrWork, m_pStr, n);
285       g_pStrWork[n] = '\0';
286     }
287     else
288     {
289       g_pStrWork = "";
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 = "";
331       g_pStrWork = new char[1];
332       g_pStrWork[0] = '\0';
333     }
334     return g_pStrWork;
335   }
336
337 #ifdef __G_LIB_H__
338   void Format(const char* fmt, ...)
339   {
340     va_list args;
341     char *buffer;
342   
343     va_start (args, fmt);
344     buffer = g_strdup_vprintf (fmt, args);
345     va_end (args);
346
347     delete[] m_pStr;
348     m_pStr = __StrDup(buffer);
349     g_free (buffer);
350   }
351 #else
352   void Format(const char* fmt, ...)
353   {
354     va_list args;
355     m_pStr = new char[1024];
356
357     va_start (args, fmt);
358     vsprintf (m_pStr, fmt, args);
359     va_end (args);
360   }
361 #endif
362
363   void SetAt(int n, char ch)
364   {
365     if (n >= 0 && n < GetLength ())
366       m_pStr[n] = ch;
367   }
368
369         // NOTE: unlike CString, this looses the pointer
370   void ReleaseBuffer(int n = -1)
371   {
372     if (n == -1)
373       n = GetLength ();
374
375     char* tmp = m_pStr;
376     tmp[n] = '\0';
377     m_pStr = __StrDup(tmp);
378     delete []tmp;
379   }
380
381   char* GetBufferSetLength(int n)
382   {
383     if (n < 0)
384       n = 0;
385
386     char *p = new char[n+1];
387     strncpy (p, m_pStr, n);
388                 p[n] = '\0';
389     delete []m_pStr;
390     m_pStr = p;
391     return m_pStr;
392   }
393
394   //  char& operator *() { return *m_pStr; }
395   //  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
396   operator void*() { return m_pStr; }
397   operator char*() { return m_pStr; }
398   operator const char*(){ return reinterpret_cast<const char*>(m_pStr); }
399   operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); }
400   operator const unsigned char*() { return reinterpret_cast<const unsigned char*>(m_pStr); }
401   Str& operator =(const Str& rhs)
402   {
403     if (&rhs != this)
404     {
405       delete[] m_pStr;
406       m_pStr = __StrDup(rhs.m_pStr);
407     }
408     return *this;
409   }
410   
411   Str& operator =(const char* pStr)
412   {
413     if (m_pStr != pStr)
414     {
415       delete[] m_pStr;
416       m_pStr = __StrDup(pStr);
417     }
418     return *this;
419   }
420
421   Str& operator +=(const char ch)
422   {
423     int len = GetLength ();
424     char *p = new char[len + 1 + 1];
425
426     if (m_pStr)
427     {
428       strcpy(p, m_pStr);
429       delete[] m_pStr;
430     }
431
432     m_pStr = p;
433     m_pStr[len] = ch;
434     m_pStr[len+1] = '\0';
435
436     return *this;
437   }
438
439   Str& operator +=(const char *pStr)
440   {
441     if (pStr)
442     {
443       if (m_pStr)
444       {
445         char *p = new char[strlen(m_pStr) + strlen(pStr) + 1];
446         strcpy(p, m_pStr);
447         strcat(p, pStr);
448         delete[] m_pStr;
449         m_pStr = p;
450       }
451       else
452       {
453         m_pStr = __StrDup(pStr);
454       }
455     }
456     return *this;
457   }
458   
459
460   bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; }
461   bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
462   bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
463   bool operator !=(Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) != 0 : strcmp(m_pStr, rhs.m_pStr) != 0; }
464   bool operator !=(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }
465   bool operator !=(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }
466   bool operator <(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) < 0 : strcmp(m_pStr, rhs.m_pStr) < 0; }
467   bool operator <(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }
468   bool operator <(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }
469   bool operator >(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) > 0 : strcmp(m_pStr, rhs.m_pStr) > 0; }
470   bool operator >(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }
471   bool operator >(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }
472   char& operator [](int nIndex) { return m_pStr[nIndex]; }
473   char& operator [](int nIndex) const { return m_pStr[nIndex]; }
474   const char GetAt (int nIndex) { return m_pStr[nIndex]; }
475 };
476
477
478
479 #endif