]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/splines/util_str.cpp
Centralise compile checks
[xonotic/netradiant.git] / libs / splines / util_str.cpp
index 436285ade1765ad69b9ba884988d44e61e96996f..c64ca73b7f52acac1edbb1bbb07c2ee3e36efafb 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-//need to rewrite this\r
-\r
-#include "util_str.h"\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-#include <stdio.h>\r
-#include <stdarg.h>\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4244)     // 'conversion' conversion from 'type1' to 'type2', possible loss of data\r
-#pragma warning(disable : 4710)     // function 'blah' not inlined\r
-#endif\r
-\r
-static const int STR_ALLOC_GRAN = 20;\r
-\r
-// screwy but intentional\r
-#ifdef __APPLE_BUG__\r
-char *idStr::__tolower\r
-#else\r
-char *idStr::tolower\r
-#endif\r
-   (\r
-   char *s1\r
-   )\r
-   \r
-   {\r
-   char *s;\r
-\r
-   s = s1;\r
-       while( *s )\r
-      {\r
-      *s = ::tolower( *s );\r
-               s++;\r
-          }\r
-   \r
-   return s1;\r
-   }\r
-\r
-// screwy but intentional\r
-#ifdef __APPLE_BUG__\r
-char *idStr::__toupper\r
-#else\r
-char *idStr::toupper\r
-#endif\r
-   (\r
-   char *s1\r
-   )\r
-   \r
-   {\r
-   char *s;\r
-\r
-   s = s1;\r
-       while( *s )\r
-      {\r
-      *s = ::toupper( *s );\r
-               s++;\r
-          }\r
-   \r
-   return s1;\r
-   }\r
-\r
-int idStr::icmpn\r
-   (\r
-   const char *s1, \r
-   const char *s2, \r
-   int n\r
-   )\r
-   \r
-   {\r
-       int c1;\r
-   int c2;\r
-       \r
-       do \r
-      {\r
-               c1 = *s1++;\r
-               c2 = *s2++;\r
-\r
-               if ( !n-- )\r
-         {\r
-         // idStrings are equal until end point\r
-                       return 0;\r
-                  }\r
-               \r
-               if ( c1 != c2 )\r
-         {\r
-                       if ( c1 >= 'a' && c1 <= 'z' )\r
-            {\r
-                               c1 -= ( 'a' - 'A' );\r
-                          }\r
-\r
-                       if ( c2 >= 'a' && c2 <= 'z' )\r
-            {\r
-                               c2 -= ( 'a' - 'A' );\r
-                          }\r
-\r
-                       if ( c1 < c2 )\r
-            {\r
-            // strings less than\r
-                               return -1;\r
-                          }\r
-         else if ( c1 > c2 ) \r
-            {\r
-            // strings greater than\r
-            return 1;\r
-            }\r
-                  }\r
-          } \r
-   while( c1 );\r
-       \r
-   // strings are equal\r
-       return 0;\r
-   }\r
-\r
-int idStr::icmp\r
-   (\r
-   const char *s1,\r
-   const char *s2\r
-   )\r
-   \r
-   {\r
-       int c1;\r
-   int c2;\r
-       \r
-       do \r
-      {\r
-               c1 = *s1++;\r
-               c2 = *s2++;\r
-\r
-               if ( c1 != c2 )\r
-         {\r
-                       if ( c1 >= 'a' && c1 <= 'z' )\r
-            {\r
-                               c1 -= ( 'a' - 'A' );\r
-                          }\r
-\r
-                       if ( c2 >= 'a' && c2 <= 'z' )\r
-            {\r
-                               c2 -= ( 'a' - 'A' );\r
-                          }\r
-\r
-                       if ( c1 < c2 )\r
-            {\r
-            // strings less than\r
-                               return -1;\r
-                          }\r
-         else if ( c1 > c2 ) \r
-            {\r
-            // strings greater than\r
-            return 1;\r
-            }\r
-                  }\r
-          } \r
-   while( c1 );\r
-       \r
-   // strings are equal\r
-       return 0;\r
-   }\r
-\r
-int idStr::cmpn\r
-   (\r
-   const char *s1, \r
-   const char *s2, \r
-   int n\r
-   )\r
-   \r
-   {\r
-       int c1;\r
-   int c2;\r
-       \r
-       do \r
-      {\r
-               c1 = *s1++;\r
-               c2 = *s2++;\r
-\r
-               if ( !n-- )\r
-         {\r
-         // strings are equal until end point\r
-                       return 0;\r
-                  }\r
-               \r
-               if ( c1 < c2 )\r
-         {\r
-         // strings less than\r
-                       return -1;\r
-                       }\r
-      else if ( c1 > c2 ) \r
-         {\r
-         // strings greater than\r
-         return 1;\r
-         }\r
-          } \r
-   while( c1 );\r
-       \r
-   // strings are equal\r
-       return 0;\r
-   }\r
-\r
-int idStr::cmp\r
-   (\r
-   const char *s1, \r
-   const char *s2\r
-   )\r
-   \r
-   {\r
-       int c1;\r
-   int c2;\r
-       \r
-       do \r
-      {\r
-               c1 = *s1++;\r
-               c2 = *s2++;\r
-\r
-               if ( c1 < c2 )\r
-         {\r
-         // strings less than\r
-                       return -1;\r
-                       }\r
-      else if ( c1 > c2 ) \r
-         {\r
-         // strings greater than\r
-         return 1;\r
-         }\r
-          } \r
-   while( c1 );\r
-       \r
-   // strings are equal\r
-       return 0;\r
-   }\r
-\r
-/*\r
-============\r
-IsNumeric\r
-\r
-Checks a string to see if it contains only numerical values.\r
-============\r
-*/\r
-bool idStr::isNumeric\r
-   (\r
-   const char *str\r
-   )\r
-\r
-   {\r
-       int len;\r
-       int i;\r
-       bool dot;\r
-\r
-       if ( *str == '-' )\r
-               {\r
-               str++;\r
-               }\r
-\r
-       dot = false;\r
-       len = strlen( str );\r
-       for( i = 0; i < len; i++ )\r
-               {\r
-               if ( !isdigit( str[ i ] ) )\r
-                       {\r
-                       if ( ( str[ i ] == '.' ) && !dot )\r
-                               {\r
-                               dot = true;\r
-                               continue;\r
-                               }\r
-                       return false;\r
-                       }\r
-               }\r
-\r
-       return true;\r
-   }\r
-\r
-idStr operator+\r
-   (\r
-   const idStr& a,\r
-   const float b\r
-   )\r
-\r
-   {\r
-   char text[ 20 ];\r
-\r
-       idStr result( a );\r
-\r
-   sprintf( text, "%f", b );\r
-       result.append( text );\r
-\r
-       return result;\r
-   }\r
-\r
-idStr operator+\r
-   (\r
-   const idStr& a,\r
-   const int b\r
-   )\r
-\r
-   {\r
-   char text[ 20 ];\r
-\r
-       idStr result( a );\r
-\r
-   sprintf( text, "%d", b );\r
-       result.append( text );\r
-\r
-       return result;\r
-   }\r
-\r
-idStr operator+\r
-   (\r
-   const idStr& a,\r
-   const unsigned b\r
-   )\r
-\r
-   {\r
-   char text[ 20 ];\r
-\r
-       idStr result( a );\r
-\r
-   sprintf( text, "%u", b );\r
-       result.append( text );\r
-\r
-       return result;\r
-   }\r
-\r
-idStr& idStr::operator+=\r
-       (\r
-       const float a\r
-       )\r
-\r
-       {\r
-   char text[ 20 ];\r
-\r
-   sprintf( text, "%f", a );\r
-       append( text );\r
-\r
-   return *this;\r
-       }\r
-\r
-idStr& idStr::operator+=\r
-       (\r
-       const int a\r
-       )\r
-\r
-       {\r
-   char text[ 20 ];\r
-\r
-   sprintf( text, "%d", a );\r
-       append( text );\r
-\r
-   return *this;\r
-       }\r
-\r
-idStr& idStr::operator+=\r
-       (\r
-       const unsigned a\r
-       )\r
-\r
-       {\r
-   char text[ 20 ];\r
-\r
-   sprintf( text, "%u", a );\r
-       append( text );\r
-\r
-   return *this;\r
-       }\r
-\r
-void idStr::CapLength \r
-   (\r
-   int newlen \r
-   )\r
-\r
-   {\r
-   assert ( m_data );\r
-   \r
-   if ( length() <= newlen )\r
-      return;\r
-\r
-   EnsureDataWritable ();\r
-\r
-   m_data->data[newlen] = 0;\r
-   m_data->len = newlen;\r
-   }\r
-\r
-void idStr::EnsureDataWritable \r
-   (\r
-   void\r
-   )\r
-\r
-   {\r
-   assert ( m_data );\r
-   strdata *olddata;\r
-   int len;\r
-\r
-   if ( !m_data->refcount )\r
-      return;\r
-\r
-   olddata = m_data;\r
-   len = length();\r
-\r
-   m_data = new strdata;\r
-\r
-   EnsureAlloced ( len + 1, false );\r
-   strncpy ( m_data->data, olddata->data, len+1 );\r
-   m_data->len = len;\r
-\r
-   olddata->DelRef ();\r
-   }\r
-\r
-void idStr::EnsureAlloced (int amount, bool keepold) {\r
-\r
-       if ( !m_data ) {\r
-      m_data = new strdata();\r
-       }\r
-   \r
-       // Now, let's make sure it's writable\r
-       EnsureDataWritable ();\r
-\r
-       char *newbuffer;\r
-       bool wasalloced = ( m_data->alloced != 0 );\r
-\r
-       if ( amount < m_data->alloced ) {\r
-               return;\r
-       }\r
-\r
-       assert ( amount );\r
-       if ( amount == 1 ) {\r
-               m_data->alloced = 1;\r
-       } else {\r
-               int newsize, mod;\r
-               mod = amount % STR_ALLOC_GRAN;\r
-               if ( !mod ) {\r
-                       newsize = amount;\r
-               } else {\r
-         newsize = amount + STR_ALLOC_GRAN - mod;\r
-               }\r
-               m_data->alloced = newsize;\r
-       }\r
-\r
-       newbuffer = new char[m_data->alloced];\r
-       if ( wasalloced && keepold ) {\r
-               strcpy ( newbuffer, m_data->data );\r
-       }\r
-\r
-       if ( m_data->data ) {\r
-               delete [] m_data->data;\r
-    }\r
-       m_data->data = newbuffer;\r
-}\r
-\r
-void idStr::BackSlashesToSlashes\r
-   (\r
-   void\r
-   )\r
-\r
-   {\r
-   int i;\r
-\r
-   EnsureDataWritable ();\r
-\r
-   for ( i=0; i < m_data->len; i++ )\r
-      {\r
-      if ( m_data->data[i] == '\\' )\r
-         m_data->data[i] = '/';\r
-      }\r
-   }\r
-\r
-void idStr::snprintf \r
-   (\r
-   char *dst,\r
-   int size,\r
-   const char *fmt, \r
-   ...\r
-   )\r
-\r
-   {\r
-   char buffer[0x10000];\r
-       int             len;\r
-       va_list         argptr;\r
-\r
-       va_start (argptr,fmt);\r
-       len = vsprintf (buffer,fmt,argptr);\r
-       va_end (argptr);\r
-       \r
-   assert ( len < size );\r
-\r
-   strncpy (dst, buffer, size-1);\r
-   }\r
-\r
-#ifdef _WIN32\r
-#pragma warning(disable : 4189)                // local variable is initialized but not referenced\r
-#endif\r
-\r
-/*\r
-=================\r
-TestStringClass\r
-\r
-This is a fairly rigorous test of the idStr class's functionality.\r
-Because of the fairly global and subtle ramifications of a bug occuring\r
-in this class, it should be run after any changes to the class.\r
-Add more tests as functionality is changed.  Tests should include\r
-any possible bounds violation and NULL data tests.\r
-=================\r
-*/\r
-void TestStringClass\r
-       (\r
-       void \r
-       )\r
-\r
-       {\r
-       char    ch;                                                     // ch == ?\r
-       idStr   *t;                                                     // t == ?\r
-       idStr   a;                                                              // a.len == 0, a.data == "\0"\r
-       idStr   b;                                                              // b.len == 0, b.data == "\0"\r
-       idStr   c( "test" );                            // c.len == 4, c.data == "test\0"\r
-       idStr   d( c );                                         // d.len == 4, d.data == "test\0"\r
-       idStr   e( reinterpret_cast<const char *>(NULL) );                                      \r
-                                 // e.len == 0, e.data == "\0"                                 ASSERT!\r
-       int     i;                                                              // i == ?\r
-\r
-       i = a.length();                                 // i == 0\r
-       i = c.length();                                 // i == 4\r
-\r
-       const char *s1 = a.c_str();     // s1 == "\0"\r
-       const char *s2 = c.c_str();     // s2 == "test\0"\r
-\r
-       t = new idStr();                                                // t->len == 0, t->data == "\0"\r
-       delete t;                                                       // t == ?\r
-\r
-       b = "test";                                                     // b.len == 4, b.data == "test\0"\r
-       t = new idStr( "test" );                        // t->len == 4, t->data == "test\0"\r
-       delete t;                                                       // t == ?\r
-\r
-       a = c;                                                          // a.len == 4, a.data == "test\0"\r
-//   a = "";\r
-   a = NULL;                                                   // a.len == 0, a.data == "\0"                                   ASSERT!\r
-       a = c + d;                                                      // a.len == 8, a.data == "testtest\0"\r
-       a = c + "wow";                                          // a.len == 7, a.data == "testwow\0"\r
-       a = c + reinterpret_cast<const char *>(NULL);\r
-                                 // a.len == 4, a.data == "test\0"                     ASSERT!\r
-       a = "this" + d;                                 // a.len == 8, a.data == "thistest\0"\r
-       a = reinterpret_cast<const char *>(NULL) + d;\r
-                                 // a.len == 4, a.data == "test\0"                     ASSERT!\r
-       a += c;                                                         // a.len == 8, a.data == "testtest\0"\r
-       a += "wow";                                                     // a.len == 11, a.data == "testtestwow\0"\r
-       a += reinterpret_cast<const char *>(NULL);\r
-                                 // a.len == 11, a.data == "testtestwow\0"     ASSERT!\r
-\r
-       a = "test";                                                     // a.len == 4, a.data == "test\0"\r
-       ch = a[ 0 ];                                            // ch == 't'\r
-       ch = a[ -1 ];                                           // ch == 0                                                                                      ASSERT!\r
-       ch = a[ 1000 ];                                 // ch == 0                                                                                      ASSERT!\r
-       ch = a[ 0 ];                                            // ch == 't'\r
-       ch = a[ 1 ];                                            // ch == 'e'\r
-       ch = a[ 2 ];                                            // ch == 's'\r
-       ch = a[ 3 ];                                            // ch == 't'\r
-       ch = a[ 4 ];                                            // ch == '\0'                                                                           ASSERT!\r
-       ch = a[ 5 ];                                            // ch == '\0'                                                                           ASSERT!\r
-\r
-       a[ 1 ] = 'b';                                           // a.len == 4, a.data == "tbst\0"\r
-       a[ -1 ] = 'b';                                          // a.len == 4, a.data == "tbst\0"                       ASSERT!\r
-       a[ 0 ] = '0';                                           // a.len == 4, a.data == "0bst\0"\r
-       a[ 1 ] = '1';                                           // a.len == 4, a.data == "01st\0"\r
-       a[ 2 ] = '2';                                           // a.len == 4, a.data == "012t\0"\r
-       a[ 3 ] = '3';                                           // a.len == 4, a.data == "0123\0"\r
-       a[ 4 ] = '4';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!\r
-       a[ 5 ] = '5';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!\r
-       a[ 7 ] = '7';                                           // a.len == 4, a.data == "0123\0"                       ASSERT!\r
-\r
-       a = "test";                                                     // a.len == 4, a.data == "test\0"\r
-       b = "no";                                                       // b.len == 2, b.data == "no\0"\r
-\r
-       i = ( a == b );                                 // i == 0\r
-       i = ( a == c );                                 // i == 1\r
-\r
-       i = ( a == "blow" );                            // i == 0\r
-       i = ( a == "test" );                            // i == 1\r
-       i = ( a == NULL );                              // i == 0                                                                                       ASSERT!\r
-\r
-       i = ( "test" == b );                            // i == 0\r
-       i = ( "test" == a );                            // i == 1\r
-       i = ( NULL == a );                              // i == 0                                                                                       ASSERT!\r
-\r
-       i = ( a != b );                                 // i == 1\r
-       i = ( a != c );                                 // i == 0\r
-\r
-       i = ( a != "blow" );                            // i == 1\r
-       i = ( a != "test" );                            // i == 0\r
-       i = ( a != NULL );                              // i == 1                                                                                       ASSERT!\r
-\r
-       i = ( "test" != b );                            // i == 1\r
-       i = ( "test" != a );                            // i == 0\r
-       i = ( NULL != a );                              // i == 1                                                                                       ASSERT!\r
-\r
-   a = "test";                   // a.data == "test"\r
-   b = a;                        // b.data == "test"\r
-\r
-   a = "not";                   // a.data == "not", b.data == "test"\r
-\r
-   a = b;                        // a.data == b.data == "test"\r
-\r
-   a += b;                       // a.data == "testtest", b.data = "test"\r
-\r
-   a = b;\r
-\r
-   a[1] = '1';                   // a.data = "t1st", b.data = "test"\r
-       }\r
-\r
-#ifdef _WIN32\r
-#pragma warning(default : 4189)                // local variable is initialized but not referenced\r
-#pragma warning(disable : 4514)     // unreferenced inline function has been removed\r
-#endif\r
+/*
+   Copyright (C) 1999-2006 Id Software, Inc. and contributors.
+   For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+   This file is part of GtkRadiant.
+
+   GtkRadiant is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   GtkRadiant is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GtkRadiant; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+//need to rewrite this
+
+#include "util_str.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#if GDEF_COMPILER_MSVC
+#pragma warning(disable : 4244)     // 'conversion' conversion from 'type1' to 'type2', possible loss of data
+#pragma warning(disable : 4710)     // function 'blah' not inlined
+#endif
+
+static const int STR_ALLOC_GRAN = 20;
+
+// screwy but intentional
+#ifdef __APPLE_BUG__
+char *idStr::__tolower
+#else
+char *idStr::tolower
+#endif
+(
+       char *s1
+){
+       char *s;
+
+       s = s1;
+       while ( *s )
+       {
+               *s = ::tolower( *s );
+               s++;
+       }
+
+       return s1;
+}
+
+// screwy but intentional
+#ifdef __APPLE_BUG__
+char *idStr::__toupper
+#else
+char *idStr::toupper
+#endif
+(
+       char *s1
+){
+       char *s;
+
+       s = s1;
+       while ( *s )
+       {
+               *s = ::toupper( *s );
+               s++;
+       }
+
+       return s1;
+}
+
+int idStr::icmpn
+(
+       const char *s1,
+       const char *s2,
+       int n
+){
+       int c1;
+       int c2;
+
+       do
+       {
+               c1 = *s1++;
+               c2 = *s2++;
+
+               if ( !n-- ) {
+                       // idStrings are equal until end point
+                       return 0;
+               }
+
+               if ( c1 != c2 ) {
+                       if ( c1 >= 'a' && c1 <= 'z' ) {
+                               c1 -= ( 'a' - 'A' );
+                       }
+
+                       if ( c2 >= 'a' && c2 <= 'z' ) {
+                               c2 -= ( 'a' - 'A' );
+                       }
+
+                       if ( c1 < c2 ) {
+                               // strings less than
+                               return -1;
+                       }
+                       else if ( c1 > c2 ) {
+                               // strings greater than
+                               return 1;
+                       }
+               }
+       }
+       while ( c1 );
+
+       // strings are equal
+       return 0;
+}
+
+int idStr::icmp
+(
+       const char *s1,
+       const char *s2
+){
+       int c1;
+       int c2;
+
+       do
+       {
+               c1 = *s1++;
+               c2 = *s2++;
+
+               if ( c1 != c2 ) {
+                       if ( c1 >= 'a' && c1 <= 'z' ) {
+                               c1 -= ( 'a' - 'A' );
+                       }
+
+                       if ( c2 >= 'a' && c2 <= 'z' ) {
+                               c2 -= ( 'a' - 'A' );
+                       }
+
+                       if ( c1 < c2 ) {
+                               // strings less than
+                               return -1;
+                       }
+                       else if ( c1 > c2 ) {
+                               // strings greater than
+                               return 1;
+                       }
+               }
+       }
+       while ( c1 );
+
+       // strings are equal
+       return 0;
+}
+
+int idStr::cmpn
+(
+       const char *s1,
+       const char *s2,
+       int n
+){
+       int c1;
+       int c2;
+
+       do
+       {
+               c1 = *s1++;
+               c2 = *s2++;
+
+               if ( !n-- ) {
+                       // strings are equal until end point
+                       return 0;
+               }
+
+               if ( c1 < c2 ) {
+                       // strings less than
+                       return -1;
+               }
+               else if ( c1 > c2 ) {
+                       // strings greater than
+                       return 1;
+               }
+       }
+       while ( c1 );
+
+       // strings are equal
+       return 0;
+}
+
+int idStr::cmp
+(
+       const char *s1,
+       const char *s2
+){
+       int c1;
+       int c2;
+
+       do
+       {
+               c1 = *s1++;
+               c2 = *s2++;
+
+               if ( c1 < c2 ) {
+                       // strings less than
+                       return -1;
+               }
+               else if ( c1 > c2 ) {
+                       // strings greater than
+                       return 1;
+               }
+       }
+       while ( c1 );
+
+       // strings are equal
+       return 0;
+}
+
+/*
+   ============
+   IsNumeric
+
+   Checks a string to see if it contains only numerical values.
+   ============
+ */
+bool idStr::isNumeric
+(
+       const char *str
+){
+       int len;
+       int i;
+       bool dot;
+
+       if ( *str == '-' ) {
+               str++;
+       }
+
+       dot = false;
+       len = strlen( str );
+       for ( i = 0; i < len; i++ )
+       {
+               if ( !isdigit( str[ i ] ) ) {
+                       if ( ( str[ i ] == '.' ) && !dot ) {
+                               dot = true;
+                               continue;
+                       }
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+idStr operator+
+(
+       const idStr& a,
+       const float b
+){
+       char text[ 20 ];
+
+       idStr result( a );
+
+       sprintf( text, "%f", b );
+       result.append( text );
+
+       return result;
+}
+
+idStr operator+
+(
+       const idStr& a,
+       const int b
+){
+       char text[ 20 ];
+
+       idStr result( a );
+
+       sprintf( text, "%d", b );
+       result.append( text );
+
+       return result;
+}
+
+idStr operator+
+(
+       const idStr& a,
+       const unsigned b
+){
+       char text[ 20 ];
+
+       idStr result( a );
+
+       sprintf( text, "%u", b );
+       result.append( text );
+
+       return result;
+}
+
+idStr& idStr::operator+=
+(
+       const float a
+){
+       char text[ 20 ];
+
+       sprintf( text, "%f", a );
+       append( text );
+
+       return *this;
+}
+
+idStr& idStr::operator+=
+(
+       const int a
+){
+       char text[ 20 ];
+
+       sprintf( text, "%d", a );
+       append( text );
+
+       return *this;
+}
+
+idStr& idStr::operator+=
+(
+       const unsigned a
+){
+       char text[ 20 ];
+
+       sprintf( text, "%u", a );
+       append( text );
+
+       return *this;
+}
+
+void idStr::CapLength
+(
+       int newlen
+){
+       assert( m_data );
+
+       if ( length() <= newlen ) {
+               return;
+       }
+
+       EnsureDataWritable();
+
+       m_data->data[newlen] = 0;
+       m_data->len = newlen;
+}
+
+void idStr::EnsureDataWritable
+(
+       void
+){
+       assert( m_data );
+       strdata *olddata;
+       int len;
+
+       if ( !m_data->refcount ) {
+               return;
+       }
+
+       olddata = m_data;
+       len = length();
+
+       m_data = new strdata;
+
+       EnsureAlloced( len + 1, false );
+       strncpy( m_data->data, olddata->data, len + 1 );
+       m_data->len = len;
+
+       olddata->DelRef();
+}
+
+void idStr::EnsureAlloced( int amount, bool keepold ) {
+
+       if ( !m_data ) {
+               m_data = new strdata();
+       }
+
+       // Now, let's make sure it's writable
+       EnsureDataWritable();
+
+       char *newbuffer;
+       bool wasalloced = ( m_data->alloced != 0 );
+
+       if ( amount < m_data->alloced ) {
+               return;
+       }
+
+       assert( amount );
+       if ( amount == 1 ) {
+               m_data->alloced = 1;
+       }
+       else {
+               int newsize, mod;
+               mod = amount % STR_ALLOC_GRAN;
+               if ( !mod ) {
+                       newsize = amount;
+               }
+               else {
+                       newsize = amount + STR_ALLOC_GRAN - mod;
+               }
+               m_data->alloced = newsize;
+       }
+
+       newbuffer = new char[m_data->alloced];
+       if ( wasalloced && keepold ) {
+               strcpy( newbuffer, m_data->data );
+       }
+
+       if ( m_data->data ) {
+               delete [] m_data->data;
+       }
+       m_data->data = newbuffer;
+}
+
+void idStr::BackSlashesToSlashes
+(
+       void
+){
+       int i;
+
+       EnsureDataWritable();
+
+       for ( i = 0; i < m_data->len; i++ )
+       {
+               if ( m_data->data[i] == '\\' ) {
+                       m_data->data[i] = '/';
+               }
+       }
+}
+
+void idStr::snprintf
+(
+       char *dst,
+       int size,
+       const char *fmt,
+       ...
+){
+       char buffer[0x10000];
+       int len;
+       va_list argptr;
+
+       va_start( argptr,fmt );
+       len = vsprintf( buffer,fmt,argptr );
+       va_end( argptr );
+
+       assert( len < size );
+
+       strncpy( dst, buffer, size - 1 );
+}
+
+#if GDEF_COMPILER_MSVC
+#pragma warning(disable : 4189)     // local variable is initialized but not referenced
+#endif
+
+/*
+   =================
+   TestStringClass
+
+   This is a fairly rigorous test of the idStr class's functionality.
+   Because of the fairly global and subtle ramifications of a bug occuring
+   in this class, it should be run after any changes to the class.
+   Add more tests as functionality is changed.  Tests should include
+   any possible bounds violation and NULL data tests.
+   =================
+ */
+void TestStringClass
+(
+       void
+){
+       char ch;                            // ch == ?
+       (void) ch;
+       idStr   *t;                         // t == ?
+       idStr a;                                // a.len == 0, a.data == "\0"
+       idStr b;                                // b.len == 0, b.data == "\0"
+       idStr c( "test" );                  // c.len == 4, c.data == "test\0"
+       idStr d( c );                       // d.len == 4, d.data == "test\0"
+       idStr e( static_cast<const char *>( NULL ) );
+       // e.len == 0, e.data == "\0"                                   ASSERT!
+       int i;                              // i == ?
+       (void) i;
+
+       i = a.length();                 // i == 0
+       i = c.length();                 // i == 4
+
+       t = new idStr();                        // t->len == 0, t->data == "\0"
+       delete t;                           // t == ?
+
+       b = "test";                         // b.len == 4, b.data == "test\0"
+       t = new idStr( "test" );            // t->len == 4, t->data == "test\0"
+       delete t;                           // t == ?
+
+       a = c;                              // a.len == 4, a.data == "test\0"
+//   a = "";
+       a = NULL;                           // a.len == 0, a.data == "\0"                                       ASSERT!
+       a = c + d;                          // a.len == 8, a.data == "testtest\0"
+       a = c + "wow";                      // a.len == 7, a.data == "testwow\0"
+       a = c + static_cast<const char *>( NULL );
+       // a.len == 4, a.data == "test\0"                       ASSERT!
+       a = "this" + d;                 // a.len == 8, a.data == "thistest\0"
+       a = static_cast<const char *>( NULL ) + d;
+       // a.len == 4, a.data == "test\0"                       ASSERT!
+       a += c;                             // a.len == 8, a.data == "testtest\0"
+       a += "wow";                         // a.len == 11, a.data == "testtestwow\0"
+       a += static_cast<const char *>( NULL );
+       // a.len == 11, a.data == "testtestwow\0"       ASSERT!
+
+       a = "test";                         // a.len == 4, a.data == "test\0"
+       ch = a[ 0 ];                        // ch == 't'
+       ch = a[ -1 ];                       // ch == 0                                                                                  ASSERT!
+       ch = a[ 1000 ];                 // ch == 0                                                                                      ASSERT!
+       ch = a[ 0 ];                        // ch == 't'
+       ch = a[ 1 ];                        // ch == 'e'
+       ch = a[ 2 ];                        // ch == 's'
+       ch = a[ 3 ];                        // ch == 't'
+       ch = a[ 4 ];                        // ch == '\0'                                                                               ASSERT!
+       ch = a[ 5 ];                        // ch == '\0'                                                                               ASSERT!
+
+       a[ 1 ] = 'b';                       // a.len == 4, a.data == "tbst\0"
+       a[ -1 ] = 'b';                      // a.len == 4, a.data == "tbst\0"                   ASSERT!
+       a[ 0 ] = '0';                       // a.len == 4, a.data == "0bst\0"
+       a[ 1 ] = '1';                       // a.len == 4, a.data == "01st\0"
+       a[ 2 ] = '2';                       // a.len == 4, a.data == "012t\0"
+       a[ 3 ] = '3';                       // a.len == 4, a.data == "0123\0"
+       a[ 4 ] = '4';                       // a.len == 4, a.data == "0123\0"                   ASSERT!
+       a[ 5 ] = '5';                       // a.len == 4, a.data == "0123\0"                   ASSERT!
+       a[ 7 ] = '7';                       // a.len == 4, a.data == "0123\0"                   ASSERT!
+
+       a = "test";                         // a.len == 4, a.data == "test\0"
+       b = "no";                           // b.len == 2, b.data == "no\0"
+
+       i = ( a == b );                 // i == 0
+       i = ( a == c );                 // i == 1
+
+       i = ( a == "blow" );                // i == 0
+       i = ( a == "test" );                // i == 1
+       i = ( a == NULL );              // i == 0                                                                                       ASSERT!
+
+       i = ( "test" == b );                // i == 0
+       i = ( "test" == a );                // i == 1
+       i = ( NULL == a );              // i == 0                                                                                       ASSERT!
+
+       i = ( a != b );                 // i == 1
+       i = ( a != c );                 // i == 0
+
+       i = ( a != "blow" );                // i == 1
+       i = ( a != "test" );                // i == 0
+       i = ( a != NULL );              // i == 1                                                                                       ASSERT!
+
+       i = ( "test" != b );                // i == 1
+       i = ( "test" != a );                // i == 0
+       i = ( NULL != a );              // i == 1                                                                                       ASSERT!
+
+       a = "test";                  // a.data == "test"
+       b = a;                       // b.data == "test"
+
+       a = "not";                  // a.data == "not", b.data == "test"
+
+       a = b;                       // a.data == b.data == "test"
+
+       a += b;                      // a.data == "testtest", b.data = "test"
+
+       a = b;
+
+       a[1] = '1';                  // a.data = "t1st", b.data = "test"
+}
+
+#if GDEF_COMPILER_MSVC
+#pragma warning(default : 4189)     // local variable is initialized but not referenced
+#pragma warning(disable : 4514)     // unreferenced inline function has been removed
+#endif