]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/str.h
Merge pull request #21 from merlin1991/Q3-gamepack-fix
[xonotic/netradiant.git] / libs / str.h
index 8bb56ea971b418c49847587f4915a32bb67d1953..0ee38f812953384144f9031c457405e34e0891e7 100644 (file)
-/*\r
-Copyright (c) 2001, Loki software, inc.\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification, \r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list \r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other materials provided with the distribution.\r
-\r
-Neither the name of Loki software nor the names of its contributors may be used \r
-to endorse or promote products derived from this software without specific prior \r
-written permission. \r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' \r
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \r
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY \r
-DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES \r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; \r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON \r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS \r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \r
-*/\r
-\r
-#ifndef __STR__\r
-#define __STR__\r
-\r
-//\r
-// class Str\r
-// loose replacement for CString from MFC\r
-//\r
-\r
-#include <string.h>\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-\r
-#ifdef __APPLE__\r
-  #ifdef NULL\r
-    #undef NULL\r
-    #define NULL 0\r
-  #endif\r
-#endif\r
-\r
-\r
-#ifdef _WIN32\r
-#define strcasecmp strcmpi\r
-#endif\r
-\r
-// NOTE TTimo __StrDup was initially implemented in pakstuff.cpp\r
-//   causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)\r
-//   Q_StrDup should be used now, using a #define __StrDup for easy transition\r
-\r
-#define __StrDup Q_StrDup\r
-\r
-inline char* Q_StrDup(char* pStr)\r
-{\r
-  if (pStr == NULL)\r
-    pStr = "";\r
-\r
-  return strcpy(new char[strlen(pStr)+1], pStr); \r
-}\r
-\r
-inline char* Q_StrDup(const char* pStr)\r
-{ \r
-  if (pStr == NULL)\r
-    pStr = "";\r
-\r
-  return strcpy(new char[strlen(pStr)+1], pStr); \r
-}\r
-\r
-#if defined (__linux__) || defined (__APPLE__)\r
-#define strcmpi strcasecmp\r
-#define stricmp strcasecmp\r
-#define strnicmp strncasecmp\r
-\r
-inline char* strlwr(char* string)\r
-{\r
-  char *cp;\r
-  for (cp = string; *cp; ++cp)\r
-  {\r
-    if ('A' <= *cp && *cp <= 'Z')\r
-      *cp += 'a' - 'A';\r
-  }\r
-\r
-  return string;\r
-}\r
-\r
-inline char* strupr(char* string)\r
-{\r
-  char *cp;\r
-  for (cp = string; *cp; ++cp)\r
-  {\r
-    if ('a' <= *cp && *cp <= 'z')\r
-      *cp += 'A' - 'a';\r
-  }\r
-\r
-  return string;\r
-}\r
-#endif\r
-\r
-static char *g_pStrWork = NULL;\r
-\r
-class Str\r
-{\r
-protected:\r
-  bool m_bIgnoreCase;\r
-  char *m_pStr;\r
-\r
-public:\r
-  Str()\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = new char[1];\r
-    m_pStr[0] = '\0';\r
-  }\r
-\r
-  Str(char *p)\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = __StrDup(p);\r
-  }\r
-\r
-  Str(const char *p)\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = __StrDup(p);\r
-  }\r
-\r
-  Str(const unsigned char *p)\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = __StrDup((const char *)p);\r
-  }\r
-\r
-  Str(const char c)\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = new char[2];\r
-    m_pStr[0] = c;\r
-    m_pStr[1] = '\0';    \r
-  }\r
-\r
-  const char* GetBuffer() const\r
-  {\r
-    return m_pStr;\r
-  }\r
-\r
-  Str(const Str &s)\r
-  {\r
-    m_bIgnoreCase = true;\r
-    m_pStr = __StrDup(s.GetBuffer());\r
-  }\r
-\r
-  void Deallocate()\r
-  {\r
-    delete []m_pStr;\r
-    m_pStr = NULL;\r
-  }\r
-\r
-  void Allocate(int n)\r
-  {\r
-    Deallocate();\r
-    m_pStr = new char[n];\r
-  }\r
-\r
-  void MakeEmpty()\r
-  {\r
-    Deallocate();\r
-    m_pStr = __StrDup("");\r
-  }\r
-\r
-  virtual ~Str()\r
-  {\r
-    Deallocate();\r
-    // NOTE TTimo: someone explain this g_pStrWork to me?\r
-    if (g_pStrWork)\r
-      delete []g_pStrWork;\r
-    g_pStrWork = NULL;\r
-  }\r
-\r
-  void MakeLower()\r
-  {\r
-    if (m_pStr)\r
-    {\r
-      strlwr(m_pStr);\r
-    }\r
-  }\r
-\r
-  void MakeUpper()\r
-  {\r
-    if (m_pStr)\r
-    {\r
-      strupr(m_pStr);\r
-    }\r
-  }\r
-\r
-  void TrimRight()\r
-    {\r
-      char* lpsz = m_pStr;\r
-      char* lpszLast = NULL;\r
-      while (*lpsz != '\0')\r
-      {\r
-       if (isspace(*lpsz))\r
-       {\r
-         if (lpszLast == NULL)\r
-           lpszLast = lpsz;\r
-       }\r
-       else\r
-         lpszLast = NULL;\r
-       lpsz++;\r
-      }\r
\r
-      if (lpszLast != NULL)\r
-      {\r
-       // truncate at trailing space start\r
-       *lpszLast = '\0';\r
-      }\r
-    }\r
-\r
-  void TrimLeft()\r
-    {\r
-      // find first non-space character\r
-      char* lpsz = m_pStr;\r
-      while (isspace(*lpsz))\r
-       lpsz++;\r
\r
-      // fix up data and length\r
-      int nDataLength = GetLength() - (lpsz - m_pStr);\r
-      memmove(m_pStr, lpsz, (nDataLength+1));\r
-    }\r
-\r
-  int Find(const char *p)\r
-  {\r
-    char *pf = strstr(m_pStr, p);\r
-    return (pf) ? (pf - m_pStr) : -1;\r
-  }\r
-\r
-  // search starting at a given offset\r
-  int Find(const char *p, int offset)\r
-  {\r
-    char *pf = strstr(m_pStr+offset, p);\r
-    return (pf) ? (pf - m_pStr) : -1;\r
-  }\r
-\r
-  int Find(const char ch)\r
-  {\r
-    char *pf = strchr (m_pStr, ch);\r
-    return (pf) ? (pf - m_pStr) : -1;\r
-  }\r
-\r
-  int ReverseFind(const char ch)\r
-  {\r
-    char *pf = strrchr(m_pStr, ch);\r
-    return (pf) ? (pf - m_pStr) : -1;\r
-  }\r
-\r
-  int Compare (const char* str) const\r
-  {\r
-    return strcmp (m_pStr, str);\r
-  }\r
-  \r
-  int CompareNoCase (const char* str) const\r
-  {\r
-    return strcasecmp (m_pStr, str);\r
-  }\r
-\r
-  int GetLength()\r
-  {\r
-    return (m_pStr) ? strlen(m_pStr) : 0;\r
-  }\r
-\r
-  const char* Left(int n)\r
-  {\r
-    delete []g_pStrWork;\r
-    if (n > 0)\r
-    {\r
-      g_pStrWork = new char[n+1];\r
-      strncpy(g_pStrWork, m_pStr, n);\r
-      g_pStrWork[n] = '\0';\r
-    }\r
-    else\r
-    {\r
-      g_pStrWork = "";\r
-      g_pStrWork = new char[1];\r
-      g_pStrWork[0] = '\0';\r
-    }\r
-    return g_pStrWork;\r
-  }\r
-\r
-  const char* Right(int n)\r
-  {\r
-    delete []g_pStrWork;\r
-    if (n > 0)\r
-    {\r
-      g_pStrWork = new char[n+1];\r
-      int nStart = GetLength() - n;\r
-      strncpy(g_pStrWork, &m_pStr[nStart], n);\r
-      g_pStrWork[n] = '\0';\r
-    }\r
-    else\r
-    {\r
-      g_pStrWork = new char[1];\r
-      g_pStrWork[0] = '\0';\r
-    }\r
-    return g_pStrWork;\r
-  }\r
-\r
-  const char* Mid(int nFirst) const\r
-    {\r
-      return Mid(nFirst, strlen (m_pStr) - nFirst);\r
-    }\r
-\r
-  const char* Mid(int first, int n) const\r
-  {\r
-    delete []g_pStrWork;\r
-    if (n > 0)\r
-    {\r
-      g_pStrWork = new char[n+1];\r
-      strncpy(g_pStrWork, m_pStr+first, n);\r
-      g_pStrWork[n] = '\0';\r
-    }\r
-    else\r
-    {\r
-      g_pStrWork = "";\r
-      g_pStrWork = new char[1];\r
-      g_pStrWork[0] = '\0';\r
-    }\r
-    return g_pStrWork;\r
-  }\r
-\r
-#ifdef __G_LIB_H__\r
-  void Format(const char* fmt, ...)\r
-  {\r
-    va_list args;\r
-    char *buffer;\r
-  \r
-    va_start (args, fmt);\r
-    buffer = g_strdup_vprintf (fmt, args);\r
-    va_end (args);\r
-\r
-    delete[] m_pStr;\r
-    m_pStr = __StrDup(buffer);\r
-    g_free (buffer);\r
-  }\r
-#else\r
-  void Format(const char* fmt, ...)\r
-  {\r
-    va_list args;\r
-    m_pStr = new char[1024];\r
-\r
-    va_start (args, fmt);\r
-    vsprintf (m_pStr, fmt, args);\r
-    va_end (args);\r
-  }\r
-#endif\r
-\r
-  void SetAt(int n, char ch)\r
-  {\r
-    if (n >= 0 && n < GetLength ())\r
-      m_pStr[n] = ch;\r
-  }\r
-\r
-       // NOTE: unlike CString, this looses the pointer\r
-  void ReleaseBuffer(int n = -1)\r
-  {\r
-    if (n == -1)\r
-      n = GetLength ();\r
-\r
-    char* tmp = m_pStr;\r
-    tmp[n] = '\0';\r
-    m_pStr = __StrDup(tmp);\r
-    delete []tmp;\r
-  }\r
-\r
-  char* GetBufferSetLength(int n)\r
-  {\r
-    if (n < 0)\r
-      n = 0;\r
-\r
-    char *p = new char[n+1];\r
-    strncpy (p, m_pStr, n);\r
-               p[n] = '\0';\r
-    delete []m_pStr;\r
-    m_pStr = p;\r
-    return m_pStr;\r
-  }\r
-\r
-  //  char& operator *() { return *m_pStr; }\r
-  //  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }\r
-  operator void*() { return m_pStr; }\r
-  operator char*() { return m_pStr; }\r
-  operator const char*(){ return reinterpret_cast<const char*>(m_pStr); }\r
-  operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); }\r
-  operator const unsigned char*() { return reinterpret_cast<const unsigned char*>(m_pStr); }\r
-  Str& operator =(const Str& rhs)\r
-  {\r
-    if (&rhs != this)\r
-    {\r
-      delete[] m_pStr;\r
-      m_pStr = __StrDup(rhs.m_pStr);\r
-    }\r
-    return *this;\r
-  }\r
-  \r
-  Str& operator =(const char* pStr)\r
-  {\r
-    if (m_pStr != pStr)\r
-    {\r
-      delete[] m_pStr;\r
-      m_pStr = __StrDup(pStr);\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  Str& operator +=(const char ch)\r
-  {\r
-    int len = GetLength ();\r
-    char *p = new char[len + 1 + 1];\r
-\r
-    if (m_pStr)\r
-    {\r
-      strcpy(p, m_pStr);\r
-      delete[] m_pStr;\r
-    }\r
-\r
-    m_pStr = p;\r
-    m_pStr[len] = ch;\r
-    m_pStr[len+1] = '\0';\r
-\r
-    return *this;\r
-  }\r
-\r
-  Str& operator +=(const char *pStr)\r
-  {\r
-    if (pStr)\r
-    {\r
-      if (m_pStr)\r
-      {\r
-        char *p = new char[strlen(m_pStr) + strlen(pStr) + 1];\r
-        strcpy(p, m_pStr);\r
-        strcat(p, pStr);\r
-        delete[] m_pStr;\r
-        m_pStr = p;\r
-      }\r
-      else\r
-      {\r
-        m_pStr = __StrDup(pStr);\r
-      }\r
-    }\r
-    return *this;\r
-  }\r
-  \r
-\r
-  bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; }\r
-  bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }\r
-  bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; }\r
-  bool operator !=(Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) != 0 : strcmp(m_pStr, rhs.m_pStr) != 0; }\r
-  bool operator !=(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }\r
-  bool operator !=(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; }\r
-  bool operator <(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) < 0 : strcmp(m_pStr, rhs.m_pStr) < 0; }\r
-  bool operator <(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }\r
-  bool operator <(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; }\r
-  bool operator >(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) > 0 : strcmp(m_pStr, rhs.m_pStr) > 0; }\r
-  bool operator >(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }\r
-  bool operator >(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; }\r
-  char& operator [](int nIndex) { return m_pStr[nIndex]; }\r
-  char& operator [](int nIndex) const { return m_pStr[nIndex]; }\r
-  const char GetAt (int nIndex) { return m_pStr[nIndex]; }\r
-};\r
-\r
-\r
-\r
-#endif\r
+/*
+   Copyright (c) 2001, Loki software, inc.
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without modification,
+   are permitted provided that the following conditions are met:
+
+   Redistributions of source code must retain the above copyright notice, this list
+   of conditions and the following disclaimer.
+
+   Redistributions in binary form must reproduce the above copyright notice, this
+   list of conditions and the following disclaimer in the documentation and/or
+   other materials provided with the distribution.
+
+   Neither the name of Loki software nor the names of its contributors may be used
+   to endorse or promote products derived from this software without specific prior
+   written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+   DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STR__
+#define __STR__
+
+//
+// class Str
+// loose replacement for CString from MFC
+//
+
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#ifdef __APPLE__
+  #ifdef NULL
+       #undef NULL
+       #define NULL 0
+  #endif
+#endif
+
+
+#ifdef _WIN32
+#define strcasecmp strcmpi
+#endif
+
+// NOTE TTimo __StrDup was initially implemented in pakstuff.cpp
+//   causing a bunch of issues for broader targets that use Str.h (such as plugins and modules)
+//   Q_StrDup should be used now, using a #define __StrDup for easy transition
+
+#define __StrDup Q_StrDup
+
+inline char* Q_StrDup( char* _pStr ) {
+       const char* pStr = _pStr;
+       if ( pStr == NULL ) {
+               pStr = "";
+       }
+
+       return strcpy( new char[ strlen( pStr ) + 1 ], pStr );
+}
+
+inline char* Q_StrDup( const char* pStr ) {
+       if ( pStr == NULL ) {
+               pStr = "";
+       }
+
+       return strcpy( new char[strlen( pStr ) + 1], pStr );
+}
+
+#if defined ( __linux__ ) || defined ( __APPLE__ )
+#define strcmpi strcasecmp
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+inline char* strlwr( char* string ){
+       char *cp;
+       for ( cp = string; *cp; ++cp )
+       {
+               if ( 'A' <= *cp && *cp <= 'Z' ) {
+                       *cp += 'a' - 'A';
+               }
+       }
+
+       return string;
+}
+
+inline char* strupr( char* string ){
+       char *cp;
+       for ( cp = string; *cp; ++cp )
+       {
+               if ( 'a' <= *cp && *cp <= 'z' ) {
+                       *cp += 'A' - 'a';
+               }
+       }
+
+       return string;
+}
+#endif
+
+static char *g_pStrWork = NULL;
+
+class Str
+{
+protected:
+bool m_bIgnoreCase;
+char *m_pStr;
+
+public:
+Str(){
+       m_bIgnoreCase = true;
+       m_pStr = new char[1];
+       m_pStr[0] = '\0';
+}
+
+Str( char *p ){
+       m_bIgnoreCase = true;
+       m_pStr = __StrDup( p );
+}
+
+Str( const char *p ){
+       m_bIgnoreCase = true;
+       m_pStr = __StrDup( p );
+}
+
+Str( const unsigned char *p ){
+       m_bIgnoreCase = true;
+       m_pStr = __StrDup( (const char *)p );
+}
+
+Str( const char c ){
+       m_bIgnoreCase = true;
+       m_pStr = new char[2];
+       m_pStr[0] = c;
+       m_pStr[1] = '\0';
+}
+
+const char* GetBuffer() const {
+       return m_pStr;
+}
+
+Str( const Str &s ){
+       m_bIgnoreCase = true;
+       m_pStr = __StrDup( s.GetBuffer() );
+}
+
+void Deallocate(){
+       delete []m_pStr;
+       m_pStr = NULL;
+}
+
+void Allocate( int n ){
+       Deallocate();
+       m_pStr = new char[n];
+}
+
+void MakeEmpty(){
+       Deallocate();
+       m_pStr = __StrDup( "" );
+}
+
+virtual ~Str(){
+       Deallocate();
+       // NOTE TTimo: someone explain this g_pStrWork to me?
+       if ( g_pStrWork ) {
+               delete []g_pStrWork;
+       }
+       g_pStrWork = NULL;
+}
+
+void MakeLower(){
+       if ( m_pStr ) {
+               strlwr( m_pStr );
+       }
+}
+
+void MakeUpper(){
+       if ( m_pStr ) {
+               strupr( m_pStr );
+       }
+}
+
+void TrimRight(){
+       char* lpsz = m_pStr;
+       char* lpszLast = NULL;
+       while ( *lpsz != '\0' )
+       {
+               if ( isspace( *lpsz ) ) {
+                       if ( lpszLast == NULL ) {
+                               lpszLast = lpsz;
+                       }
+               }
+               else{
+                       lpszLast = NULL;
+               }
+               lpsz++;
+       }
+
+       if ( lpszLast != NULL ) {
+               // truncate at trailing space start
+               *lpszLast = '\0';
+       }
+}
+
+void TrimLeft(){
+       // find first non-space character
+       char* lpsz = m_pStr;
+       while ( isspace( *lpsz ) )
+               lpsz++;
+
+       // fix up data and length
+       int nDataLength = GetLength() - ( lpsz - m_pStr );
+       memmove( m_pStr, lpsz, ( nDataLength + 1 ) );
+}
+
+int Find( const char *p ){
+       char *pf = strstr( m_pStr, p );
+       return ( pf ) ? ( pf - m_pStr ) : -1;
+}
+
+// search starting at a given offset
+int Find( const char *p, int offset ){
+       char *pf = strstr( m_pStr + offset, p );
+       return ( pf ) ? ( pf - m_pStr ) : -1;
+}
+
+int Find( const char ch ){
+       char *pf = strchr( m_pStr, ch );
+       return ( pf ) ? ( pf - m_pStr ) : -1;
+}
+
+int ReverseFind( const char ch ){
+       char *pf = strrchr( m_pStr, ch );
+       return ( pf ) ? ( pf - m_pStr ) : -1;
+}
+
+int Compare( const char* str ) const {
+       return strcmp( m_pStr, str );
+}
+
+int CompareNoCase( const char* str ) const {
+       return strcasecmp( m_pStr, str );
+}
+
+int GetLength(){
+       return ( m_pStr ) ? strlen( m_pStr ) : 0;
+}
+
+const char* Left( int n ){
+       delete []g_pStrWork;
+       if ( n > 0 ) {
+               g_pStrWork = new char[n + 1];
+               strncpy( g_pStrWork, m_pStr, n );
+               g_pStrWork[n] = '\0';
+       }
+       else
+       {
+               g_pStrWork = new char[1];
+               g_pStrWork[0] = '\0';
+       }
+       return g_pStrWork;
+}
+
+const char* Right( int n ){
+       delete []g_pStrWork;
+       if ( n > 0 ) {
+               g_pStrWork = new char[n + 1];
+               int nStart = GetLength() - n;
+               strncpy( g_pStrWork, &m_pStr[nStart], n );
+               g_pStrWork[n] = '\0';
+       }
+       else
+       {
+               g_pStrWork = new char[1];
+               g_pStrWork[0] = '\0';
+       }
+       return g_pStrWork;
+}
+
+const char* Mid( int nFirst ) const {
+       return Mid( nFirst, strlen( m_pStr ) - nFirst );
+}
+
+const char* Mid( int first, int n ) const {
+       delete []g_pStrWork;
+       if ( n > 0 ) {
+               g_pStrWork = new char[n + 1];
+               strncpy( g_pStrWork, m_pStr + first, n );
+               g_pStrWork[n] = '\0';
+       }
+       else
+       {
+               g_pStrWork = new char[1];
+               g_pStrWork[0] = '\0';
+       }
+       return g_pStrWork;
+}
+
+#ifdef __G_LIB_H__
+void Format( const char* fmt, ... ){
+       va_list args;
+       char *buffer;
+
+       va_start( args, fmt );
+       buffer = g_strdup_vprintf( fmt, args );
+       va_end( args );
+
+       delete[] m_pStr;
+       m_pStr = __StrDup( buffer );
+       g_free( buffer );
+}
+#else
+void Format( const char* fmt, ... ){
+       va_list args;
+       m_pStr = new char[1024];
+
+       va_start( args, fmt );
+       vsprintf( m_pStr, fmt, args );
+       va_end( args );
+}
+#endif
+
+void SetAt( int n, char ch ){
+       if ( n >= 0 && n < GetLength() ) {
+               m_pStr[n] = ch;
+       }
+}
+
+// NOTE: unlike CString, this looses the pointer
+void ReleaseBuffer( int n = -1 ){
+       if ( n == -1 ) {
+               n = GetLength();
+       }
+
+       char* tmp = m_pStr;
+       tmp[n] = '\0';
+       m_pStr = __StrDup( tmp );
+       delete []tmp;
+}
+
+char* GetBufferSetLength( int n ){
+       if ( n < 0 ) {
+               n = 0;
+       }
+
+       char *p = new char[n + 1];
+       strncpy( p, m_pStr, n );
+       p[n] = '\0';
+       delete []m_pStr;
+       m_pStr = p;
+       return m_pStr;
+}
+
+//  char& operator *() { return *m_pStr; }
+//  char& operator *() const { return *const_cast<Str*>(this)->m_pStr; }
+operator void*() {
+       return m_pStr;
+}
+operator char*() {
+       return m_pStr;
+}
+operator const char*(){
+       return reinterpret_cast<const char*>( m_pStr );
+}
+operator unsigned char*() {
+       return reinterpret_cast<unsigned char*>( m_pStr );
+}
+operator const unsigned char*() {
+       return reinterpret_cast<const unsigned char*>( m_pStr );
+}
+Str& operator =( const Str& rhs ){
+       if ( &rhs != this ) {
+               delete[] m_pStr;
+               m_pStr = __StrDup( rhs.m_pStr );
+       }
+       return *this;
+}
+
+Str& operator =( const char* pStr ){
+       if ( m_pStr != pStr ) {
+               delete[] m_pStr;
+               m_pStr = __StrDup( pStr );
+       }
+       return *this;
+}
+
+Str& operator +=( const char ch ){
+       int len = GetLength();
+       char *p = new char[len + 1 + 1];
+
+       if ( m_pStr ) {
+               strcpy( p, m_pStr );
+               delete[] m_pStr;
+       }
+
+       m_pStr = p;
+       m_pStr[len] = ch;
+       m_pStr[len + 1] = '\0';
+
+       return *this;
+}
+
+Str& operator +=( const char *pStr ){
+       if ( pStr ) {
+               if ( m_pStr ) {
+                       char *p = new char[strlen( m_pStr ) + strlen( pStr ) + 1];
+                       strcpy( p, m_pStr );
+                       strcat( p, pStr );
+                       delete[] m_pStr;
+                       m_pStr = p;
+               }
+               else
+               {
+                       m_pStr = __StrDup( pStr );
+               }
+       }
+       return *this;
+}
+
+
+bool operator ==( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) == 0 : strcmp( m_pStr, rhs.m_pStr ) == 0; }
+bool operator ==( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
+bool operator ==( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) == 0 : strcmp( m_pStr, pStr ) == 0; }
+bool operator !=( Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) != 0 : strcmp( m_pStr, rhs.m_pStr ) != 0; }
+bool operator !=( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
+bool operator !=( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) != 0 : strcmp( m_pStr, pStr ) != 0; }
+bool operator <( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) < 0 : strcmp( m_pStr, rhs.m_pStr ) < 0; }
+bool operator <( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
+bool operator <( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) < 0 : strcmp( m_pStr, pStr ) < 0; }
+bool operator >( const Str& rhs ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, rhs.m_pStr ) > 0 : strcmp( m_pStr, rhs.m_pStr ) > 0; }
+bool operator >( char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
+bool operator >( const char* pStr ) const { return ( m_bIgnoreCase ) ? stricmp( m_pStr, pStr ) > 0 : strcmp( m_pStr, pStr ) > 0; }
+char& operator []( int nIndex ) { return m_pStr[nIndex]; }
+char& operator []( int nIndex ) const { return m_pStr[nIndex]; }
+const char GetAt( int nIndex ) { return m_pStr[nIndex]; }
+};
+
+
+
+#endif