801 lines
14 KiB
C++
801 lines
14 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $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 <qcommon/platform.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#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<unsigned int> (data);
|
|
unsigned int dataEnd = reinterpret_cast<unsigned int> (data) + len;
|
|
unsigned int textStart = reinterpret_cast<unsigned int> (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
|