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 
42 #include <stdio.h>
43 #include <stdarg.h>
44 
45 #include <cstdio>
46 
47 #ifdef WIN32
48 #define strcasecmp strcmpi
49 #if _MSC_VER < 1400
50 #define vsnprintf std::vsnprintf
51 #endif
52 #else
53 #include <cstddef>
54 #endif
55 
56 // NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
57 //   causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
58 //   Q_StrDup should be used now, using a #define __StrDup for easy transition
59 
60 #define __StrDup Q_StrDup
61 
Q_StrDup(const char * pStr)62 inline char* Q_StrDup(const char* pStr)
63 {
64   if (pStr == 0)
65     pStr = "";
66 
67   return strcpy(new char[strlen(pStr)+1], pStr);
68 }
69 
70 #if defined (__linux__) || defined (__APPLE__) || defined (__FreeBSD__)
71 #define strcmpi strcasecmp
72 #define stricmp strcasecmp
73 #define strnicmp strncasecmp
74 
strlwr(char * string)75 inline char* strlwr(char* string)
76 {
77   char *cp;
78   for (cp = string; *cp; ++cp)
79   {
80     if ('A' <= *cp && *cp <= 'Z')
81       *cp += 'a' - 'A';
82   }
83 
84   return string;
85 }
86 
strupr(char * string)87 inline char* strupr(char* string)
88 {
89   char *cp;
90   for (cp = string; *cp; ++cp)
91   {
92     if ('a' <= *cp && *cp <= 'z')
93       *cp += 'A' - 'a';
94   }
95 
96   return string;
97 }
98 #endif
99 
100 static char *g_pStrWork = 0;
101 
102 class Str
103 {
104 protected:
105   bool m_bIgnoreCase;
106   char *m_pStr;
107 
108 public:
Str()109   Str()
110   {
111     m_bIgnoreCase = true;
112     m_pStr = new char[1];
113     m_pStr[0] = '\0';
114   }
115 
Str(char * p)116   Str(char *p)
117   {
118     m_bIgnoreCase = true;
119     m_pStr = __StrDup(p);
120   }
121 
Str(const char * p)122   Str(const char *p)
123   {
124     m_bIgnoreCase = true;
125     m_pStr = __StrDup(p);
126   }
127 
Str(const unsigned char * p)128   Str(const unsigned char *p)
129   {
130     m_bIgnoreCase = true;
131     m_pStr = __StrDup(reinterpret_cast<const char *>(p));
132   }
133 
Str(const char c)134   Str(const char c)
135   {
136     m_bIgnoreCase = true;
137     m_pStr = new char[2];
138     m_pStr[0] = c;
139     m_pStr[1] = '\0';
140   }
141 
GetBuffer()142   const char* GetBuffer() const
143   {
144     return m_pStr;
145   }
146 
GetBuffer()147   char* GetBuffer()
148   {
149     return m_pStr;
150   }
151 
Str(const Str & s)152   Str(const Str &s)
153   {
154     m_bIgnoreCase = true;
155     m_pStr = __StrDup(s.GetBuffer());
156   }
157 
Deallocate()158   void Deallocate()
159   {
160     delete []m_pStr;
161     m_pStr = 0;
162   }
163 
Allocate(std::size_t n)164   void Allocate(std::size_t n)
165   {
166     Deallocate();
167     m_pStr = new char[n];
168   }
169 
MakeEmpty()170   void MakeEmpty()
171   {
172     Deallocate();
173     m_pStr = __StrDup("");
174   }
175 
~Str()176   ~Str()
177   {
178     Deallocate();
179     // NOTE TTimo: someone explain this g_pStrWork to me?
180     if (g_pStrWork)
181       delete []g_pStrWork;
182     g_pStrWork = 0;
183   }
184 
MakeLower()185   void MakeLower()
186   {
187     if (m_pStr)
188     {
189       strlwr(m_pStr);
190     }
191   }
192 
MakeUpper()193   void MakeUpper()
194   {
195     if (m_pStr)
196     {
197       strupr(m_pStr);
198     }
199   }
200 
TrimRight()201   void TrimRight()
202     {
203       char* lpsz = m_pStr;
204       char* lpszLast = 0;
205       while (*lpsz != '\0')
206       {
207 	if (isspace(*lpsz))
208 	{
209 	  if (lpszLast == 0)
210 	    lpszLast = lpsz;
211 	}
212 	else
213 	  lpszLast = 0;
214 	lpsz++;
215       }
216 
217       if (lpszLast != 0)
218       {
219 	// truncate at trailing space start
220 	*lpszLast = '\0';
221       }
222     }
223 
TrimLeft()224   void TrimLeft()
225     {
226       // find first non-space character
227       char* lpsz = m_pStr;
228       while (isspace(*lpsz))
229 	lpsz++;
230 
231       // fix up data and length
232       std::size_t nDataLength = GetLength() - (lpsz - m_pStr);
233       memmove(m_pStr, lpsz, (nDataLength+1));
234     }
235 
Find(const char * p)236   char* Find(const char *p)
237   {
238     return strstr(m_pStr, p);
239   }
240 
241   // search starting at a given offset
Find(const char * p,std::size_t offset)242   char* Find(const char *p, std::size_t offset)
243   {
244     return strstr(m_pStr+offset, p);
245   }
246 
Find(const char ch)247   char* Find(const char ch)
248   {
249     return strchr (m_pStr, ch);
250   }
251 
ReverseFind(const char ch)252   char* ReverseFind(const char ch)
253   {
254     return strrchr(m_pStr, ch);
255   }
256 
Compare(const char * str)257   int Compare (const char* str) const
258   {
259     return strcmp (m_pStr, str);
260   }
261 
CompareNoCase(const char * str)262   int CompareNoCase (const char* str) const
263   {
264     return strcasecmp (m_pStr, str);
265   }
266 
GetLength()267   std::size_t GetLength()
268   {
269     return (m_pStr) ? strlen(m_pStr) : 0;
270   }
271 
Left(std::size_t n)272   const char* Left(std::size_t n)
273   {
274     delete []g_pStrWork;
275     if (n > 0)
276     {
277       g_pStrWork = new char[n+1];
278       strncpy(g_pStrWork, m_pStr, n);
279       g_pStrWork[n] = '\0';
280     }
281     else
282     {
283       g_pStrWork = "";
284       g_pStrWork = new char[1];
285       g_pStrWork[0] = '\0';
286     }
287     return g_pStrWork;
288   }
289 
Right(std::size_t n)290   const char* Right(std::size_t n)
291   {
292     delete []g_pStrWork;
293     if (n > 0)
294     {
295       g_pStrWork = new char[n+1];
296       std::size_t nStart = GetLength() - n;
297       strncpy(g_pStrWork, &m_pStr[nStart], n);
298       g_pStrWork[n] = '\0';
299     }
300     else
301     {
302       g_pStrWork = new char[1];
303       g_pStrWork[0] = '\0';
304     }
305     return g_pStrWork;
306   }
307 
Mid(std::size_t nFirst)308   const char* Mid(std::size_t nFirst) const
309   {
310     return Mid(nFirst, strlen (m_pStr) - nFirst);
311   }
312 
Mid(std::size_t first,std::size_t n)313   const char* Mid(std::size_t first, std::size_t n) const
314   {
315     delete []g_pStrWork;
316     if (n > 0)
317     {
318       g_pStrWork = new char[n+1];
319       strncpy(g_pStrWork, m_pStr+first, n);
320       g_pStrWork[n] = '\0';
321     }
322     else
323     {
324       g_pStrWork = "";
325       g_pStrWork = new char[1];
326       g_pStrWork[0] = '\0';
327     }
328     return g_pStrWork;
329   }
330 
331 #if 0 // defined(__G_LIB_H__)
332   void Format(const char* fmt, ...)
333   {
334     va_list args;
335     char *buffer;
336 
337     va_start (args, fmt);
338     buffer = g_strdup_vprintf (fmt, args);
339     va_end (args);
340 
341     delete[] m_pStr;
342     m_pStr = __StrDup(buffer);
343     g_free (buffer);
344   }
345 #else
Format(const char * fmt,...)346   void Format(const char* fmt, ...)
347   {
348     char buffer[1024];
349 
350     {
351       va_list args;
352       va_start (args, fmt);
353       vsnprintf(buffer, 1023, fmt, args);
354       va_end (args);
355     }
356 
357     delete[] m_pStr;
358     m_pStr = __StrDup(buffer);
359   }
360 #endif
361 
SetAt(std::size_t n,char ch)362   void SetAt(std::size_t n, char ch)
363   {
364     if (n < GetLength())
365       m_pStr[n] = ch;
366   }
367 
368 	// NOTE: unlike CString, this looses the pointer
ReleaseBuffer(std::size_t n)369   void ReleaseBuffer(std::size_t n)
370   {
371     char* tmp = m_pStr;
372     tmp[n] = '\0';
373     m_pStr = __StrDup(tmp);
374     delete []tmp;
375   }
ReleaseBuffer()376   void ReleaseBuffer()
377   {
378     ReleaseBuffer(GetLength());
379   }
380 
GetBufferSetLength(std::size_t n)381   char* GetBufferSetLength(std::size_t n)
382   {
383     char *p = new char[n+1];
384     strncpy (p, m_pStr, n);
385 		p[n] = '\0';
386     delete []m_pStr;
387     m_pStr = p;
388     return m_pStr;
389   }
390 
391   //  char& operator *() { return *m_pStr; }
392   //  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
393   operator void*() { return m_pStr; }
394   operator char*() { return m_pStr; }
395   operator const char*() const{ return reinterpret_cast<const char*>(m_pStr); }
396   operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); }
397   operator const unsigned char*() const { return reinterpret_cast<const unsigned char*>(m_pStr); }
398   Str& operator =(const Str& rhs)
399   {
400     if (&rhs != this)
401     {
402       delete[] m_pStr;
403       m_pStr = __StrDup(rhs.m_pStr);
404     }
405     return *this;
406   }
407 
408   Str& operator =(const char* pStr)
409   {
410     if (m_pStr != pStr)
411     {
412       delete[] m_pStr;
413       m_pStr = __StrDup(pStr);
414     }
415     return *this;
416   }
417 
418   Str& operator +=(const char ch)
419   {
420     std::size_t len = GetLength();
421     char *p = new char[len + 1 + 1];
422 
423     if (m_pStr)
424     {
425       strcpy(p, m_pStr);
426       delete[] m_pStr;
427     }
428 
429     m_pStr = p;
430     m_pStr[len] = ch;
431     m_pStr[len+1] = '\0';
432 
433     return *this;
434   }
435 
436   Str& operator +=(const char *pStr)
437   {
438     if (pStr)
439     {
440       if (m_pStr)
441       {
442         char *p = new char[strlen(m_pStr) + strlen(pStr) + 1];
443         strcpy(p, m_pStr);
444         strcat(p, pStr);
445         delete[] m_pStr;
446         m_pStr = p;
447       }
448       else
449       {
450         m_pStr = __StrDup(pStr);
451       }
452     }
453     return *this;
454   }
455 
456 
457   bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; }
458   bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
459   bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }
460   bool operator !=(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 <(const 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   char& operator [](std::size_t nIndex) { return m_pStr[nIndex]; }
470   const char& operator [](std::size_t nIndex) const { return m_pStr[nIndex]; }
GetAt(std::size_t nIndex)471   const char GetAt (std::size_t nIndex) { return m_pStr[nIndex]; }
472 };
473 
474 
475 template<typename TextOutputStreamType>
ostream_write(TextOutputStreamType & ostream,const Str & str)476 inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Str& str)
477 {
478   return ostream << str.GetBuffer();
479 }
480 
481 
AddSlash(Str & strPath)482 inline void AddSlash(Str& strPath)
483 {
484   if (strPath.GetLength() > 0)
485   {
486     if ((strPath.GetAt(strPath.GetLength()-1) != '/') &&
487 	(strPath.GetAt(strPath.GetLength()-1) != '\\'))
488       strPath += '/';
489   }
490 }
491 
ExtractPath_and_Filename(const char * pPath,Str & strPath,Str & strFilename)492 inline bool ExtractPath_and_Filename(const char* pPath, Str& strPath, Str& strFilename)
493 {
494   Str strPathName;
495   strPathName = pPath;
496   const char* substr = strPathName.ReverseFind('\\');
497   if (substr == 0)
498     // TTimo: try forward slash, some are using forward
499     substr = strPathName.ReverseFind('/');
500   if (substr != 0)
501   {
502     std::size_t nSlash = substr - strPathName.GetBuffer();
503     strPath = strPathName.Left(nSlash+1);
504     strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1);
505   }
506   else
507     strFilename = pPath;
508   return true;
509 }
510 
511 
512 
513 #endif
514