2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
22 //need to rewrite this
\r
24 #include "util_str.h"
\r
31 #pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
\r
32 #pragma warning(disable : 4710) // function 'blah' not inlined
\r
35 static const int STR_ALLOC_GRAN = 20;
\r
37 // screwy but intentional
\r
38 #ifdef __APPLE_BUG__
\r
39 char *idStr::__tolower
\r
41 char *idStr::tolower
\r
53 *s = ::tolower( *s );
\r
60 // screwy but intentional
\r
61 #ifdef __APPLE_BUG__
\r
62 char *idStr::__toupper
\r
64 char *idStr::toupper
\r
76 *s = ::toupper( *s );
\r
101 // idStrings are equal until end point
\r
107 if ( c1 >= 'a' && c1 <= 'z' )
\r
109 c1 -= ( 'a' - 'A' );
\r
112 if ( c2 >= 'a' && c2 <= 'z' )
\r
114 c2 -= ( 'a' - 'A' );
\r
119 // strings less than
\r
122 else if ( c1 > c2 )
\r
124 // strings greater than
\r
131 // strings are equal
\r
152 if ( c1 >= 'a' && c1 <= 'z' )
\r
154 c1 -= ( 'a' - 'A' );
\r
157 if ( c2 >= 'a' && c2 <= 'z' )
\r
159 c2 -= ( 'a' - 'A' );
\r
164 // strings less than
\r
167 else if ( c1 > c2 )
\r
169 // strings greater than
\r
176 // strings are equal
\r
198 // strings are equal until end point
\r
204 // strings less than
\r
207 else if ( c1 > c2 )
\r
209 // strings greater than
\r
215 // strings are equal
\r
236 // strings less than
\r
239 else if ( c1 > c2 )
\r
241 // strings greater than
\r
247 // strings are equal
\r
255 Checks a string to see if it contains only numerical values.
\r
258 bool idStr::isNumeric
\r
274 len = strlen( str );
\r
275 for( i = 0; i < len; i++ )
\r
277 if ( !isdigit( str[ i ] ) )
\r
279 if ( ( str[ i ] == '.' ) && !dot )
\r
302 sprintf( text, "%f", b );
\r
303 result.append( text );
\r
319 sprintf( text, "%d", b );
\r
320 result.append( text );
\r
336 sprintf( text, "%u", b );
\r
337 result.append( text );
\r
342 idStr& idStr::operator+=
\r
350 sprintf( text, "%f", a );
\r
356 idStr& idStr::operator+=
\r
364 sprintf( text, "%d", a );
\r
370 idStr& idStr::operator+=
\r
378 sprintf( text, "%u", a );
\r
384 void idStr::CapLength
\r
392 if ( length() <= newlen )
\r
395 EnsureDataWritable ();
\r
397 m_data->data[newlen] = 0;
\r
398 m_data->len = newlen;
\r
401 void idStr::EnsureDataWritable
\r
411 if ( !m_data->refcount )
\r
417 m_data = new strdata;
\r
419 EnsureAlloced ( len + 1, false );
\r
420 strncpy ( m_data->data, olddata->data, len+1 );
\r
423 olddata->DelRef ();
\r
426 void idStr::EnsureAlloced (int amount, bool keepold) {
\r
429 m_data = new strdata();
\r
432 // Now, let's make sure it's writable
\r
433 EnsureDataWritable ();
\r
436 bool wasalloced = ( m_data->alloced != 0 );
\r
438 if ( amount < m_data->alloced ) {
\r
443 if ( amount == 1 ) {
\r
444 m_data->alloced = 1;
\r
447 mod = amount % STR_ALLOC_GRAN;
\r
451 newsize = amount + STR_ALLOC_GRAN - mod;
\r
453 m_data->alloced = newsize;
\r
456 newbuffer = new char[m_data->alloced];
\r
457 if ( wasalloced && keepold ) {
\r
458 strcpy ( newbuffer, m_data->data );
\r
461 if ( m_data->data ) {
\r
462 delete [] m_data->data;
\r
464 m_data->data = newbuffer;
\r
467 void idStr::BackSlashesToSlashes
\r
475 EnsureDataWritable ();
\r
477 for ( i=0; i < m_data->len; i++ )
\r
479 if ( m_data->data[i] == '\\' )
\r
480 m_data->data[i] = '/';
\r
484 void idStr::snprintf
\r
493 char buffer[0x10000];
\r
497 va_start (argptr,fmt);
\r
498 len = vsprintf (buffer,fmt,argptr);
\r
501 assert ( len < size );
\r
503 strncpy (dst, buffer, size-1);
\r
507 #pragma warning(disable : 4189) // local variable is initialized but not referenced
\r
514 This is a fairly rigorous test of the idStr class's functionality.
\r
515 Because of the fairly global and subtle ramifications of a bug occuring
\r
516 in this class, it should be run after any changes to the class.
\r
517 Add more tests as functionality is changed. Tests should include
\r
518 any possible bounds violation and NULL data tests.
\r
521 void TestStringClass
\r
527 char ch; // ch == ?
\r
528 idStr *t; // t == ?
\r
529 idStr a; // a.len == 0, a.data == "\0"
\r
530 idStr b; // b.len == 0, b.data == "\0"
\r
531 idStr c( "test" ); // c.len == 4, c.data == "test\0"
\r
532 idStr d( c ); // d.len == 4, d.data == "test\0"
\r
533 idStr e( reinterpret_cast<const char *>(NULL) );
\r
534 // e.len == 0, e.data == "\0" ASSERT!
\r
537 i = a.length(); // i == 0
\r
538 i = c.length(); // i == 4
\r
540 const char *s1 = a.c_str(); // s1 == "\0"
\r
541 const char *s2 = c.c_str(); // s2 == "test\0"
\r
543 t = new idStr(); // t->len == 0, t->data == "\0"
\r
544 delete t; // t == ?
\r
546 b = "test"; // b.len == 4, b.data == "test\0"
\r
547 t = new idStr( "test" ); // t->len == 4, t->data == "test\0"
\r
548 delete t; // t == ?
\r
550 a = c; // a.len == 4, a.data == "test\0"
\r
552 a = NULL; // a.len == 0, a.data == "\0" ASSERT!
\r
553 a = c + d; // a.len == 8, a.data == "testtest\0"
\r
554 a = c + "wow"; // a.len == 7, a.data == "testwow\0"
\r
555 a = c + reinterpret_cast<const char *>(NULL);
\r
556 // a.len == 4, a.data == "test\0" ASSERT!
\r
557 a = "this" + d; // a.len == 8, a.data == "thistest\0"
\r
558 a = reinterpret_cast<const char *>(NULL) + d;
\r
559 // a.len == 4, a.data == "test\0" ASSERT!
\r
560 a += c; // a.len == 8, a.data == "testtest\0"
\r
561 a += "wow"; // a.len == 11, a.data == "testtestwow\0"
\r
562 a += reinterpret_cast<const char *>(NULL);
\r
563 // a.len == 11, a.data == "testtestwow\0" ASSERT!
\r
565 a = "test"; // a.len == 4, a.data == "test\0"
\r
566 ch = a[ 0 ]; // ch == 't'
\r
567 ch = a[ -1 ]; // ch == 0 ASSERT!
\r
568 ch = a[ 1000 ]; // ch == 0 ASSERT!
\r
569 ch = a[ 0 ]; // ch == 't'
\r
570 ch = a[ 1 ]; // ch == 'e'
\r
571 ch = a[ 2 ]; // ch == 's'
\r
572 ch = a[ 3 ]; // ch == 't'
\r
573 ch = a[ 4 ]; // ch == '\0' ASSERT!
\r
574 ch = a[ 5 ]; // ch == '\0' ASSERT!
\r
576 a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0"
\r
577 a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT!
\r
578 a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0"
\r
579 a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0"
\r
580 a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0"
\r
581 a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0"
\r
582 a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT!
\r
583 a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT!
\r
584 a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT!
\r
586 a = "test"; // a.len == 4, a.data == "test\0"
\r
587 b = "no"; // b.len == 2, b.data == "no\0"
\r
589 i = ( a == b ); // i == 0
\r
590 i = ( a == c ); // i == 1
\r
592 i = ( a == "blow" ); // i == 0
\r
593 i = ( a == "test" ); // i == 1
\r
594 i = ( a == NULL ); // i == 0 ASSERT!
\r
596 i = ( "test" == b ); // i == 0
\r
597 i = ( "test" == a ); // i == 1
\r
598 i = ( NULL == a ); // i == 0 ASSERT!
\r
600 i = ( a != b ); // i == 1
\r
601 i = ( a != c ); // i == 0
\r
603 i = ( a != "blow" ); // i == 1
\r
604 i = ( a != "test" ); // i == 0
\r
605 i = ( a != NULL ); // i == 1 ASSERT!
\r
607 i = ( "test" != b ); // i == 1
\r
608 i = ( "test" != a ); // i == 0
\r
609 i = ( NULL != a ); // i == 1 ASSERT!
\r
611 a = "test"; // a.data == "test"
\r
612 b = a; // b.data == "test"
\r
614 a = "not"; // a.data == "not", b.data == "test"
\r
616 a = b; // a.data == b.data == "test"
\r
618 a += b; // a.data == "testtest", b.data = "test"
\r
622 a[1] = '1'; // a.data = "t1st", b.data = "test"
\r
626 #pragma warning(default : 4189) // local variable is initialized but not referenced
\r
627 #pragma warning(disable : 4514) // unreferenced inline function has been removed
\r