2 Copyright (c) 2001, Loki software, inc.
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 Redistributions of source code must retain the above copyright notice, this list
9 of conditions and the following disclaimer.
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.
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
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.
36 // loose replacement for CString from MFC
48 #define strcasecmp strcmpi
50 #define vsnprintf std::vsnprintf
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
60 #define __StrDup Q_StrDup
62 inline char* Q_StrDup(const char* pStr)
67 return strcpy(new char[strlen(pStr)+1], pStr);
71 #define strcmpi strcasecmp
72 #define stricmp strcasecmp
73 #define strnicmp strncasecmp
75 inline char* strlwr(char* string)
78 for (cp = string; *cp; ++cp)
80 if ('A' <= *cp && *cp <= 'Z')
87 inline char* strupr(char* string)
90 for (cp = string; *cp; ++cp)
92 if ('a' <= *cp && *cp <= 'z')
100 static char *g_pStrWork = 0;
111 m_bIgnoreCase = true;
112 m_pStr = new char[1];
118 m_bIgnoreCase = true;
119 m_pStr = __StrDup(p);
124 m_bIgnoreCase = true;
125 m_pStr = __StrDup(p);
128 Str(const unsigned char *p)
130 m_bIgnoreCase = true;
131 m_pStr = __StrDup(reinterpret_cast<const char *>(p));
136 m_bIgnoreCase = true;
137 m_pStr = new char[2];
142 const char* GetBuffer() const
154 m_bIgnoreCase = true;
155 m_pStr = __StrDup(s.GetBuffer());
164 void Allocate(std::size_t n)
167 m_pStr = new char[n];
173 m_pStr = __StrDup("");
179 // NOTE TTimo: someone explain this g_pStrWork to me?
205 while (*lpsz != '\0')
219 // truncate at trailing space start
226 // find first non-space character
228 while (isspace(*lpsz))
231 // fix up data and length
232 std::size_t nDataLength = GetLength() - (lpsz - m_pStr);
233 memmove(m_pStr, lpsz, (nDataLength+1));
236 char* Find(const char *p)
238 return strstr(m_pStr, p);
241 // search starting at a given offset
242 char* Find(const char *p, std::size_t offset)
244 return strstr(m_pStr+offset, p);
247 char* Find(const char ch)
249 return strchr (m_pStr, ch);
252 char* ReverseFind(const char ch)
254 return strrchr(m_pStr, ch);
257 int Compare (const char* str) const
259 return strcmp (m_pStr, str);
262 int CompareNoCase (const char* str) const
264 return strcasecmp (m_pStr, str);
267 std::size_t GetLength()
269 return (m_pStr) ? strlen(m_pStr) : 0;
272 const char* Left(std::size_t n)
277 g_pStrWork = new char[n+1];
278 strncpy(g_pStrWork, m_pStr, n);
279 g_pStrWork[n] = '\0';
284 g_pStrWork = new char[1];
285 g_pStrWork[0] = '\0';
290 const char* Right(std::size_t n)
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';
302 g_pStrWork = new char[1];
303 g_pStrWork[0] = '\0';
308 const char* Mid(std::size_t nFirst) const
310 return Mid(nFirst, strlen (m_pStr) - nFirst);
313 const char* Mid(std::size_t first, std::size_t n) const
318 g_pStrWork = new char[n+1];
319 strncpy(g_pStrWork, m_pStr+first, n);
320 g_pStrWork[n] = '\0';
325 g_pStrWork = new char[1];
326 g_pStrWork[0] = '\0';
331 #if 0 // defined(__G_LIB_H__)
332 void Format(const char* fmt, ...)
337 va_start (args, fmt);
338 buffer = g_strdup_vprintf (fmt, args);
342 m_pStr = __StrDup(buffer);
346 void Format(const char* fmt, ...)
352 va_start (args, fmt);
353 vsnprintf(buffer, 1023, fmt, args);
358 m_pStr = __StrDup(buffer);
362 void SetAt(std::size_t n, char ch)
368 // NOTE: unlike CString, this looses the pointer
369 void ReleaseBuffer(std::size_t n)
373 m_pStr = __StrDup(tmp);
378 ReleaseBuffer(GetLength());
381 char* GetBufferSetLength(std::size_t n)
383 char *p = new char[n+1];
384 strncpy (p, m_pStr, n);
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)
403 m_pStr = __StrDup(rhs.m_pStr);
408 Str& operator =(const char* pStr)
413 m_pStr = __StrDup(pStr);
418 Str& operator +=(const char ch)
420 std::size_t len = GetLength();
421 char *p = new char[len + 1 + 1];
431 m_pStr[len+1] = '\0';
436 Str& operator +=(const char *pStr)
442 char *p = new char[strlen(m_pStr) + strlen(pStr) + 1];
450 m_pStr = __StrDup(pStr);
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]; }
471 const char GetAt (std::size_t nIndex) { return m_pStr[nIndex]; }
475 template<typename TextOutputStreamType>
476 inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Str& str)
478 return ostream << str.GetBuffer();
482 inline void AddSlash(Str& strPath)
484 if (strPath.GetLength() > 0)
486 if ((strPath.GetAt(strPath.GetLength()-1) != '/') &&
487 (strPath.GetAt(strPath.GetLength()-1) != '\\'))
492 inline bool ExtractPath_and_Filename(const char* pPath, Str& strPath, Str& strFilename)
496 const char* substr = strPathName.ReverseFind('\\');
498 // TTimo: try forward slash, some are using forward
499 substr = strPathName.ReverseFind('/');
502 std::size_t nSlash = substr - strPathName.GetBuffer();
503 strPath = strPathName.Left(nSlash+1);
504 strFilename = strPathName.Right(strPathName.GetLength() - nSlash - 1);