-/*\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-2007 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>
+
+#ifdef _WIN32
+#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);
+ }
+
+#ifdef _WIN32
+#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 == ?
+ 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( reinterpret_cast<const char *>(NULL) );
+ // e.len == 0, e.data == "\0" ASSERT!
+ int i; // i == ?
+
+ i = a.length(); // i == 0
+ i = c.length(); // i == 4
+
+ const char *s1 = a.c_str(); // s1 == "\0"
+ const char *s2 = c.c_str(); // s2 == "test\0"
+
+ 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 + reinterpret_cast<const char *>(NULL);
+ // a.len == 4, a.data == "test\0" ASSERT!
+ a = "this" + d; // a.len == 8, a.data == "thistest\0"
+ a = reinterpret_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 += reinterpret_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"
+ }
+
+#ifdef _WIN32
+#pragma warning(default : 4189) // local variable is initialized but not referenced
+#pragma warning(disable : 4514) // unreferenced inline function has been removed
+#endif