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