/* 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 #ifndef __UTIL_STR_H__ #define __UTIL_STR_H__ #include #include #include #ifdef _WIN32 #pragma warning(disable : 4710) // function 'blah' not inlined #endif void TestStringClass (); class strdata { public: strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} ~strdata () { if ( data ) delete [] data; } void AddRef () { refcount++; } bool DelRef () // True if killed { refcount--; if ( refcount < 0 ) { delete this; return true; } return false; } int len; int refcount; char *data; int alloced; }; class idStr { protected: strdata *m_data; void EnsureAlloced ( int, bool keepold = true ); void EnsureDataWritable (); public: ~idStr(); idStr(); idStr( const char *text ); idStr( const idStr& string ); idStr( const idStr string, int start, int end ); idStr( const char ch ); idStr( const int num ); idStr( const float num ); idStr( const unsigned num ); int length( void ) const; int allocated( void ) const; const char * c_str( void ) const; void append( const char *text ); void append( const idStr& text ); char operator[]( int index ) const; char& operator[]( int index ); void operator=( const idStr& text ); void operator=( const char *text ); friend idStr operator+( const idStr& a, const idStr& b ); friend idStr operator+( const idStr& a, const char *b ); friend idStr operator+( const char *a, const idStr& b ); friend idStr operator+( const idStr& a, const float b ); friend idStr operator+( const idStr& a, const int b ); friend idStr operator+( const idStr& a, const unsigned b ); friend idStr operator+( const idStr& a, const bool b ); friend idStr operator+( const idStr& a, const char b ); idStr& operator+=( const idStr& a ); idStr& operator+=( const char *a ); idStr& operator+=( const float a ); idStr& operator+=( const char a ); idStr& operator+=( const int a ); idStr& operator+=( const unsigned a ); idStr& operator+=( const bool a ); friend bool operator==( const idStr& a, const idStr& b ); friend bool operator==( const idStr& a, const char *b ); friend bool operator==( const char *a, const idStr& b ); friend bool operator!=( const idStr& a, const idStr& b ); friend bool operator!=( const idStr& a, const char *b ); friend bool operator!=( const char *a, const idStr& b ); operator const char * () const; operator const char * (); int icmpn( const char *text, int n ) const; int icmpn( const idStr& text, int n ) const; int icmp( const char *text ) const; int icmp( const idStr& text ) const; int cmpn( const char *text, int n ) const; int cmpn( const idStr& text, int n ) const; int cmp( const char *text ) const; int cmp( const idStr& text ) const; void tolower( void ); void toupper( void ); static char *tolower( char *s1 ); static char *toupper( char *s1 ); static int icmpn( const char *s1, const char *s2, int n ); static int icmp( const char *s1, const char *s2 ); static int cmpn( const char *s1, const char *s2, int n ); static int cmp( const char *s1, const char *s2 ); static void snprintf ( char *dst, int size, const char *fmt, ... ); static bool isNumeric( const char *str ); bool isNumeric( void ) const; void CapLength ( int ); void BackSlashesToSlashes (); }; inline idStr::~idStr() { if ( m_data ) { m_data->DelRef (); m_data = NULL; } } inline idStr::idStr() : m_data ( NULL ) { EnsureAlloced ( 1 ); m_data->data[ 0 ] = 0; } inline idStr::idStr ( const char *text ) : m_data ( NULL ) { int len; assert( text ); if ( text ) { len = strlen( text ); EnsureAlloced ( len + 1 ); strcpy( m_data->data, text ); m_data->len = len; } else { EnsureAlloced ( 1 ); m_data->data[ 0 ] = 0; m_data->len = 0; } } inline idStr::idStr ( const idStr& text ) : m_data ( NULL ) { m_data = text.m_data; m_data->AddRef (); } inline idStr::idStr ( const idStr text, int start, int end ) : m_data ( NULL ) { int i; int len; if ( end > text.length() ) { end = text.length(); } if ( start > text.length() ) { start = text.length(); } len = end - start; if ( len < 0 ) { len = 0; } EnsureAlloced ( len + 1 ); for( i = 0; i < len; i++ ) { m_data->data[ i ] = text[ start + i ]; } m_data->data[ len ] = 0; m_data->len = len; } inline idStr::idStr ( const char ch ) : m_data ( NULL ) { EnsureAlloced ( 2 ); m_data->data[ 0 ] = ch; m_data->data[ 1 ] = 0; m_data->len = 1; } inline idStr::idStr ( const float num ) : m_data ( NULL ) { char text[ 32 ]; int len; sprintf( text, "%.3f", num ); len = strlen( text ); EnsureAlloced( len + 1 ); strcpy( m_data->data, text ); m_data->len = len; } inline idStr::idStr ( const int num ) : m_data ( NULL ) { char text[ 32 ]; int len; sprintf( text, "%d", num ); len = strlen( text ); EnsureAlloced( len + 1 ); strcpy( m_data->data, text ); m_data->len = len; } inline idStr::idStr ( const unsigned num ) : m_data ( NULL ) { char text[ 32 ]; int len; sprintf( text, "%u", num ); len = strlen( text ); EnsureAlloced( len + 1 ); strcpy( m_data->data, text ); m_data->len = len; } inline int idStr::length( void ) const { return ( m_data != NULL ) ? m_data->len : 0; } inline int idStr::allocated( void ) const { return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0; } inline const char *idStr::c_str( void ) const { assert( m_data ); return m_data->data; } inline void idStr::append ( const char *text ) { int len; assert( text ); if ( text ) { len = length() + strlen( text ); EnsureAlloced( len + 1 ); strcat( m_data->data, text ); m_data->len = len; } } inline void idStr::append ( const idStr& text ) { int len; len = length() + text.length(); EnsureAlloced ( len + 1 ); strcat ( m_data->data, text.c_str () ); m_data->len = len; } inline char idStr::operator[]( int index ) const { assert ( m_data ); if ( !m_data ) return 0; // don't include the '/0' in the test, because technically, it's out of bounds assert( ( index >= 0 ) && ( index < m_data->len ) ); // In release mode, give them a null character // don't include the '/0' in the test, because technically, it's out of bounds if ( ( index < 0 ) || ( index >= m_data->len ) ) { return 0; } return m_data->data[ index ]; } inline char& idStr::operator[] ( int index ) { // Used for result for invalid indices static char dummy = 0; assert ( m_data ); // We don't know if they'll write to it or not // if it's not a const object EnsureDataWritable (); if ( !m_data ) return dummy; // don't include the '/0' in the test, because technically, it's out of bounds assert( ( index >= 0 ) && ( index < m_data->len ) ); // In release mode, let them change a safe variable // don't include the '/0' in the test, because technically, it's out of bounds if ( ( index < 0 ) || ( index >= m_data->len ) ) { return dummy; } return m_data->data[ index ]; } inline void idStr::operator= ( const idStr& text ) { // adding the reference before deleting our current reference prevents // us from deleting our string if we are copying from ourself text.m_data->AddRef(); m_data->DelRef(); m_data = text.m_data; } inline void idStr::operator= ( const char *text ) { int len; assert( text ); if ( !text ) { // safe behaviour if NULL EnsureAlloced ( 1, false ); m_data->data[0] = 0; m_data->len = 0; return; } if ( !m_data ) { len = strlen ( text ); EnsureAlloced( len + 1, false ); strcpy ( m_data->data, text ); m_data->len = len; return; } if ( text == m_data->data ) return; // Copying same thing. Punt. // If we alias and I don't do this, I could corrupt other strings... This // will get called with EnsureAlloced anyway EnsureDataWritable (); // Now we need to check if we're aliasing.. if ( text >= m_data->data && text <= m_data->data + m_data->len ) { // Great, we're aliasing. We're copying from inside ourselves. // This means that I don't have to ensure that anything is alloced, // though I'll assert just in case. int diff = text - m_data->data; int i; assert ( strlen ( text ) < (unsigned) m_data->len ); for ( i = 0; text[i]; i++ ) { m_data->data[i] = text[i]; } m_data->data[i] = 0; m_data->len -= diff; return; } len = strlen( text ); EnsureAlloced ( len + 1, false ); strcpy( m_data->data, text ); m_data->len = len; } inline idStr operator+ ( const idStr& a, const idStr& b ) { idStr result( a ); result.append( b ); return result; } inline idStr operator+ ( const idStr& a, const char *b ) { idStr result( a ); result.append( b ); return result; } inline idStr operator+ ( const char *a, const idStr& b ) { idStr result( a ); result.append( b ); return result; } inline idStr operator+ ( const idStr& a, const bool b ) { idStr result( a ); result.append( b ? "true" : "false" ); return result; } inline idStr operator+ ( const idStr& a, const char b ) { char text[ 2 ]; text[ 0 ] = b; text[ 1 ] = 0; return a + text; } inline idStr& idStr::operator+= ( const idStr& a ) { append( a ); return *this; } inline idStr& idStr::operator+= ( const char *a ) { append( a ); return *this; } inline idStr& idStr::operator+= ( const char a ) { char text[ 2 ]; text[ 0 ] = a; text[ 1 ] = 0; append( text ); return *this; } inline idStr& idStr::operator+= ( const bool a ) { append( a ? "true" : "false" ); return *this; } inline bool operator== ( const idStr& a, const idStr& b ) { return ( !strcmp( a.c_str(), b.c_str() ) ); } inline bool operator== ( const idStr& a, const char *b ) { assert( b ); if ( !b ) { return false; } return ( !strcmp( a.c_str(), b ) ); } inline bool operator== ( const char *a, const idStr& b ) { assert( a ); if ( !a ) { return false; } return ( !strcmp( a, b.c_str() ) ); } inline bool operator!= ( const idStr& a, const idStr& b ) { return !( a == b ); } inline bool operator!= ( const idStr& a, const char *b ) { return !( a == b ); } inline bool operator!= ( const char *a, const idStr& b ) { return !( a == b ); } inline int idStr::icmpn ( const char *text, int n ) const { assert( m_data ); assert( text ); return idStr::icmpn( m_data->data, text, n ); } inline int idStr::icmpn ( const idStr& text, int n ) const { assert( m_data ); assert( text.m_data ); return idStr::icmpn( m_data->data, text.m_data->data, n ); } inline int idStr::icmp ( const char *text ) const { assert( m_data ); assert( text ); return idStr::icmp( m_data->data, text ); } inline int idStr::icmp ( const idStr& text ) const { assert( c_str () ); assert( text.c_str () ); return idStr::icmp( c_str () , text.c_str () ); } inline int idStr::cmp ( const char *text ) const { assert( m_data ); assert( text ); return idStr::cmp( m_data->data, text ); } inline int idStr::cmp ( const idStr& text ) const { assert( c_str () ); assert( text.c_str () ); return idStr::cmp( c_str () , text.c_str () ); } inline int idStr::cmpn ( const char *text, int n ) const { assert( c_str () ); assert( text ); return idStr::cmpn( c_str () , text, n ); } inline int idStr::cmpn ( const idStr& text, int n ) const { assert( c_str () ); assert( text.c_str () ); return idStr::cmpn( c_str () , text.c_str () , n ); } inline void idStr::tolower ( void ) { assert( m_data ); EnsureDataWritable (); idStr::tolower( m_data->data ); } inline void idStr::toupper ( void ) { assert( m_data ); EnsureDataWritable (); idStr::toupper( m_data->data ); } inline bool idStr::isNumeric ( void ) const { assert( m_data ); return idStr::isNumeric( m_data->data ); } inline idStr::operator const char *() { return c_str(); } inline idStr::operator const char * ( void ) const { return c_str (); } #endif