worldspawn/libs/splines/util_str.h
2020-11-17 12:16:16 +01:00

721 lines
12 KiB
C++

/*
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 <assert.h>
#include <string.h>
#include <stdio.h>
#if GDEF_COMPILER_MSVC
#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