Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

util_str.h (13906B)


      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 #ifndef __UTIL_STR_H__
     25 #define __UTIL_STR_H__
     26 
     27 #include <assert.h>
     28 #include <string.h>
     29 #include <stdio.h>
     30 
     31 #ifdef _WIN32
     32 #pragma warning(disable : 4710)     // function 'blah' not inlined
     33 #endif
     34 
     35 void TestStringClass ();
     36 
     37 class strdata
     38    {
     39    public:
     40       strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {}
     41       ~strdata () 
     42          {
     43          if ( data )
     44             delete [] data;
     45          }
     46 
     47       void AddRef () { refcount++; }
     48       bool DelRef () // True if killed
     49          {
     50          refcount--;
     51          if ( refcount < 0 )
     52             {
     53             delete this;
     54             return true;
     55             }
     56          
     57          return false;
     58          }
     59 
     60       int len;
     61       int refcount;
     62       char *data;
     63       int alloced;
     64    };
     65 
     66 class idStr {
     67 protected:
     68 	strdata	*m_data;
     69 	void EnsureAlloced ( int, bool keepold = true );
     70 	void EnsureDataWritable ();
     71 
     72 public:
     73 	~idStr();
     74 	idStr();
     75 	idStr( const char *text );
     76 	idStr( const idStr& string );
     77 	idStr( const idStr string, int start, int end );
     78 	idStr( const char ch );
     79 	idStr( const int num );
     80 	idStr( const float num );
     81 	idStr( const unsigned num );
     82 	int	length( void ) const;
     83 	int	allocated( void ) const;
     84 	const char * c_str( void ) const;
     85 
     86 	void		append( const char *text );
     87 	void		append( const idStr& text );
     88 	char		operator[]( int index ) const;
     89 	char&		operator[]( int index );
     90 
     91 	void		operator=( const idStr& text );
     92 	void		operator=( const char *text );
     93 
     94 	friend	idStr		operator+( const idStr& a, const idStr& b );
     95 	friend	idStr		operator+( const idStr& a, const char *b );
     96 	friend	idStr		operator+( const char *a, const idStr& b );
     97 
     98     friend	idStr		operator+( const idStr& a, const float b );
     99     friend	idStr		operator+( const idStr& a, const int b );
    100     friend	idStr		operator+( const idStr& a, const unsigned b );
    101     friend	idStr		operator+( const idStr& a, const bool b );
    102     friend	idStr		operator+( const idStr& a, const char b );
    103 
    104 	idStr&		operator+=( const idStr& a );
    105 	idStr&		operator+=( const char *a );
    106 	idStr&		operator+=( const float a );
    107 	idStr&		operator+=( const char a );
    108 	idStr&		operator+=( const int a );
    109 	idStr&		operator+=( const unsigned a );
    110 	idStr&		operator+=( const bool a );
    111 
    112 	friend	bool		operator==(	const idStr& a, const idStr& b );
    113 	friend	bool		operator==(	const idStr& a, const char *b );
    114 	friend	bool		operator==(	const char *a, const idStr& b );
    115 
    116 	friend	bool		operator!=(	const idStr& a, const idStr& b );
    117 	friend	bool		operator!=(	const idStr& a, const char *b );
    118 	friend	bool		operator!=(	const char *a, const idStr& b );
    119 
    120 	operator const char * () const;
    121 	operator const char * ();
    122 
    123     int      icmpn( const char *text, int n ) const;
    124 	int      icmpn( const idStr& text, int n ) const;
    125 	int      icmp( const char *text ) const;
    126 	int      icmp( const idStr& text ) const;
    127 	int      cmpn( const char *text, int n ) const;
    128 	int      cmpn( const idStr& text, int n ) const;
    129 	int      cmp( const char *text ) const;
    130 	int      cmp( const idStr& text ) const;
    131 
    132 	void     tolower( void );
    133 	void     toupper( void );
    134 
    135 	static   char     *tolower( char *s1 );
    136 	static   char     *toupper( char *s1 );
    137 
    138 	static   int      icmpn( const char *s1, const char *s2, int n );
    139 	static   int      icmp( const char *s1, const char *s2 );
    140 	static   int      cmpn( const char *s1, const char *s2, int n );
    141 	static   int      cmp( const char *s1, const char *s2 );
    142 
    143 	static   void     snprintf ( char *dst, int size, const char *fmt, ... );
    144 
    145 	static   bool	   isNumeric( const char *str );
    146     bool    isNumeric( void ) const;
    147 
    148 	void     CapLength ( int );
    149 
    150 	void     BackSlashesToSlashes ();
    151 
    152 };
    153 
    154 inline idStr::~idStr()
    155 	{
    156    if ( m_data )
    157       {
    158       m_data->DelRef ();
    159       m_data = NULL;
    160       }
    161 	}
    162 
    163 inline idStr::idStr() : m_data ( NULL )
    164 	{
    165    EnsureAlloced ( 1 );
    166 	m_data->data[ 0 ] = 0;
    167 	}
    168 
    169 inline idStr::idStr
    170 	(
    171 	const char *text
    172    ) : m_data ( NULL )
    173 
    174 	{
    175    int len;
    176 
    177 	assert( text );
    178 
    179 	if ( text )
    180 		{
    181       len = strlen( text );
    182 		EnsureAlloced ( len + 1 );
    183 		strcpy( m_data->data, text );
    184       m_data->len = len;
    185 		}
    186 	else
    187 		{
    188       EnsureAlloced ( 1 );
    189 		m_data->data[ 0 ] = 0;
    190 		m_data->len = 0;
    191 		}
    192 	}
    193 
    194 inline idStr::idStr
    195 	(
    196 	const idStr& text
    197    ) : m_data ( NULL )
    198 
    199 	{
    200    m_data = text.m_data;
    201    m_data->AddRef ();
    202    }
    203 
    204 inline idStr::idStr
    205 	(
    206 	const idStr text, 
    207 	int start,
    208 	int end
    209    ) : m_data ( NULL )
    210 
    211 	{
    212 	int i;
    213    int len;
    214 
    215 	if ( end > text.length() )
    216 		{
    217 		end = text.length();
    218 		}
    219 
    220 	if ( start > text.length() )
    221 		{
    222 		start = text.length();
    223 		}
    224 
    225 	len = end - start;
    226 	if ( len < 0 )
    227 		{
    228 		len = 0;
    229 		}
    230 
    231    EnsureAlloced ( len + 1 );
    232 
    233 	for( i = 0; i < len; i++ )
    234 		{
    235 		m_data->data[ i ] = text[ start + i ];
    236 		}
    237 
    238 	m_data->data[ len ] = 0;
    239    m_data->len = len;
    240 	}
    241 
    242 inline idStr::idStr
    243    (
    244    const char ch
    245    ) : m_data ( NULL )
    246 
    247    {
    248    EnsureAlloced ( 2 );
    249 
    250    m_data->data[ 0 ] = ch;
    251    m_data->data[ 1 ] = 0;
    252    m_data->len = 1;
    253    }
    254 
    255 inline idStr::idStr
    256    (
    257    const float num
    258    ) : m_data ( NULL )
    259 
    260    {
    261    char text[ 32 ];
    262    int len;
    263 
    264    sprintf( text, "%.3f", num );
    265    len = strlen( text );
    266    EnsureAlloced( len + 1 );
    267    strcpy( m_data->data, text );
    268    m_data->len = len;
    269    }
    270 
    271 inline idStr::idStr
    272    (
    273    const int num
    274    ) : m_data ( NULL )
    275 
    276    {
    277    char text[ 32 ];
    278    int len;
    279 
    280    sprintf( text, "%d", num );
    281    len = strlen( text );
    282    EnsureAlloced( len + 1 );
    283    strcpy( m_data->data, text );
    284    m_data->len = len;
    285    }
    286 
    287 inline idStr::idStr
    288    (
    289    const unsigned num
    290    ) : m_data ( NULL )
    291 
    292    {
    293    char text[ 32 ];
    294    int len;
    295 
    296    sprintf( text, "%u", num );
    297    len = strlen( text );
    298    EnsureAlloced( len + 1 );
    299    strcpy( m_data->data, text );
    300    m_data->len = len;
    301    }
    302 
    303 inline int idStr::length( void ) const
    304 	{
    305    return ( m_data != NULL ) ? m_data->len : 0;
    306 	}
    307 
    308 inline int idStr::allocated( void ) const
    309 	{
    310    return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0;
    311 	}
    312 
    313 inline const char *idStr::c_str( void ) const
    314 	{
    315 	assert( m_data );
    316 
    317 	return m_data->data;
    318 	}
    319 
    320 inline void idStr::append
    321 	(
    322 	const char *text
    323 	)
    324 
    325 	{
    326    int len;
    327 
    328 	assert( text );
    329 
    330 	if ( text )
    331 		{
    332 		len = length() + strlen( text );
    333 		EnsureAlloced( len + 1 );
    334 
    335       strcat( m_data->data, text );
    336       m_data->len = len;
    337 		}
    338 	}
    339 
    340 inline void idStr::append
    341 	(
    342 	const idStr& text
    343 	)
    344 
    345 	{
    346    int len;
    347 
    348    len = length() + text.length();
    349    EnsureAlloced ( len + 1 );
    350 
    351    strcat ( m_data->data, text.c_str () );
    352    m_data->len = len;
    353 	}
    354 
    355 inline char idStr::operator[]( int index ) const
    356 	{
    357    assert ( m_data );
    358    
    359    if ( !m_data )
    360       return 0;
    361 
    362 	// don't include the '/0' in the test, because technically, it's out of bounds
    363 	assert( ( index >= 0 ) && ( index < m_data->len ) );
    364 
    365 	// In release mode, give them a null character
    366 	// don't include the '/0' in the test, because technically, it's out of bounds
    367 	if ( ( index < 0 ) || ( index >= m_data->len ) )
    368 		{
    369 		return 0;
    370 		}
    371 
    372 	return m_data->data[ index ];
    373 	}
    374 
    375 inline char& idStr::operator[]
    376 	(
    377 	int index
    378 	)
    379 
    380 	{
    381 	// Used for result for invalid indices
    382 	static char dummy = 0;
    383    assert ( m_data );
    384 
    385    // We don't know if they'll write to it or not
    386    // if it's not a const object
    387    EnsureDataWritable ();
    388 
    389    if ( !m_data )
    390       return dummy;
    391 
    392 	// don't include the '/0' in the test, because technically, it's out of bounds
    393 	assert( ( index >= 0 ) && ( index < m_data->len ) );
    394 
    395 	// In release mode, let them change a safe variable
    396 	// don't include the '/0' in the test, because technically, it's out of bounds
    397 	if ( ( index < 0 ) || ( index >= m_data->len ) )
    398 		{
    399 		return dummy;
    400 		}
    401 
    402 	return m_data->data[ index ];
    403 	}
    404 
    405 inline void idStr::operator=
    406 	(
    407 	const idStr& text
    408 	)
    409 
    410 	{
    411    // adding the reference before deleting our current reference prevents
    412    // us from deleting our string if we are copying from ourself
    413    text.m_data->AddRef();
    414    m_data->DelRef();
    415    m_data = text.m_data;
    416    }
    417 
    418 inline void idStr::operator=
    419 	(
    420 	const char *text
    421 	)
    422 
    423 	{
    424    int len;
    425 
    426 	assert( text );
    427 
    428 	if ( !text )
    429 		{
    430 		// safe behaviour if NULL
    431 		EnsureAlloced ( 1, false );
    432       m_data->data[0] = 0;
    433       m_data->len = 0;
    434       return;
    435 		}
    436 
    437    if ( !m_data )
    438       {
    439       len = strlen ( text );
    440       EnsureAlloced( len + 1, false );
    441       strcpy ( m_data->data, text );
    442       m_data->len = len;
    443       return;
    444       }
    445 
    446    if ( text == m_data->data )
    447       return; // Copying same thing.  Punt.
    448 
    449    // If we alias and I don't do this, I could corrupt other strings...  This 
    450    // will get called with EnsureAlloced anyway
    451    EnsureDataWritable ();
    452 
    453    // Now we need to check if we're aliasing..
    454    if ( text >= m_data->data && text <= m_data->data + m_data->len )
    455       {
    456       // Great, we're aliasing.  We're copying from inside ourselves.
    457       // This means that I don't have to ensure that anything is alloced,
    458       // though I'll assert just in case.
    459       int diff = text - m_data->data;
    460       int i;
    461 
    462       assert ( strlen ( text ) < (unsigned) m_data->len );
    463       
    464       for ( i = 0; text[i]; i++ )
    465          {
    466          m_data->data[i] = text[i];
    467          }
    468 
    469       m_data->data[i] = 0;
    470 
    471       m_data->len -= diff;
    472 
    473       return;
    474       }
    475 
    476 	len = strlen( text );
    477    EnsureAlloced ( len + 1, false );
    478 	strcpy( m_data->data, text );
    479    m_data->len = len;
    480 	}
    481 
    482 inline idStr operator+
    483 	(
    484 	const idStr& a,
    485 	const idStr& b
    486 	)
    487 
    488 	{
    489 	idStr result( a );
    490 
    491 	result.append( b );
    492 
    493 	return result;
    494 	}
    495 
    496 inline idStr operator+
    497 	(
    498 	const idStr& a,
    499 	const char *b
    500 	)
    501 
    502 	{
    503 	idStr result( a );
    504 
    505 	result.append( b );
    506 
    507 	return result;
    508 	}
    509 
    510 inline idStr operator+
    511 	(
    512 	const char *a,
    513 	const idStr& b
    514 	)
    515 
    516 	{
    517 	idStr result( a );
    518 
    519 	result.append( b );
    520 
    521 	return result;
    522 	}
    523 
    524 inline idStr operator+
    525    (
    526    const idStr& a,
    527    const bool b
    528    )
    529 
    530    {
    531 	idStr result( a );
    532 
    533    result.append( b ? "true" : "false" );
    534 
    535 	return result;
    536    }
    537 
    538 inline idStr operator+
    539 	(
    540    const idStr& a,
    541 	const char b
    542 	)
    543 
    544 	{
    545    char text[ 2 ];
    546 
    547    text[ 0 ] = b;
    548    text[ 1 ] = 0;
    549 
    550 	return a + text;
    551 	}
    552 
    553 inline idStr& idStr::operator+=
    554 	(
    555 	const idStr& a
    556 	)
    557 
    558 	{
    559 	append( a );
    560 	return *this;
    561 	}
    562 
    563 inline idStr& idStr::operator+=
    564 	(
    565 	const char *a
    566 	)
    567 
    568 	{
    569 	append( a );
    570 	return *this;
    571 	}
    572 
    573 inline idStr& idStr::operator+=
    574 	(
    575 	const char a
    576 	)
    577 
    578 	{
    579    char text[ 2 ];
    580 
    581    text[ 0 ] = a;
    582    text[ 1 ] = 0;
    583 	append( text );
    584 
    585    return *this;
    586 	}
    587 
    588 inline idStr& idStr::operator+=
    589 	(
    590 	const bool a
    591 	)
    592 
    593 	{
    594    append( a ? "true" : "false" );
    595 	return *this;
    596 	}
    597 
    598 inline bool operator==
    599 	(
    600 	const idStr& a,
    601 	const idStr& b
    602 	)
    603 
    604 	{
    605 	return ( !strcmp( a.c_str(), b.c_str() ) );
    606 	}
    607 
    608 inline bool operator==
    609 	(
    610 	const idStr& a,
    611 	const char *b
    612 	)
    613 
    614 	{
    615 	assert( b );
    616 	if ( !b )
    617 		{
    618 		return false;
    619 		}
    620 	return ( !strcmp( a.c_str(), b ) );
    621 	}
    622 
    623 inline bool operator==
    624 	(
    625 	const char *a,
    626 	const idStr& b
    627 	)
    628 
    629 	{
    630 	assert( a );
    631 	if ( !a )
    632 		{
    633 		return false;
    634 		}
    635 	return ( !strcmp( a, b.c_str() ) );
    636 	}
    637 
    638 inline bool operator!=
    639 	(
    640 	const idStr& a,
    641 	const idStr& b
    642 	)
    643 
    644 	{
    645 	return !( a == b );
    646 	}
    647 
    648 inline bool operator!=
    649 	(
    650 	const idStr& a,
    651 	const char *b
    652 	)
    653 
    654 	{
    655 	return !( a == b );
    656 	}
    657 
    658 inline bool operator!=
    659 	(
    660 	const char *a,
    661 	const idStr& b
    662 	)
    663 
    664 	{
    665 	return !( a == b );
    666 	}
    667 
    668 inline int idStr::icmpn
    669    (
    670    const char *text, 
    671    int n
    672    ) const
    673 
    674    {
    675 	assert( m_data );
    676 	assert( text );
    677 
    678    return idStr::icmpn( m_data->data, text, n );
    679    }
    680 
    681 inline int idStr::icmpn
    682    (
    683    const idStr& text, 
    684    int n
    685    ) const
    686 
    687    {
    688 	assert( m_data );
    689 	assert( text.m_data );
    690 
    691    return idStr::icmpn( m_data->data, text.m_data->data, n );
    692    }
    693 
    694 inline int idStr::icmp
    695    (
    696    const char *text
    697    ) const
    698 
    699    {
    700 	assert( m_data );
    701 	assert( text );
    702 
    703    return idStr::icmp( m_data->data, text );
    704    }
    705 
    706 inline int idStr::icmp
    707    (
    708    const idStr& text
    709    ) const
    710 
    711    {
    712 	assert( c_str () );
    713 	assert( text.c_str () );
    714 
    715    return idStr::icmp( c_str () , text.c_str () );
    716    }
    717 
    718 inline int idStr::cmp
    719    (
    720    const char *text
    721    ) const
    722 
    723    {
    724 	assert( m_data );
    725 	assert( text );
    726 
    727    return idStr::cmp( m_data->data, text );
    728    }
    729 
    730 inline int idStr::cmp
    731    (
    732    const idStr& text
    733    ) const
    734 
    735    {
    736 	assert( c_str () );
    737 	assert( text.c_str () );
    738 
    739    return idStr::cmp( c_str () , text.c_str () );
    740    }
    741 
    742 inline int idStr::cmpn
    743    (
    744    const char *text, 
    745    int n
    746    ) const
    747 
    748    {
    749 	assert( c_str () );
    750 	assert( text );
    751 
    752    return idStr::cmpn( c_str () , text, n );
    753    }
    754 
    755 inline int idStr::cmpn
    756    (
    757    const idStr& text, 
    758    int n
    759    ) const
    760 
    761    {
    762 	assert( c_str () );
    763 	assert( text.c_str ()  );
    764 
    765    return idStr::cmpn( c_str () , text.c_str () , n );
    766    }
    767 
    768 inline void idStr::tolower
    769    (
    770    void
    771    )
    772 
    773    {
    774    assert( m_data );
    775 
    776    EnsureDataWritable ();
    777 
    778    idStr::tolower( m_data->data );
    779    }
    780 
    781 inline void idStr::toupper
    782    (
    783    void
    784    )
    785 
    786    {
    787    assert( m_data );
    788 
    789    EnsureDataWritable ();
    790 
    791    idStr::toupper( m_data->data );
    792    }
    793 
    794 inline bool idStr::isNumeric
    795    (
    796    void
    797    ) const
    798 
    799    {
    800    assert( m_data );
    801    return idStr::isNumeric( m_data->data );
    802    }
    803 
    804 inline idStr::operator const char *() {
    805 	return c_str();
    806 }
    807 
    808 inline idStr::operator const char *
    809    (
    810    void
    811    ) const
    812 
    813    {
    814    return c_str ();
    815    }
    816 
    817 #endif