Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

util_str.cpp (11486B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //need to rewrite this
     23 
     24 #include "util_str.h"
     25 #include <stdlib.h>
     26 #include <ctype.h>
     27 #include <stdio.h>
     28 #include <stdarg.h>
     29 
     30 #ifdef _WIN32
     31 #pragma warning(disable : 4244)     // 'conversion' conversion from 'type1' to 'type2', possible loss of data
     32 #pragma warning(disable : 4710)     // function 'blah' not inlined
     33 #endif
     34 
     35 static const int STR_ALLOC_GRAN = 20;
     36 
     37 char *idStr::toLower
     38    (
     39    char *s1
     40    )
     41    
     42    {
     43    char *s;
     44 
     45    s = s1;
     46 	while( *s )
     47       {
     48       *s = ::tolower( *s );
     49 		s++;
     50 	   }
     51    
     52    return s1;
     53    }
     54 
     55 char *idStr::toUpper
     56    (
     57    char *s1
     58    )
     59    
     60    {
     61    char *s;
     62 
     63    s = s1;
     64 	while( *s )
     65       {
     66       *s = ::toupper( *s );
     67 		s++;
     68 	   }
     69    
     70    return s1;
     71    }
     72 
     73 
     74 int idStr::icmpn
     75    (
     76    const char *s1, 
     77    const char *s2, 
     78    int n
     79    )
     80    
     81    {
     82 	int c1;
     83    int c2;
     84 	
     85 	do 
     86       {
     87 		c1 = *s1++;
     88 		c2 = *s2++;
     89 
     90 		if ( !n-- )
     91          {
     92          // idStrings are equal until end point
     93 			return 0;
     94 		   }
     95 		
     96 		if ( c1 != c2 )
     97          {
     98 			if ( c1 >= 'a' && c1 <= 'z' )
     99             {
    100 				c1 -= ( 'a' - 'A' );
    101 			   }
    102 
    103 			if ( c2 >= 'a' && c2 <= 'z' )
    104             {
    105 				c2 -= ( 'a' - 'A' );
    106 			   }
    107 
    108 			if ( c1 < c2 )
    109             {
    110             // strings less than
    111 				return -1;
    112 			   }
    113          else if ( c1 > c2 ) 
    114             {
    115             // strings greater than
    116             return 1;
    117             }
    118 		   }
    119 	   } 
    120    while( c1 );
    121 	
    122    // strings are equal
    123 	return 0;
    124    }
    125 
    126 int idStr::icmp
    127    (
    128    const char *s1,
    129    const char *s2
    130    )
    131    
    132    {
    133 	int c1;
    134    int c2;
    135 	
    136 	do 
    137       {
    138 		c1 = *s1++;
    139 		c2 = *s2++;
    140 
    141 		if ( c1 != c2 )
    142          {
    143 			if ( c1 >= 'a' && c1 <= 'z' )
    144             {
    145 				c1 -= ( 'a' - 'A' );
    146 			   }
    147 
    148 			if ( c2 >= 'a' && c2 <= 'z' )
    149             {
    150 				c2 -= ( 'a' - 'A' );
    151 			   }
    152 
    153 			if ( c1 < c2 )
    154             {
    155             // strings less than
    156 				return -1;
    157 			   }
    158          else if ( c1 > c2 ) 
    159             {
    160             // strings greater than
    161             return 1;
    162             }
    163 		   }
    164 	   } 
    165    while( c1 );
    166 	
    167    // strings are equal
    168 	return 0;
    169    }
    170 
    171 int idStr::cmpn
    172    (
    173    const char *s1, 
    174    const char *s2, 
    175    int n
    176    )
    177    
    178    {
    179 	int c1;
    180    int c2;
    181 	
    182 	do 
    183       {
    184 		c1 = *s1++;
    185 		c2 = *s2++;
    186 
    187 		if ( !n-- )
    188          {
    189          // strings are equal until end point
    190 			return 0;
    191 		   }
    192 		
    193 		if ( c1 < c2 )
    194          {
    195          // strings less than
    196 			return -1;
    197 			}
    198       else if ( c1 > c2 ) 
    199          {
    200          // strings greater than
    201          return 1;
    202          }
    203 	   } 
    204    while( c1 );
    205 	
    206    // strings are equal
    207 	return 0;
    208    }
    209 
    210 int idStr::cmp
    211    (
    212    const char *s1, 
    213    const char *s2
    214    )
    215    
    216    {
    217 	int c1;
    218    int c2;
    219 	
    220 	do 
    221       {
    222 		c1 = *s1++;
    223 		c2 = *s2++;
    224 
    225 		if ( c1 < c2 )
    226          {
    227          // strings less than
    228 			return -1;
    229 			}
    230       else if ( c1 > c2 ) 
    231          {
    232          // strings greater than
    233          return 1;
    234          }
    235 	   } 
    236    while( c1 );
    237 	
    238    // strings are equal
    239 	return 0;
    240    }
    241 
    242 /*
    243 ============
    244 IsNumeric
    245 
    246 Checks a string to see if it contains only numerical values.
    247 ============
    248 */
    249 bool idStr::isNumeric
    250    (
    251    const char *str
    252    )
    253 
    254    {
    255 	int len;
    256 	int i;
    257 	bool dot;
    258 
    259 	if ( *str == '-' )
    260 		{
    261 		str++;
    262 		}
    263 
    264 	dot = false;
    265 	len = strlen( str );
    266 	for( i = 0; i < len; i++ )
    267 		{
    268 		if ( !isdigit( str[ i ] ) )
    269 			{
    270 			if ( ( str[ i ] == '.' ) && !dot )
    271 				{
    272 				dot = true;
    273 				continue;
    274 				}
    275 			return false;
    276 			}
    277 		}
    278 
    279 	return true;
    280    }
    281 
    282 idStr operator+
    283    (
    284    const idStr& a,
    285    const float b
    286    )
    287 
    288    {
    289    char text[ 20 ];
    290 
    291 	idStr result( a );
    292 
    293    sprintf( text, "%f", b );
    294 	result.append( text );
    295 
    296 	return result;
    297    }
    298 
    299 idStr operator+
    300    (
    301    const idStr& a,
    302    const int b
    303    )
    304 
    305    {
    306    char text[ 20 ];
    307 
    308 	idStr result( a );
    309 
    310    sprintf( text, "%d", b );
    311 	result.append( text );
    312 
    313 	return result;
    314    }
    315 
    316 idStr operator+
    317    (
    318    const idStr& a,
    319    const unsigned b
    320    )
    321 
    322    {
    323    char text[ 20 ];
    324 
    325 	idStr result( a );
    326 
    327    sprintf( text, "%u", b );
    328 	result.append( text );
    329 
    330 	return result;
    331    }
    332 
    333 idStr& idStr::operator+=
    334 	(
    335 	const float a
    336 	)
    337 
    338 	{
    339    char text[ 20 ];
    340 
    341    sprintf( text, "%f", a );
    342 	append( text );
    343 
    344    return *this;
    345 	}
    346 
    347 idStr& idStr::operator+=
    348 	(
    349 	const int a
    350 	)
    351 
    352 	{
    353    char text[ 20 ];
    354 
    355    sprintf( text, "%d", a );
    356 	append( text );
    357 
    358    return *this;
    359 	}
    360 
    361 idStr& idStr::operator+=
    362 	(
    363 	const unsigned a
    364 	)
    365 
    366 	{
    367    char text[ 20 ];
    368 
    369    sprintf( text, "%u", a );
    370 	append( text );
    371 
    372    return *this;
    373 	}
    374 
    375 void idStr::CapLength 
    376    (
    377    int newlen 
    378    )
    379 
    380    {
    381    assert ( m_data );
    382    
    383    if ( length() <= newlen )
    384       return;
    385 
    386    EnsureDataWritable ();
    387 
    388    m_data->data[newlen] = 0;
    389    m_data->len = newlen;
    390    }
    391 
    392 void idStr::EnsureDataWritable 
    393    (
    394    void
    395    )
    396 
    397    {
    398    assert ( m_data );
    399    strdata *olddata;
    400    int len;
    401 
    402    if ( !m_data->refcount )
    403       return;
    404 
    405    olddata = m_data;
    406    len = length();
    407 
    408    m_data = new strdata;
    409 
    410    EnsureAlloced ( len + 1, false );
    411    strncpy ( m_data->data, olddata->data, len+1 );
    412    m_data->len = len;
    413 
    414    olddata->DelRef ();
    415    }
    416 
    417 void idStr::EnsureAlloced (int amount, bool keepold) {
    418 
    419 	if ( !m_data ) {
    420       m_data = new strdata();
    421 	}
    422    
    423 	// Now, let's make sure it's writable
    424 	EnsureDataWritable ();
    425 
    426 	char *newbuffer;
    427 	bool wasalloced = ( m_data->alloced != 0 );
    428 
    429 	if ( amount < m_data->alloced ) {
    430 		return;
    431 	}
    432 
    433 	assert ( amount );
    434 	if ( amount == 1 ) {
    435 		m_data->alloced = 1;
    436 	} else {
    437 		int newsize, mod;
    438 		mod = amount % STR_ALLOC_GRAN;
    439 		if ( !mod ) {
    440 			newsize = amount;
    441 		} else {
    442          newsize = amount + STR_ALLOC_GRAN - mod;
    443 		}
    444 		m_data->alloced = newsize;
    445 	}
    446 
    447 	newbuffer = new char[m_data->alloced];
    448 	if ( wasalloced && keepold ) {
    449 		strcpy ( newbuffer, m_data->data );
    450 	}
    451 
    452 	if ( m_data->data ) {
    453 		delete [] m_data->data;
    454     }
    455 	m_data->data = newbuffer;
    456 }
    457 
    458 void idStr::BackSlashesToSlashes
    459    (
    460    void
    461    )
    462 
    463    {
    464    int i;
    465 
    466    EnsureDataWritable ();
    467 
    468    for ( i=0; i < m_data->len; i++ )
    469       {
    470       if ( m_data->data[i] == '\\' )
    471          m_data->data[i] = '/';
    472       }
    473    }
    474 
    475 void idStr::snprintf 
    476    (
    477    char *dst,
    478    int size,
    479    const char *fmt, 
    480    ...
    481    )
    482 
    483    {
    484    char buffer[0x10000];
    485 	int		len;
    486 	va_list		argptr;
    487 
    488 	va_start (argptr,fmt);
    489 	len = vsprintf (buffer,fmt,argptr);
    490 	va_end (argptr);
    491 	
    492    assert ( len < size );
    493 
    494    strncpy (dst, buffer, size-1);
    495    }
    496 
    497 #ifdef _WIN32
    498 #pragma warning(disable : 4189)		// local variable is initialized but not referenced
    499 #endif
    500 
    501 /*
    502 =================
    503 TestStringClass
    504 
    505 This is a fairly rigorous test of the idStr class's functionality.
    506 Because of the fairly global and subtle ramifications of a bug occuring
    507 in this class, it should be run after any changes to the class.
    508 Add more tests as functionality is changed.  Tests should include
    509 any possible bounds violation and NULL data tests.
    510 =================
    511 */
    512 void TestStringClass
    513 	(
    514 	void 
    515 	)
    516 
    517 	{
    518 	char	ch;							// ch == ?
    519 	idStr	*t;							// t == ?
    520 	idStr	a;								// a.len == 0, a.data == "\0"
    521 	idStr	b;								// b.len == 0, b.data == "\0"
    522 	idStr	c( "test" );				// c.len == 4, c.data == "test\0"
    523 	idStr	d( c );						// d.len == 4, d.data == "test\0"
    524 	idStr	e( reinterpret_cast<const char *>(NULL) );					
    525                                  // e.len == 0, e.data == "\0"					ASSERT!
    526 	int	i;								// i == ?
    527 
    528 	i = a.length();					// i == 0
    529 	i = c.length();					// i == 4
    530 
    531     // TTimo: not used
    532 //	const char *s1 = a.c_str();	// s1 == "\0"
    533 //	const char *s2 = c.c_str();	// s2 == "test\0"
    534 
    535 	t = new idStr();						// t->len == 0, t->data == "\0"
    536 	delete t;							// t == ?
    537 
    538 	b = "test";							// b.len == 4, b.data == "test\0"
    539 	t = new idStr( "test" );			// t->len == 4, t->data == "test\0"
    540 	delete t;							// t == ?
    541 
    542 	a = c;								// a.len == 4, a.data == "test\0"
    543 //   a = "";
    544    a = NULL;							// a.len == 0, a.data == "\0"					ASSERT!
    545 	a = c + d;							// a.len == 8, a.data == "testtest\0"
    546 	a = c + "wow";						// a.len == 7, a.data == "testwow\0"
    547 	a = c + reinterpret_cast<const char *>(NULL);
    548                                  // a.len == 4, a.data == "test\0"			ASSERT!
    549 	a = "this" + d;					// a.len == 8, a.data == "thistest\0"
    550 	a = reinterpret_cast<const char *>(NULL) + d;
    551                                  // a.len == 4, a.data == "test\0"			ASSERT!
    552 	a += c;								// a.len == 8, a.data == "testtest\0"
    553 	a += "wow";							// a.len == 11, a.data == "testtestwow\0"
    554 	a += reinterpret_cast<const char *>(NULL);
    555                                  // a.len == 11, a.data == "testtestwow\0"	ASSERT!
    556 
    557 	a = "test";							// a.len == 4, a.data == "test\0"
    558 	ch = a[ 0 ];						// ch == 't'
    559 	ch = a[ -1 ];						// ch == 0											ASSERT!
    560 	ch = a[ 1000 ];					// ch == 0											ASSERT!
    561 	ch = a[ 0 ];						// ch == 't'
    562 	ch = a[ 1 ];						// ch == 'e'
    563 	ch = a[ 2 ];						// ch == 's'
    564 	ch = a[ 3 ];						// ch == 't'
    565 	ch = a[ 4 ];						// ch == '\0'										ASSERT!
    566 	ch = a[ 5 ];						// ch == '\0'										ASSERT!
    567 
    568 	a[ 1 ] = 'b';						// a.len == 4, a.data == "tbst\0"
    569 	a[ -1 ] = 'b';						// a.len == 4, a.data == "tbst\0"			ASSERT!
    570 	a[ 0 ] = '0';						// a.len == 4, a.data == "0bst\0"
    571 	a[ 1 ] = '1';						// a.len == 4, a.data == "01st\0"
    572 	a[ 2 ] = '2';						// a.len == 4, a.data == "012t\0"
    573 	a[ 3 ] = '3';						// a.len == 4, a.data == "0123\0"
    574 	a[ 4 ] = '4';						// a.len == 4, a.data == "0123\0"			ASSERT!
    575 	a[ 5 ] = '5';						// a.len == 4, a.data == "0123\0"			ASSERT!
    576 	a[ 7 ] = '7';						// a.len == 4, a.data == "0123\0"			ASSERT!
    577 
    578 	a = "test";							// a.len == 4, a.data == "test\0"
    579 	b = "no";							// b.len == 2, b.data == "no\0"
    580 
    581 	i = ( a == b );					// i == 0
    582 	i = ( a == c );					// i == 1
    583 
    584 	i = ( a == "blow" );				// i == 0
    585 	i = ( a == "test" );				// i == 1
    586 	i = ( a == NULL );				// i == 0											ASSERT!
    587 
    588 	i = ( "test" == b );				// i == 0
    589 	i = ( "test" == a );				// i == 1
    590 	i = ( NULL == a );				// i == 0											ASSERT!
    591 
    592 	i = ( a != b );					// i == 1
    593 	i = ( a != c );					// i == 0
    594 
    595 	i = ( a != "blow" );				// i == 1
    596 	i = ( a != "test" );				// i == 0
    597 	i = ( a != NULL );				// i == 1											ASSERT!
    598 
    599 	i = ( "test" != b );				// i == 1
    600 	i = ( "test" != a );				// i == 0
    601 	i = ( NULL != a );				// i == 1											ASSERT!
    602 
    603    a = "test";                   // a.data == "test"
    604    b = a;                        // b.data == "test"
    605 
    606    a = "not";                   // a.data == "not", b.data == "test"
    607 
    608    a = b;                        // a.data == b.data == "test"
    609 
    610    a += b;                       // a.data == "testtest", b.data = "test"
    611 
    612    a = b;
    613 
    614    a[1] = '1';                   // a.data = "t1st", b.data = "test"
    615 	}
    616 
    617 #ifdef _WIN32
    618 #pragma warning(default : 4189)		// local variable is initialized but not referenced
    619 #pragma warning(disable : 4514)     // unreferenced inline function has been removed
    620 #endif