//----------------------------------------------------------------------------- // // $Logfile:: /Code/DLLs/game/str.h $ // $Revision:: 16 $ // $Author:: Steven $ // $Date:: 10/13/03 8:54a $ // // Copyright (C) 1997 by Ritual Entertainment, Inc. // All rights reserved. // // This source is may not be distributed and/or modified without // expressly written permission by Ritual Entertainment, Inc. // // // DESCRIPTION: // Simple, DLL portable string class // // WARNING: This file is shared between game, cgame and possibly the user interface. // It is instanced in each one of these directories because of the way that SourceSafe works. // #ifndef __STR_H__ #define __STR_H__ #include #include #include #include #ifdef _WIN32 #pragma warning(disable : 4710) // function 'blah' not inlined #endif #define STRING_PREALLOC_SIZE 16 void TestStringClass( void ); #if 1 class __declspec( dllexport ) str #else class str : public Class #endif { protected: char *data; char buffer[ STRING_PREALLOC_SIZE ]; int alloced; int len; void EnsureAlloced ( int, bool keepold = true ); public: ~str(); str(); str( const char *text ); str( const str& text ); str( const str text, int start, int end ); str( const char ch ); str( const int num ); str( const float num ); str( const unsigned num ); int length( void ) const; inline const char * c_str( void ) const; void append( const char *text ); void append( const str& text ); char operator[]( int index ) const; char& operator[]( int index ); str& operator=( const str& text ); str& operator=( const char *text ); friend str operator+( const str& a, const str& b ); friend str operator+( const str& a, const char *b ); friend str operator+( const char *a, const str& b ); friend str operator+( const str& a, const float b ); friend str operator+( const str& a, const int b ); friend str operator+( const str& a, const unsigned b ); friend str operator+( const str& a, const bool b ); friend str operator+( const str& a, const char b ); str& operator+=( const str& a ); str& operator+=( const char *a ); str& operator+=( const float a ); str& operator+=( const char a ); str& operator+=( const int a ); str& operator+=( const unsigned a ); str& operator+=( const bool a ); friend bool operator==( const str& a, const str& b ); friend bool operator==( const str& a, const char *b ); friend bool operator==( const char *a, const str& b ); friend bool operator!=( const str& a, const str& b ); friend bool operator!=( const str& a, const char *b ); friend bool operator!=( const char *a, const str& b ); operator const char * () const; int icmpn( const char *text, int n ) const; int icmpn( const str& text, int n ) const; int icmp( const char *text ) const; int icmp( const str& text ) const; int cmpn( const char *text, int n ) const; int cmpn( const str& text, int n ) const; int cmp( const char *text ) const; int cmp( const str& text ) const; char *tolower( void ); char *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 char str::operator[]( int index ) const { assert ( data ); if ( !data ) return 0; // don't include the '/0' in the test, because technically, it's out of bounds assert( ( index >= 0 ) && ( index < 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 >= len ) ) { return 0; } return data[ index ]; } inline int str::length( void ) const { return len; } inline str::~str() { if ( data != buffer ) delete [] data; } inline str::str() { data = buffer; alloced = STRING_PREALLOC_SIZE; data[ 0 ] = 0; len = 0; } inline str::str ( const char *text ) { int stringLength; assert( text ); data = buffer; alloced = STRING_PREALLOC_SIZE; data[ 0 ] = 0; len = 0; if ( text ) { stringLength = strlen( text ); EnsureAlloced ( stringLength + 1 ); strcpy( data, text ); len = stringLength; } } inline str::str ( const str& text ) { data = buffer; alloced = STRING_PREALLOC_SIZE; data[ 0 ] = 0; len = 0; EnsureAlloced ( text.length() + 1); strcpy( data, text.c_str() ); len = text.length(); } inline str::str ( const str text, int start, int end ) { int i; int stringLength; data = buffer; alloced = STRING_PREALLOC_SIZE; data[ 0 ] = 0; len = 0; if ( end > text.length() ) { end = text.length(); } if ( start > text.length() ) { start = text.length(); } stringLength = end - start; if ( stringLength < 0 ) { stringLength = 0; } EnsureAlloced ( stringLength + 1 ); for( i = 0; i < stringLength; i++ ) { data[ i ] = text[ start + i ]; } data[ stringLength ] = 0; len = stringLength; } inline str::str ( const char ch ) { data = buffer; alloced = STRING_PREALLOC_SIZE; EnsureAlloced ( 2 ); data[ 0 ] = ch; data[ 1 ] = 0; len = 1; } inline str::str ( const float num ) { char text[ 32 ]; int stringLength; data = buffer; alloced = STRING_PREALLOC_SIZE; sprintf( text, "%.3f", num ); stringLength = strlen( text ); EnsureAlloced( stringLength + 1 ); strcpy( data, text ); len = stringLength; } inline str::str ( const int num ) { char text[ 32 ]; int stringLength; data = buffer; alloced = STRING_PREALLOC_SIZE; sprintf( text, "%d", num ); stringLength = strlen( text ); EnsureAlloced( stringLength + 1 ); strcpy( data, text ); len = stringLength; } inline str::str ( const unsigned num ) { char text[ 32 ]; int stringLength; data = buffer; alloced = STRING_PREALLOC_SIZE; sprintf( text, "%u", num ); stringLength = strlen( text ); EnsureAlloced( stringLength + 1 ); strcpy( data, text ); len = stringLength; } inline const char *str::c_str( void ) const { //assert( data ); return data; } inline void str::append ( const char *text ) { int new_length; assert( text ); if ( text ) { new_length = length(); new_length += strlen( text ); EnsureAlloced( new_length + 1 ); strcat( data, text ); len = new_length; } } inline void str::append ( const str& text ) { int new_length; new_length = length(); new_length += text.length(); EnsureAlloced ( new_length + 1 ); strcat ( data, text.c_str () ); len = new_length; } inline char& str::operator[] ( int index ) { // Used for result for invalid indices static char dummy = 0; assert ( data ); if ( !data ) return dummy; // don't include the '/0' in the test, because technically, it's out of bounds assert( ( index >= 0 ) && ( index < 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 >= len ) ) { return dummy; } return data[ index ]; } inline str& str::operator= ( const str& text ) { EnsureAlloced ( text.length() + 1, false ); strcpy( data, text.c_str() ); len = text.length(); return *this; } inline str& str::operator= ( const char *text ) { int stringLength; assert( text ); if ( !text ) { // safe behaviour if NULL EnsureAlloced ( 1, false ); data[0] = 0; len = 0; return *this; } if ( text == data ) return *this; // Copying same thing. Punt. // Now we need to check if we're aliasing.. unsigned int dataStart = reinterpret_cast (data); unsigned int dataEnd = reinterpret_cast (data) + len; unsigned int textStart = reinterpret_cast (text); if ( textStart >= dataStart && textStart <= dataEnd ) { // 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 - data; int i; assert ( strlen ( text ) < (unsigned) len ); for ( i = 0; text[i]; i++ ) { data[i] = text[i]; } data[i] = 0; len -= diff; return *this; } stringLength = strlen( text ); EnsureAlloced ( stringLength + 1, false ); strcpy( data, text ); len = stringLength; return *this; } inline str operator+ ( const str& a, const str& b ) { str result( a ); result.append( b ); return result; } inline str operator+ ( const str& a, const char *b ) { str result( a ); result.append( b ); return result; } inline str operator+ ( const char *a, const str& b ) { str result( a ); result.append( b ); return result; } inline str operator+ ( const str& a, const bool b ) { str result( a ); result.append( b ? "true" : "false" ); return result; } inline str operator+ ( const str& a, const char b ) { char text[ 2 ]; text[ 0 ] = b; text[ 1 ] = 0; return a + text; } inline str& str::operator+= ( const str& a ) { append( a ); return *this; } inline str& str::operator+= ( const char *a ) { append( a ); return *this; } inline str& str::operator+= ( const char a ) { char text[ 2 ]; text[ 0 ] = a; text[ 1 ] = 0; append( text ); return *this; } inline str& str::operator+= ( const bool a ) { append( a ? "true" : "false" ); return *this; } inline bool operator== ( const str& a, const str& b ) { /// Check if lengths are equal if( a.length() != b.length() ) return( false ); return ( !strcmp( a.c_str(), b.c_str() ) ); } inline bool operator== ( const str& a, const char *b ) { assert( b ); if ( !b ) { return false; } return ( !strcmp( a.c_str(), b ) ); } inline bool operator== ( const char *a, const str& b ) { assert( a ); if ( !a ) { return false; } return ( !strcmp( a, b.c_str() ) ); } inline bool operator!= ( const str& a, const str& b ) { return !( a == b ); } inline bool operator!= ( const str& a, const char *b ) { return !( a == b ); } inline bool operator!= ( const char *a, const str& b ) { return !( a == b ); } inline int str::icmpn ( const char *text, int n ) const { assert( data ); assert( text ); return str::icmpn( data, text, n ); } inline int str::icmpn ( const str& text, int n ) const { assert( data ); assert( text.data ); return str::icmpn( data, text.data, n ); } inline int str::icmp ( const char *text ) const { assert( data ); assert( text ); return str::icmp( data, text ); } inline int str::icmp ( const str& text ) const { assert( c_str () ); assert( text.c_str () ); return str::icmp( c_str () , text.c_str () ); } inline int str::cmp ( const char *text ) const { assert( data ); assert( text ); return str::cmp( data, text ); } inline int str::cmp ( const str& text ) const { assert( c_str () ); assert( text.c_str () ); return str::cmp( c_str () , text.c_str () ); } inline int str::cmpn ( const char *text, int n ) const { assert( c_str () ); assert( text ); return str::cmpn( c_str () , text, n ); } inline int str::cmpn ( const str& text, int n ) const { assert( c_str () ); assert( text.c_str () ); return str::cmpn( c_str () , text.c_str () , n ); } inline char *str::tolower ( void ) { assert( data ); return str::tolower( data ); } inline char *str::toupper ( void ) { assert( data ); return str::toupper( data ); } inline bool str::isNumeric ( void ) const { assert( data ); return str::isNumeric( data ); } inline str::operator const char * ( void ) const { return c_str (); } #endif