Commit 9323ae47 authored by Dimitri van Heesch's avatar Dimitri van Heesch

Added faster reference counted string implementation with short string optimization

parent 258259ff
......@@ -127,7 +127,7 @@ REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = YES
CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
......
......@@ -3,8 +3,8 @@
* Copyright (C) 1997-2004 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
......@@ -24,281 +24,148 @@
#include <qregexp.h>
#include <qdatastream.h>
QCString::QCString(int size)
{
if (size>0)
{
m_data = (char *)malloc(size);
if (m_data)
{
if (size>1) memset(m_data,' ',size-1);
m_data[size-1]='\0';
}
}
else
{
m_data=0;
}
}
QCString::QCString( const QCString &s )
{
duplicate(s);
}
QCString::QCString( const char *str )
{
duplicate(str);
}
QCString::QCString( const char *str, uint maxlen )
{
uint l;
if (str && ( l = QMIN(qstrlen(str),maxlen) ))
{
m_data=(char *)malloc(l+1);
strncpy(m_data,str,l+1);
m_data[l]='\0';
}
else
{
m_data=0;
}
}
QCString::~QCString()
{
if (m_data) free(m_data);
m_data=0;
}
QCString &QCString::assign( const char *str )
QCString &QCString::sprintf( const char *format, ... )
{
if (m_data) free(m_data);
duplicate(str);
va_list ap;
va_start( ap, format );
const int minlen=256;
if (length()<minlen) resize(minlen);
vsnprintf( data(), minlen, format, ap);
resize(strlen(data())+1);
va_end( ap );
return *this;
}
bool QCString::resize( uint newlen )
int QCString::find( char c, int index, bool cs ) const
{
if (newlen==0)
{
if (m_data) { free(m_data); m_data=0; }
return TRUE;
}
if (m_data==0) // newlen>0
if (index<0 || index>=(int)length()) return -1; // index outside string
register const char *pos;
if (cs)
{
m_data = (char *)malloc(newlen);
pos = strchr(data()+index,c);
}
else
{
m_data = (char *)realloc(m_data,newlen);
pos = data()+index;
c = tolower((unsigned char)c);
while (*pos && tolower((unsigned char)*pos)!=c) pos++;
if (!*pos && c) pos=0; // not found
}
if (m_data==0) return FALSE;
m_data[newlen-1]='\0';
return TRUE;
return pos ? (int)(pos - data()) : -1;
}
bool QCString::fill( char c, int len )
int QCString::find( const char *str, int index, bool cs ) const
{
uint l=length();
if (len<0) len=l;
if ((uint)len!=l)
int l = length();
if (index<0 || index>=l) return -1; // index outside string
if (!str) return -1; // no string to search for
if (!*str) return index; // empty string matching at index
register char *pos;
if (cs) // case sensitive
{
if (m_data) free(m_data);
if (len>0)
{
m_data=(char *)malloc(len+1);
if (m_data==0) return FALSE;
m_data[len]='\0';
}
else
{
m_data=0;
}
pos = strstr(data()+index,str);
}
if (len>0)
else // case insensitive
{
uint i;
for (i=0;i<(uint)len;i++) m_data[i]=c;
}
return TRUE;
}
QCString &QCString::sprintf( const char *format, ... )
{
va_list ap;
va_start( ap, format );
uint l = length();
const uint minlen=256;
if (l<minlen)
{
if (m_data)
m_data = (char *)realloc(m_data,minlen);
else
m_data = (char *)malloc(minlen);
}
vsprintf( m_data, format, ap );
resize( qstrlen(m_data) + 1 ); // truncate
va_end( ap );
return *this;
}
int QCString::find( char c, int index, bool cs ) const
{
uint len = length();
if ( m_data==0 || (uint)index>len ) // index outside string
return -1;
register const char *d;
if ( cs ) // case sensitive
{
d = strchr( m_data+index, c );
}
else
{
d = m_data+index;
c = tolower( (uchar) c );
while ( *d && tolower((uchar) *d) != c )
d++;
if ( !*d && c ) // not found
d = 0;
}
return d ? (int)(d - m_data) : -1;
}
int QCString::find( const char *str, int index, bool cs ) const
{
uint l = length();
if ( m_data==0 || (uint)index > l ) // index outside string
return -1;
if ( !str ) // no search string
return -1;
if ( !*str ) // zero-length search string
return index;
register const char *d;
if ( cs ) // case sensitive
{
d = strstr( m_data+index, str );
}
else // case insensitive
{
d = m_data+index;
int len = qstrlen( str );
while ( *d )
pos = data();
int len = strlen(str);
while (*pos)
{
if ( qstrnicmp(d, str, len) == 0 )
break;
d++;
if (strncasecmp(pos,str,len)==0) break;
pos++;
}
if ( !*d ) // not found
d = 0;
if (!*pos) pos = 0; // not found
}
return d ? (int)(d - m_data) : -1;
return pos ? (int)(pos - data()) : -1;
}
int QCString::find( const QCString &str,int index,bool cs) const
int QCString::find( const QCString &str, int index, bool cs ) const
{
return find(str.data(),index,cs);
}
int QCString::find( const QRegExp &rx, int index ) const
{
QString d = QString::fromLatin1( m_data );
QString d = QString::fromLatin1( data() );
return d.find( rx, index );
}
int QCString::findRev( char c, int index, bool cs) const
{
const char *b = m_data;
const char *d;
uint len = length();
if ( b == 0 ) return -1; // empty string
if ( index < 0 ) // neg index ==> start from end
// printf("QCString::findRev(%d,%d,%d)\n",c,index,cs);
const char *b = data();
const char *pos;
int len = length();
if (len==0) return -1; // empty string
if (index<0) // start from end
{
if ( len == 0 ) return -1;
if ( cs )
if (cs)
{
d = strrchr( b, c );
return d ? (int)(d - b) : -1;
pos = strrchr(b,c);
return pos ? (int)(pos - b) : -1;
}
index = len;
}
else if ( (uint)index > len ) // bad index
{
index=len;
}
else if (index>len) // bad index
{
return -1;
}
d = b+index;
if ( cs ) // case sensitive
pos = b+index;
if (cs)
{
while ( d >= b && *d != c )
d--;
}
else // case insensitive
while ( pos>=b && *pos!=c) pos--;
}
else
{
c = tolower( (uchar) c );
while ( d >= b && tolower((uchar) *d) != c )
d--;
c = tolower((unsigned char)c);
while ( pos>=b && tolower((unsigned char)*pos)!=c) pos--;
}
return d >= b ? (int)(d - b) : -1;
//printf("pos=%p b=%p diff=%d\n",pos,b,(int)(pos-b));
return pos>=b ? (int)(pos - b) : -1;
}
int QCString::findRev( const char *str, int index, bool cs) const
{
int slen = qstrlen(str);
uint len = length();
if ( index < 0 ) // neg index ==> start from end
index = len-slen;
else if ( (uint)index > len ) // bad index
return -1;
else if ( (uint)(index + slen) > len ) // str would be too long
index = len - slen;
if ( index < 0 )
return -1;
register char *d = m_data + index;
if ( cs ) // case sensitive
{
for ( int i=index; i>=0; i-- )
if ( qstrncmp(d--,str,slen)==0 )
return i;
}
else // case insensitive
{
for ( int i=index; i>=0; i-- )
if ( qstrnicmp(d--,str,slen)==0 )
return i;
int slen = strlen(str);
int len = length();
if (index<0) index = len-slen; // start from end
else if (index>len) return -1; // bad index
else if (index+slen>len) index=len-slen; // str would be too long
if (index<0) return -1; // no match possible
register char *pos = data()+index;
if (cs) // case sensitive
{
for (int i=index; i>=0; i--) if (strncmp(pos--,str,slen)==0) return i;
}
else // case insensitive
{
for (int i=index; i>=0; i--) if (strncasecmp(pos,str,slen)==0) return i;
}
return -1;
}
int QCString::findRev( const QRegExp &rx, int index ) const
{
QString d = QString::fromLatin1( m_data );
QString d = QString::fromLatin1( data() );
return d.findRev( rx, index );
}
int QCString::contains( char c, bool cs ) const
{
int count = 0;
char *d = m_data;
if ( !d )
return 0;
if ( cs ) // case sensitive
{
while ( *d )
if ( *d++ == c )
count++;
}
else // case insensitive
{
c = tolower( (uchar) c );
while ( *d ) {
if ( tolower((uchar) *d) == c )
count++;
d++;
if (length()==0) return 0;
int count=0;
const char *pos = data();
if (cs)
{
while (*pos) if (*pos++ == c) count++;
}
else
{
c = tolower((unsigned char)c);
while (*pos)
{
if (tolower((unsigned char)*pos)==c) count++;
pos++;
}
}
return count;
......@@ -306,96 +173,106 @@ int QCString::contains( char c, bool cs ) const
int QCString::contains( const char *str, bool cs ) const
{
int count = 0;
char *d = data();
if ( !d )
return 0;
int len = qstrlen( str );
while ( *d ) // counts overlapping strings
if (str==0 || length()==0) return 0;
int count=0;
const char *pos = data();
int len = strlen(str);
while (*pos)
{
if ( cs )
if (cs)
{
if ( qstrncmp( d, str, len ) == 0 )
count++;
}
else
if (strncmp(pos,str,len)==0) count++;
}
else
{
if ( qstrnicmp(d, str, len) == 0 )
count++;
if (strncasecmp(pos,str,len)==0) count++;
}
d++;
pos++;
}
return count;
}
int QCString::contains( const QRegExp &rx ) const
{
QString d = QString::fromLatin1( m_data );
{
QString d = QString::fromLatin1( data() );
return d.contains( rx );
}
bool QCString::stripPrefix(const char *prefix)
{
if (prefix==0 || length()==0) return FALSE;
int len = strlen(prefix);
if (strncmp(prefix,data(),len)==0)
{
int newlen = length()-len+1;
qmemmove(data(),data()+len,newlen);
resize(newlen);
return TRUE;
}
return FALSE;
}
QCString QCString::left( uint len ) const
{
if ( isEmpty() )
if (isEmpty())
{
return QCString();
}
else if ( len >= length() )
}
else if (len>=length())
{
return *this;
}
else
return QCString(data());
}
else
{
QCString s( len+1 );
strncpy( s.data(), m_data, len );
*(s.data()+len) = '\0';
memcpy( s.data(), data(), len);
return s;
}
}
QCString QCString::right( uint len ) const
{
if ( isEmpty() )
if (isEmpty())
{
return QCString();
}
else
}
else
{
uint l = length();
if ( len > l ) len = l;
char *p = m_data + (l - len);
return QCString( p );
}
int l = length();
if ((int)len>l) len=l;
const char *pos = data() + (l-len);
return QCString(pos);
}
}
QCString QCString::mid( uint index, uint len) const
{
uint slen = length();
if ( len == 0xffffffff ) len = slen-index;
if ( isEmpty() || index >= slen )
int slen = length();
if (len==0xffffffff) len = slen-index;
if (isEmpty() || (int)index>=slen)
{
return QCString();
}
else
}
else
{
register char *p = data()+index;
QCString s( len+1 );
strncpy( s.data(), p, len );
*(s.data()+len) = '\0';
QCString s(len+1);
memcpy(s.data(),p,len);
return s;
}
}
QCString QCString::lower() const
{
QCString s( m_data );
register char *p = s.data();
if ( p )
if (length()==0) return QCString();
QCString s(data());
register char *pos = s.data();
if (pos)
{
while ( *p )
while (*pos)
{
*p = tolower((uchar) *p);
p++;
*pos = tolower((unsigned char)*pos);
pos++;
}
}
return s;
......@@ -403,41 +280,44 @@ QCString QCString::lower() const
QCString QCString::upper() const
{
QCString s( m_data );
register char *p = s.data();
if ( p ) {
while ( *p ) {
*p = toupper((uchar)*p);
p++;
if (length()==0) return QCString();
QCString s(data());
register char *pos = s.data();
if (pos)
{
while (*pos)
{
*pos = toupper((unsigned char)*pos);
pos++;
}
}
return s;
}
QCString QCString::stripWhiteSpace() const
QCString QCString::stripWhiteSpace() const
{
if ( isEmpty() ) // nothing to do
return *this;
register char *s = m_data;
register char *s = data();
int reslen = length();
if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) )
return *this; // returns a copy
if ( !isspace((uchar)s[0]) && !isspace((uchar)s[reslen-1]) )
return *this; // returns a copy
QCString result(s);
s = result.data();
s = result.data();
int start = 0;
int end = reslen - 1;
while ( isspace((uchar) s[start]) ) // skip white space from start
start++;
if ( s[start] == '\0' )
start++;
if ( s[start] == '\0' )
{ // only white space
return QCString();
}
while ( end && isspace((uchar) s[end]) ) // skip white space from end
end--;
end -= start - 1;
memmove( result.data(), &s[start], end );
qmemmove( result.data(), &s[start], end );
result.resize( end + 1 );
return result;
}
......@@ -451,7 +331,7 @@ QCString QCString::simplifyWhiteSpace() const
char *from = data();
char *to = result.data();
char *first = to;
while ( TRUE )
while ( TRUE )
{
while ( *from && isspace((uchar) *from) )
from++;
......@@ -469,84 +349,66 @@ QCString QCString::simplifyWhiteSpace() const
return result;
}
QCString &QCString::assign( const char *str )
{
return operator=(str);
}
QCString &QCString::insert( uint index, const char *s )
{
{
int len = s ? qstrlen(s) : 0;
if ( len == 0 )
return *this;
uint olen = length();
int nlen = olen + len;
if ( index >= olen ) // insert after end of string
{
m_data = (char *)realloc(m_data,nlen+index-olen+1);
if ( m_data )
{
memset( m_data+olen, ' ', index-olen );
memcpy( m_data+index, s, len+1 );
}
}
else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert
{
memmove( m_data+index+len, m_data+index, olen-index+1 );
memcpy( m_data+index, s, len );
if ( len == 0 ) return *this;
int olen = length();
int nlen = olen + len;
if ((int)index>=olen)
{
resize(nlen+index-olen+1);
memset(data()+olen, ' ', index-olen);
memcpy(data()+index,s, len+1);
}
else
{
resize(nlen+1);
qmemmove(data()+index+len,data()+index,olen-index+1);
memcpy(data()+index,s,len);
}
return *this;
}
QCString &QCString::insert( uint index, char c ) // insert char
QCString &QCString::insert( uint index, char c)
{
char buf[2];
buf[0] = c;
buf[1] = '\0';
return insert( index, buf );
}
QCString& QCString::operator+=( const char *str )
QCString &QCString::append( const char *s )
{
if ( !str ) return *this; // nothing to append
uint len1 = length();
uint len2 = qstrlen(str);
char *newData = (char *)realloc( m_data, len1 + len2 + 1 );
if (newData)
{
m_data = newData;
memcpy( m_data + len1, str, len2 + 1 );
}
return *this;
return operator+=(s);
}
QCString &QCString::operator+=( char c )
QCString &QCString::prepend( const char *s )
{
uint len = length();
char *newData = (char *)realloc( m_data, length()+2 );
if (newData)
{
m_data = newData;
m_data[len] = c;
m_data[len+1] = '\0';
}
return *this;
return insert(0,s);
}
QCString &QCString::remove( uint index, uint len )
{
uint olen = length();
if ( index + len >= olen ) // range problems
{
{
if ( index < olen ) // index ok
{
{
resize( index+1 );
}
}
else if ( len != 0 )
}
else if ( len != 0 )
{
memmove( m_data+index, m_data+index+len, olen-index-len+1 );
qmemmove( data()+index, data()+index+len, olen-index-len+1 );
resize( olen-len+1 );
}
return *this;
}
QCString &QCString::replace( uint index, uint len, const char *s )
QCString &QCString::replace( uint index, uint len, const char *s)
{
remove( index, len );
insert( index, s );
......@@ -555,65 +417,85 @@ QCString &QCString::replace( uint index, uint len, const char *s )
QCString &QCString::replace( const QRegExp &rx, const char *str )
{
QString d = QString::fromLatin1( m_data );
QString d = QString::fromLatin1( data() );
QString r = QString::fromLatin1( str );
d.replace( rx, r );
operator=( d.ascii() );
return *this;
}
long QCString::toLong( bool *ok ) const
short QCString::toShort(bool *ok) const
{
QString s(data());
return s.toShort(ok);
}
ushort QCString::toUShort(bool *ok) const
{
QString s(data());
return s.toUShort(ok);
}
int QCString::toInt(bool *ok) const
{
QString s(data());
return s.toInt(ok);
}
uint QCString::toUInt(bool *ok) const
{
QString s(data());
return s.toUInt(ok);
}
long QCString::toLong(bool *ok) const
{
QString s(m_data);
QString s(data());
return s.toLong(ok);
}
ulong QCString::toULong( bool *ok ) const
ulong QCString::toULong(bool *ok) const
{
QString s(m_data);
QString s(data());
return s.toULong(ok);
}
short QCString::toShort( bool *ok ) const
QCString &QCString::setNum(short n)
{
QString s(m_data);
return s.toShort(ok);
return setNum((long)n);
}
ushort QCString::toUShort( bool *ok ) const
QCString &QCString::setNum(ushort n)
{
QString s(m_data);
return s.toUShort(ok);
return setNum((ulong)n);
}
int QCString::toInt( bool *ok ) const
QCString &QCString::setNum(int n)
{
QString s(m_data);
return s.toInt(ok);
return setNum((long)n);
}
uint QCString::toUInt( bool *ok ) const
QCString &QCString::setNum(uint n)
{
QString s(m_data);
return s.toUInt(ok);
return setNum((ulong)n);
}
QCString &QCString::setNum( long n )
QCString &QCString::setNum(long n)
{
char buf[20];
register char *p = &buf[19];
bool neg;
if ( n < 0 )
if ( n < 0 )
{
neg = TRUE;
n = -n;
}
else
}
else
{
neg = FALSE;
}
*p = '\0';
do
do
{
*--p = ((int)(n%10)) + '0';
n /= 10;
......@@ -623,12 +505,12 @@ QCString &QCString::setNum( long n )
return *this;
}
QCString &QCString::setNum( ulong n )
QCString &QCString::setNum( ulong n)
{
char buf[20];
register char *p = &buf[19];
*p = '\0';
do
do
{
*--p = ((int)(n%10)) + '0';
n /= 10;
......@@ -637,31 +519,7 @@ QCString &QCString::setNum( ulong n )
return *this;
}
void QCString::msg_index( uint index )
{
#if defined(CHECK_RANGE)
qWarning( "QCString::at: Absolute index %d out of range", index );
#else
Q_UNUSED( index )
#endif
}
bool QCString::stripPrefix(const char *prefix)
{
if (prefix==0) return FALSE;
uint plen = qstrlen(prefix);
if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches
{
uint len = qstrlen(m_data);
uint newlen = len-plen+1;
qmemmove(m_data,m_data+plen,newlen);
resize(newlen);
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
//-------------------------------------------------
void *qmemmove( void *dst, const void *src, uint len )
{
......
/****************************************************************************
**
**
** Definition of the extended char array operations,
** and QByteArray and QCString classes
** Copyright (C) 1997-2004 by Dimitri van Heesch.
**
** Created : 920609
** Permission to use, copy, modify, and distribute this software and its
** documentation under the terms of the GNU General Public License is hereby
** granted. No representations are made about the suitability of this software
** for any purpose. It is provided "as is" without express or implied warranty.
** See the GNU General Public License for more details.
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the tools module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
** Note: this is a reimplementation of the qcstring.h that came with
** an Qt version 2.2.3. For short strings it stores the string data inside
** the object. For long strings it uses a separate array with reference counting.
**
**********************************************************************/
......@@ -43,6 +21,7 @@
#include "qarray.h"
#endif // QT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -54,6 +33,7 @@
#include <strings.h>
#endif
#include <assert.h>
class QGString;
......@@ -77,7 +57,6 @@ inline char *hack_strrchr( const char *s, int c )
#define strrchr(s,c) hack_strrchr((s),(c))
#endif
/*****************************************************************************
Safe and portable C string functions; extensions to standard string.h
*****************************************************************************/
......@@ -127,39 +106,6 @@ Q_EXPORT int qstricmp( const char *str1, const char *str2 );
Q_EXPORT int qstrnicmp( const char *str1, const char *str2, uint len );
#if 0
// ### TODO for 3.0: these and the cstr* functions should be used if
// !defined(QT_CLEAN_NAMESPACE)
// We want to keep source compatibility for 2.x
// ### TODO for 4.0: completely remove these and the cstr* functions
#if !defined(QT_GENUINE_STR)
#undef strlen
#define strlen qstrlen
#undef strcpy
#define strcpy qstrcpy
#undef strcmp
#define strcmp qstrcmp
#undef strncmp
#define strncmp qstrncmp
#undef stricmp
#define stricmp qstricmp
#undef strnicmp
#define strnicmp qstrnicmp
#endif
#endif
// qChecksum: Internet checksum
Q_EXPORT Q_UINT16 qChecksum( const char *s, uint len );
/*****************************************************************************
QByteArray class
*****************************************************************************/
......@@ -169,7 +115,6 @@ template class Q_EXPORT QArray<char>;
#endif
typedef QArray<char> QByteArray;
/*****************************************************************************
QByteArray stream functions
*****************************************************************************/
......@@ -181,143 +126,538 @@ Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & );
class QRegExp;
/** This is an alternative implementation of QCString. It provides basically
* the same functions but uses less memory for administration. This class
* is just a wrapper around a plain C string requiring only 4 bytes "overhead".
* QCString features sharing of data and stores the string length, but
* requires 4 + 12 bytes for this (even for the empty string). As doxygen
* uses a LOT of string during a run it saves a lot of memory to use a
* more memory efficient implementation at the cost of relatively low
* runtime overhead.
* the same functions but uses reference counting and copy on write.
*/
class QCString
class QCString
{
public:
QCString() : m_data(0) {} // make null string
QCString( const QCString &s );
QCString( int size );
QCString( const char *str );
QCString( const char *str, uint maxlen );
~QCString();
QCString &operator=( const QCString &s );// deep copy
QCString &operator=( const char *str ); // deep copy
bool isNull() const;
bool isEmpty() const;
uint length() const;
uint size() const { return m_data ? length()+1 : 0; }
char * data() const { return m_data; }
bool resize( uint newlen );
bool truncate( uint pos );
bool fill( char c, int len = -1 );
QCString copy() const;
QCString &sprintf( const char *format, ... );
int find( char c, int index=0, bool cs=TRUE ) const;
int find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const QCString &str, int index=0, bool cs=TRUE ) const;
int find( const QRegExp &, int index=0 ) const;
int findRev( char c, int index=-1, bool cs=TRUE) const;
int findRev( const char *str, int index=-1, bool cs=TRUE) const;
int findRev( const QRegExp &, int index=-1 ) const;
int contains( char c, bool cs=TRUE ) const;
int contains( const char *str, bool cs=TRUE ) const;
int contains( const QRegExp & ) const;
bool stripPrefix(const char *prefix);
QCString left( uint len ) const;
QCString right( uint len ) const;
QCString mid( uint index, uint len=0xffffffff) const;
QCString lower() const;
QCString upper() const;
QCString stripWhiteSpace() const;
QCString simplifyWhiteSpace() const;
QCString &assign( const char *str );
QCString &insert( uint index, const char * );
QCString &insert( uint index, char );
QCString &append( const char *s );
QCString &prepend( const char *s );
QCString &remove( uint index, uint len );
QCString &replace( uint index, uint len, const char * );
QCString &replace( const QRegExp &, const char * );
short toShort( bool *ok=0 ) const;
ushort toUShort( bool *ok=0 ) const;
int toInt( bool *ok=0 ) const;
uint toUInt( bool *ok=0 ) const;
long toLong( bool *ok=0 ) const;
ulong toULong( bool *ok=0 ) const;
QCString &setNum( short );
QCString &setNum( ushort );
QCString &setNum( int );
QCString &setNum( uint );
QCString &setNum( long );
QCString &setNum( ulong );
QCString &setNum( float, char f='g', int prec=6 );
QCString &setNum( double, char f='g', int prec=6 );
operator const char *() const;
QCString &operator+=( const char *str );
QCString &operator+=( char c );
char &at( uint index ) const;
char &operator[]( int i ) const { return at(i); }
/** creates an empty string */
QCString()
{
}
/** destroys the string */
~QCString()
{
}
/** makes a copy of a string. */
QCString( const QCString &s ) : m_rep(s.m_rep)
{
}
/** creates a string with room for size characters
* @param[in] size the number of character to allocate (including the 0-terminator)
*/
QCString( int size ) : m_rep(size)
{
}
/** creates a string from a plain C string.
* @param[in] str A zero terminated C string. When 0 an empty string is created.
*/
QCString( const char *str ) : m_rep(str)
{
}
/** creates a string from \a str and copies over the first \a maxlen characters. */
QCString( const char *str, uint maxlen ) : m_rep(str,maxlen)
{
}
/** replaces the contents by that of string \a s. */
QCString &operator=( const QCString &s )
{
m_rep = s.m_rep;
return *this;
}
/** replaces the contents by that of C string \a str. */
QCString &operator=( const char *str)
{
m_rep = str;
return *this;
}
/** Returns TRUE iff the string is empty. Equivalent to isEmpty(). */
bool isNull() const
{
return m_rep.isEmpty();
}
/** Returns TRUE iff the string is empty */
bool isEmpty() const
{
return m_rep.isEmpty();
}
/** Returns the length of the string, excluding the 0-terminator. Equivalent to size(). */
uint length() const
{
return m_rep.length();
}
/** Returns the length of the string, excluding the 0-terminator. */
uint size() const
{
return m_rep.length();
}
/** Returns a pointer to the contents of the string in the form of a 0-terminated C string */
char *data() const
{
return m_rep.data();
}
/** Resizes the string to hold \a newlen characters
* (this value should include the 0-terminator). If the string is enlarged the contents will
* be left unmodified.
*/
bool resize( uint newlen )
{
m_rep.resize(newlen);
return TRUE;
}
/** Truncates the string at position \a pos. */
bool truncate( uint pos )
{
return resize(pos+1);
}
/** Fills a string with a predefined character
* @param[in] c the character used to fill the string with.
* @param[in] len the number of character to fill. Use -1 to fill the whole string.
* @note the string will be resized to contain \a len characters. The contents of the
* string will be lost.
*/
bool fill( char c, int len = -1 )
{
m_rep.fill(c,len);
return TRUE;
}
/** Returns a deep copy of the string. */
QCString copy() const
{
if (length()==0) return QCString();
QCString cs(length()+1);
memcpy(cs.data(),data(),length());
return cs;
}
QCString &sprintf( const char *format, ... );
int find( char c, int index=0, bool cs=TRUE ) const;
int find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const QCString &str, int index=0, bool cs=TRUE ) const;
int find( const QRegExp &rx, int index=0 ) const;
int findRev( char c, int index=-1, bool cs=TRUE) const;
int findRev( const char *str, int index=-1, bool cs=TRUE) const;
int findRev( const QRegExp &rx, int index=-1 ) const;
int contains( char c, bool cs=TRUE ) const;
int contains( const char *str, bool cs=TRUE ) const;
int contains( const QRegExp &rx ) const;
bool stripPrefix(const char *prefix);
QCString left( uint len ) const;
QCString right( uint len ) const;
QCString mid( uint index, uint len=0xffffffff) const;
QCString lower() const;
QCString upper() const;
QCString stripWhiteSpace() const;
QCString simplifyWhiteSpace() const;
QCString &assign( const char *str );
QCString &insert( uint index, const char *s );
QCString &insert( uint index, char c);
QCString &append( const char *s );
QCString &prepend( const char *s );
QCString &remove( uint index, uint len );
QCString &replace( uint index, uint len, const char *s);
QCString &replace( const QRegExp &rx, const char *str );
short toShort( bool *ok=0 ) const;
ushort toUShort( bool *ok=0 ) const;
int toInt( bool *ok=0 ) const;
uint toUInt( bool *ok=0 ) const;
long toLong( bool *ok=0 ) const;
ulong toULong( bool *ok=0 ) const;
QCString &setNum(short n);
QCString &setNum(ushort n);
QCString &setNum(int n);
QCString &setNum(uint n);
QCString &setNum(long n);
QCString &setNum(ulong n);
/** Converts the string to a plain C string */
operator const char *() const
{
return (const char *)data();
}
/** Appends string \a str to this string and returns a reference to the result. */
QCString &operator+=( const char *str )
{
if (!str) return *this;
int len1 = length();
int len2 = strlen(str);
resize(len1+len2+1);
memcpy(data()+len1,str,len2);
return *this;
}
/** Appends character \a c to this string and returns a reference to the result. */
QCString &operator+=( char c )
{
int len = length();
resize(len+2);
data()[len]=c;
return *this;
}
/** Returns a reference to the character at index \a i. */
char &at( uint i) const
{
return m_rep.at(i);
}
/** Indexing operator. Equavalent to at(). */
char &operator[]( int i ) const
{
return m_rep.at((uint)i);
}
private:
static void msg_index( uint );
void duplicate( const QCString &s );
void duplicate( const char *str);
QCString &duplicate( const char *str, int);
char * m_data;
struct LSData;
// long string representation
struct LongStringRep
{
uchar isShort : 1; // should be shared with ShortStringRep
uchar : 7;
LSData *d;
};
#define SHORT_STR_CAPACITY ((int)sizeof(LongStringRep)-1)
#define SHORT_STR_MAX_LEN (SHORT_STR_CAPACITY-1)
// short string representation
struct ShortStringRep
{
uchar isShort : 1; // should be shared with LongStringRep
uchar len : 7;
char str[SHORT_STR_CAPACITY]; // size including 0-terminator
};
// ref counting string header
struct LSHeader
{
int len; // length of string without 0 terminator
int refCount; // -1=leaked, 0=one ref & non-cost, n>0, n+1 refs, const
};
// ref counting string data and methods
struct LSData : public LSHeader
{
char *toStr()
{
return (char*)(this+1); // string data starts after the header
}
// creates a LSData item with room for size bytes (which includes the 0 terminator!)
// if size is zero, an empty string will be created.
static LSData *create(int size)
{
LSData *data;
data = (LSData*)malloc(sizeof(LSHeader)+size);
data->len = size-1;
data->refCount = 0;
data->toStr()[size-1] = 0;
return data;
}
// remove out reference to the data. Frees memory if no more users
void dispose()
{
if (--refCount<0) free(this);
}
// resizes LSData so it can hold size bytes (which includes the 0 terminator!)
// Since this is for long strings only, size should be > SHORT_STR_CAPACITY
static LSData *resize(LSData *d,int size)
{
if (d->len>0 && d->refCount==0) // non-const, non-empty
{
d = (LSData*)realloc(d,sizeof(LSHeader)+size);
d->len = size-1;
d->toStr()[size-1] = 0;
return d;
}
else // need to make a copy
{
LSData *newData = LSData::create(size);
int len = d->len;
if (len>=size) len=size-1;
memcpy(newData->toStr(),d->toStr(),len);
newData->toStr()[len]=0;
d->dispose();
return newData;
}
}
};
class StringRep
{
public:
StringRep()
{
u.s.isShort=TRUE;
u.s.len=0;
}
~StringRep()
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
}
StringRep(const StringRep &s)
{
if (&s!=this)
{
u = s.u;
if (!u.s.isShort)
{
u.l.d->refCount++;
}
}
}
StringRep(int size)
{
u.s.isShort = size<=SHORT_STR_CAPACITY;
if (u.s.isShort) // init short string
{
if (size>0)
{
u.s.len = size-1;
u.s.str[size-1]='\0';
}
else
{
u.s.len = 0;
}
}
else // int long string
{
u.l.d = LSData::create(size);
}
}
StringRep(const char *str)
{
if (str)
{
int len = strlen(str);
u.s.isShort = len<=SHORT_STR_MAX_LEN;
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len+1);
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,u.l.d->len);
}
}
else // create empty string
{
u.s.isShort=TRUE;
u.s.len=0;
}
}
StringRep( const char *str, uint maxlen )
{
if (str && maxlen>0)
{
uint len=strlen(str);
if (len>maxlen) len=maxlen;
u.s.isShort = len<=SHORT_STR_MAX_LEN;
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len);
u.s.str[len]='\0';
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,len);
}
}
else // create empty string
{
u.s.isShort=TRUE;
u.s.len=0;
}
}
StringRep &operator=(const StringRep &s)
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
if (s.u.s.isShort) // copy by value
{
u.s = s.u.s;
}
else // copy by reference
{
u.l.isShort=FALSE;
u.l.d = s.u.l.d;
u.l.d->refCount++;
}
return *this;
}
StringRep &operator=(const char *str)
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
if (str)
{
int len = strlen(str);
u.s.isShort = len<=SHORT_STR_MAX_LEN;
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len+1);
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,u.l.d->len);
}
}
else
{
u.s.isShort=TRUE;
u.s.len=0;
}
return *this;
}
bool isEmpty() const
{
return u.s.isShort && u.s.len==0;
}
uint length() const
{
return u.s.isShort ? u.s.len : u.l.d->len;
}
char *data() const
{
if (u.s.isShort)
{
return u.s.len==0 ? 0 : (char*)u.s.str;
}
else
{
return u.l.d->len==0 ? 0 : u.l.d->toStr();
}
}
char &at(int i) const
{
if (u.s.isShort)
{
return (char&)u.s.str[i];
}
else
{
return u.l.d->toStr()[i];
}
}
bool resize( uint newlen )
{
if (u.s.isShort && newlen<=SHORT_STR_CAPACITY) // resize short string
{
if (newlen>0)
{
u.s.len = newlen-1;
u.s.str[newlen-1]='\0';
}
else // string becomes empty
{
u.s.len = 0;
}
}
else if (u.s.isShort) // turn short string into long string
{
StringRep tmp = *this;
u.s.isShort=FALSE;
u.l.d = LSData::create(newlen);
if (tmp.u.s.len>0)
{
memcpy(u.l.d->toStr(),tmp.u.s.str,tmp.u.s.len+1);
}
else
{
u.l.d->toStr()[0]='\0';
}
}
else if (!u.s.isShort && newlen<=SHORT_STR_CAPACITY) // turn long string into short string
{
if (newlen>0)
{
StringRep tmp(newlen); // copy short part into tmp buffer
memcpy(tmp.u.s.str,u.l.d->toStr(),newlen-1);
tmp.u.s.str[newlen-1]='\0';
u.l.d->dispose();
u.s = tmp.u.s;
}
else
{
u.l.d->dispose();
u.s.isShort=TRUE;
u.s.len=0;
}
}
else // resize long string
{
u.l.d = u.l.d->resize(u.l.d,newlen);
}
return TRUE;
}
bool fill( char c, int len )
{
if (len<0) len=length();
if (len!=(int)length())
{
if (len>0)
{
resize(len+1);
}
else
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
u.s.isShort=TRUE;
u.s.len=0;
}
}
if (len>0)
{
memset(data(),c,len);
}
return TRUE;
}
private:
union
{
ShortStringRep s;
LongStringRep l;
} u;
};
StringRep m_rep;
};
inline char &QCString::at( uint index ) const
{
return m_data[index];
}
inline void QCString::duplicate( const QCString &s )
{
if (!s.isEmpty())
{
uint l = (uint)strlen(s.data());
m_data = (char *)malloc(l+1);
if (m_data) memcpy(m_data,s.data(),l+1);
}
else
{
m_data=0;
}
}
inline void QCString::duplicate( const char *str)
{
if (str && str[0]!='\0')
{
uint l = (uint)strlen(str);
m_data = (char *)malloc(l+1);
if (m_data) memcpy(m_data,str,l+1);
}
else
{
m_data=0;
}
}
inline QCString &QCString::duplicate( const char *str, int)
{
if (m_data==str) return *this;
if (m_data) free(m_data);
duplicate(str);
return *this;
}
/*****************************************************************************
QCString stream functions
*****************************************************************************/
......@@ -326,56 +666,6 @@ Q_EXPORT QDataStream &operator<<( QDataStream &, const QCString & );
Q_EXPORT QDataStream &operator>>( QDataStream &, QCString & );
#endif
/*****************************************************************************
QCString inline functions
*****************************************************************************/
inline QCString &QCString::operator=( const QCString &s )
{ return (QCString&)assign( s ); }
inline QCString &QCString::operator=( const char *str )
{ return (QCString&)duplicate( str, qstrlen(str)+1 ); }
inline bool QCString::isNull() const
{ return data() == 0; }
inline bool QCString::isEmpty() const
{ return data() == 0 || *data() == '\0'; }
inline uint QCString::length() const
{ return qstrlen( data() ); }
inline bool QCString::truncate( uint pos )
{ return resize(pos+1); }
inline QCString QCString::copy() const
{ return QCString( data() ); }
inline QCString &QCString::prepend( const char *s )
{ return insert(0,s); }
inline QCString &QCString::append( const char *s )
{ return operator+=(s); }
inline QCString &QCString::setNum( short n )
{ return setNum((long)n); }
inline QCString &QCString::setNum( ushort n )
{ return setNum((ulong)n); }
inline QCString &QCString::setNum( int n )
{ return setNum((long)n); }
inline QCString &QCString::setNum( uint n )
{ return setNum((ulong)n); }
inline QCString &QCString::setNum( float n, char f, int prec )
{ return setNum((double)n,f,prec); }
inline QCString::operator const char *() const
{ return (const char *)data(); }
/*****************************************************************************
QCString non-member operators
*****************************************************************************/
......@@ -476,5 +766,4 @@ inline const char *qPrint(const QCString &s)
if (!s.isEmpty()) return s.data(); else return "";
}
#endif // QCSTRING_H
......@@ -7,7 +7,6 @@ HEADERS = qarray.h \
qcollection.h \
qconfig.h \
qcstring.h \
scstring.h \
qdatastream.h \
qdatetime.h \
qdict.h \
......@@ -54,7 +53,7 @@ HEADERS = qarray.h \
SOURCES = qbuffer.cpp \
qcollection.cpp \
scstring.cpp \
qcstring.cpp \
qdatastream.cpp \
qdatetime.cpp \
qdir.cpp \
......
/******************************************************************************
*
* Copyright (C) 1997-2004 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
* Documents produced by Doxygen are derivative works derived from the
* input used in their production; they are not affected by this license.
*
*/
#ifndef RCSTRING_H
#define RCSTRING_H
#define RCString QCString
#ifndef QT_H
#include "qarray.h"
#endif // QT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(_OS_WIN32_) || defined(__MINGW32__)
#include <stdint.h>
#endif
#if defined(_OS_SUN_) && defined(_CC_GNU_)
#include <strings.h>
#endif
#include <assert.h>
class QGString;
/*****************************************************************************
Fixes and workarounds for some platforms
*****************************************************************************/
#if defined(_OS_HPUX_)
// HP-UX has badly defined strstr() etc.
// ### fix in 3.0: change hack_* to qt_hack_*
// by the way HP-UX is probably right, the standard has evolved and
// we'll have to adapt to it
inline char *hack_strstr( const char *s1, const char *s2 )
{ return (char *)strstr(s1, s2); }
inline char *hack_strchr( const char *s, int c )
{ return (char *)strchr(s, c); }
inline char *hack_strrchr( const char *s, int c )
{ return (char *)strrchr(s, c); }
#define strstr(s1,s2) hack_strstr((s1),(s2))
#define strchr(s,c) hack_strchr((s),(c))
#define strrchr(s,c) hack_strrchr((s),(c))
#endif
/*****************************************************************************
Safe and portable C string functions; extensions to standard string.h
*****************************************************************************/
Q_EXPORT void *qmemmove( void *dst, const void *src, uint len );
#if defined(_OS_SUN_) || defined(_CC_OC_)
#define memmove(s1,s2,n) qmemmove((s1),(s2),(n))
#endif
#if defined(_OS_WIN32_)
#define qsnprintf _snprintf
#else
#define qsnprintf snprintf
#endif
Q_EXPORT char *qstrdup( const char * );
Q_EXPORT inline uint cstrlen( const char *str )
{ return (uint)strlen(str); }
Q_EXPORT inline uint qstrlen( const char *str )
{ return str ? (uint)strlen(str) : 0; }
Q_EXPORT inline char *cstrcpy( char *dst, const char *src )
{ return strcpy(dst,src); }
Q_EXPORT inline char *qstrcpy( char *dst, const char *src )
{ return src ? strcpy(dst, src) : 0; }
Q_EXPORT char * qstrncpy(char *src,const char *dst, uint len);
Q_EXPORT inline int cstrcmp( const char *str1, const char *str2 )
{ return strcmp(str1,str2); }
Q_EXPORT inline int qstrcmp( const char *str1, const char *str2 )
{ return (str1 && str2) ? strcmp(str1,str2) : (int)((intptr_t)str2 - (intptr_t)str1); }
Q_EXPORT inline int cstrncmp( const char *str1, const char *str2, uint len )
{ return strncmp(str1,str2,len); }
Q_EXPORT inline int qstrncmp( const char *str1, const char *str2, uint len )
{ return (str1 && str2) ? strncmp(str1,str2,len) :
(int)((intptr_t)str2 - (intptr_t)str1); }
Q_EXPORT int qstricmp( const char *str1, const char *str2 );
Q_EXPORT int qstrnicmp( const char *str1, const char *str2, uint len );
/*****************************************************************************
QByteArray class
*****************************************************************************/
#if defined(Q_TEMPLATEDLL)
template class Q_EXPORT QArray<char>;
#endif
typedef QArray<char> QByteArray;
/*****************************************************************************
QByteArray stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
Q_EXPORT QDataStream &operator<<( QDataStream &, const QByteArray & );
Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & );
#endif
class QRegExp;
/** This is an alternative implementation of QCString. It provides basically
* the same functions but uses reference counting and copy on write.
*/
class RCString
{
public:
/** creates an empty string */
RCString()
{
}
/** destroys the string */
~RCString()
{
}
/** makes a copy of a string. */
RCString( const RCString &s ) : m_rep(s.m_rep)
{
}
/** creates a string with room for size characters
* @param[in] size the number of character to allocate (including the 0-terminator)
*/
RCString( int size ) : m_rep(size)
{
}
/** creates a string from a plain C string.
* @param[in] str A zero terminated C string. When 0 an empty string is created.
*/
RCString( const char *str ) : m_rep(str)
{
}
/** creates a string from \a str and copies over the first \a maxlen characters. */
RCString( const char *str, uint maxlen ) : m_rep(str,maxlen)
{
}
/** replaces the contents by that of string \a s. */
RCString &operator=( const RCString &s )
{
m_rep = s.m_rep;
return *this;
}
/** replaces the contents by that of C string \a str. */
RCString &operator=( const char *str)
{
m_rep = str;
return *this;
}
/** Returns TRUE iff the string is empty. Equivalent to isEmpty(). */
bool isNull() const
{
return m_rep.isEmpty();
}
/** Returns TRUE iff the string is empty */
bool isEmpty() const
{
return m_rep.isEmpty();
}
/** Returns the length of the string, excluding the 0-terminator. Equivalent to size(). */
uint length() const
{
return m_rep.length();
}
/** Returns the length of the string, excluding the 0-terminator. */
uint size() const
{
return m_rep.length();
}
/** Returns a pointer to the contents of the string in the form of a 0-terminated C string */
char *data() const
{
return m_rep.data();
}
/** Resizes the string to hold \a newlen characters
* (this value should include the 0-terminator). If the string is enlarged the contents will
* be left unmodified.
*/
bool resize( uint newlen )
{
m_rep.resize(newlen);
return TRUE;
}
/** Truncates the string at position \a pos. */
bool truncate( uint pos )
{
return resize(pos+1);
}
/** Fills a string with a predefined character
* @param[in] c the character used to fill the string with.
* @param[in] len the number of character to fill. Use -1 to fill the whole string.
* @note the string will be resized to contain \a len characters. The contents of the
* string will be lost.
*/
bool fill( char c, int len = -1 )
{
m_rep.fill(c,len);
return TRUE;
}
/** Returns a deep copy of the string. */
RCString copy() const
{
if (length()==0) return RCString();
RCString cs(length()+1);
memcpy(cs.data(),data(),length());
return cs;
}
RCString &sprintf( const char *format, ... );
int find( char c, int index=0, bool cs=TRUE ) const;
int find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const RCString &str, int index=0, bool cs=TRUE ) const;
int find( const QRegExp &rx, int index=0 ) const;
int findRev( char c, int index=-1, bool cs=TRUE) const;
int findRev( const char *str, int index=-1, bool cs=TRUE) const;
int findRev( const QRegExp &rx, int index=-1 ) const;
int contains( char c, bool cs=TRUE ) const;
int contains( const char *str, bool cs=TRUE ) const;
int contains( const QRegExp &rx ) const;
bool stripPrefix(const char *prefix);
RCString left( uint len ) const;
RCString right( uint len ) const;
RCString mid( uint index, uint len=0xffffffff) const;
RCString lower() const;
RCString upper() const;
RCString stripWhiteSpace() const;
RCString simplifyWhiteSpace() const;
RCString &assign( const char *str );
RCString &insert( uint index, const char *s );
RCString &insert( uint index, char c);
RCString &append( const char *s );
RCString &prepend( const char *s );
RCString &remove( uint index, uint len );
RCString &replace( uint index, uint len, const char *s);
RCString &replace( const QRegExp &rx, const char *str );
short toShort( bool *ok=0 ) const;
ushort toUShort( bool *ok=0 ) const;
int toInt( bool *ok=0 ) const;
uint toUInt( bool *ok=0 ) const;
long toLong( bool *ok=0 ) const;
ulong toULong( bool *ok=0 ) const;
RCString &setNum(short n);
RCString &setNum(ushort n);
RCString &setNum(int n);
RCString &setNum(uint n);
RCString &setNum(long n);
RCString &setNum(ulong n);
/** Converts the string to a plain C string */
operator const char *() const
{
return (const char *)data();
}
/** Appends string \a str to this string and returns a reference to the result. */
RCString &operator+=( const char *str )
{
if (!str) return *this;
int len1 = length();
int len2 = strlen(str);
resize(len1+len2+1);
memcpy(data()+len1,str,len2);
return *this;
}
/** Appends character \a c to this string and returns a reference to the result. */
RCString &operator+=( char c )
{
int len = length();
resize(len+2);
data()[len]=c;
return *this;
}
/** Returns a reference to the character at index \a i. */
char &at( uint i) const
{
return m_rep.at(i);
}
/** Indexing operator. Equavalent to at(). */
char &operator[]( int i ) const
{
return m_rep.at((uint)i);
}
private:
struct LSData;
// long string representation
struct LongStringRep
{
uchar isShort : 1; // should be shared with ShortStringRep
uchar : 7;
LSData *d;
};
#define SHORT_STR_CAPACITY ((int)sizeof(LongStringRep)-1)
#define SHORT_STR_MAX_LEN (SHORT_STR_CAPACITY-1)
// short string representation
struct ShortStringRep
{
uchar isShort : 1; // should be shared with LongStringRep
uchar len : 7;
char str[SHORT_STR_CAPACITY]; // size including 0-terminator
};
// ref counting string header
struct LSHeader
{
int len; // length of string without 0 terminator
int refCount; // -1=leaked, 0=one ref & non-cost, n>0, n+1 refs, const
};
// ref counting string data and methods
struct LSData : public LSHeader
{
char *toStr()
{
return (char*)(this+1); // string data starts after the header
}
// creates a LSData item with room for size bytes (which includes the 0 terminator!)
// if size is zero, an empty string will be created.
static LSData *create(int size)
{
LSData *data;
data = (LSData*)malloc(sizeof(LSHeader)+size);
data->len = size-1;
data->refCount = 0;
data->toStr()[size-1] = 0;
return data;
}
// remove out reference to the data. Frees memory if no more users
void dispose()
{
if (--refCount<0) free(this);
}
// resizes LSData so it can hold size bytes (which includes the 0 terminator!)
// if size is zero, the string will become empty
static LSData *resize(LSData *d,int size)
{
if (d->len>0 && d->refCount==0) // non-const, non-empty
{
d = (LSData*)realloc(d,sizeof(LSHeader)+size);
d->len = size-1;
d->toStr()[size-1] = 0;
return d;
}
else // need to make a copy
{
LSData *newData = LSData::create(size);
int len = d->len;
if (len>=size) len=size-1;
memcpy(newData->toStr(),d->toStr(),len);
newData->toStr()[len]=0;
d->dispose();
return newData;
}
}
};
class StringRep
{
public:
StringRep()
{
//printf("%p:StringRep:empty construct\n",this);
u.s.isShort=TRUE;
u.s.len=0;
}
~StringRep()
{
//printf("%p:StringRep:destruct(short=%d) str='%s'\n",this,u.s.isShort,data());
if (!u.s.isShort)
{
u.l.d->dispose();
}
}
StringRep(const StringRep &s)
{
if (&s!=this)
{
//printf("%p:StringRep:copy construct(short=%d)\n",this,s.u.s.isShort);
u = s.u;
if (!u.s.isShort)
{
u.l.d->refCount++;
}
}
}
StringRep(int size)
{
u.s.isShort = size<=SHORT_STR_CAPACITY;
//printf("%p:StringRep:size construct(size=%d,isShort=%d)\n",this,size,u.s.isShort);
if (u.s.isShort) // init short string
{
if (size>0)
{
u.s.len = size-1;
u.s.str[size-1]='\0';
}
else
{
u.s.len = 0;
}
}
else // int long string
{
u.l.d = LSData::create(size);
}
}
StringRep(const char *str)
{
if (str)
{
int len = strlen(str);
u.s.isShort = len<=SHORT_STR_MAX_LEN;
//printf("%p:StringRep:c_str construct(isShort=%d,str='%s')\n",this,u.s.isShort,str);
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len+1);
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,u.l.d->len);
}
}
else // create empty string
{
//printf("%p:StringRep:empty c_str construct\n",this);
u.s.isShort=TRUE;
u.s.len=0;
}
}
StringRep( const char *str, uint maxlen )
{
if (str && maxlen>0)
{
uint len=strlen(str);
if (len>maxlen) len=maxlen;
u.s.isShort = len<=SHORT_STR_MAX_LEN;
//printf("%p:StringRep:c_str maxlen construct(isShort=%d)\n",this,u.s.isShort);
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len);
u.s.str[len]='\0';
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,len);
}
}
else // create empty string
{
//printf("%p:StringRep:empty c_str construct\n",this);
u.s.isShort=TRUE;
u.s.len=0;
}
}
StringRep &operator=(const StringRep &s)
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
if (s.u.s.isShort) // copy by value
{
//printf("%p:StringRep:operator=(short) s='%s'\n",this,s.data());
u.s = s.u.s;
}
else // copy by reference
{
//printf("%p:StringRep:operator=(long) s='%s'\n",this,s.data());
u.l.isShort=FALSE;
u.l.d = s.u.l.d;
u.l.d->refCount++;
}
return *this;
}
StringRep &operator=(const char *str)
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
if (str)
{
int len = strlen(str);
u.s.isShort = len<=SHORT_STR_MAX_LEN;
//printf("%p:StringRep:operator=(c_str) isShort=%d\n",this,u.s.isShort);
if (u.s.isShort)
{
u.s.len = len;
memcpy(u.s.str,str,len+1);
}
else
{
u.l.d = LSData::create(len+1);
memcpy(u.l.d->toStr(),str,u.l.d->len);
}
}
else
{
//printf("%p:StringRep:operator=(empty c_str)\n",this);
u.s.isShort=TRUE;
u.s.len=0;
}
return *this;
}
bool isEmpty() const
{
return u.s.isShort && u.s.len==0;
}
uint length() const
{
return u.s.isShort ? u.s.len : u.l.d->len;
}
char *data() const
{
if (u.s.isShort)
{
return u.s.len==0 ? 0 : (char*)u.s.str;
}
else
{
return u.l.d->len==0 ? 0 : u.l.d->toStr();
}
}
char &at(int i) const
{
if (u.s.isShort)
{
return (char&)u.s.str[i];
}
else
{
return u.l.d->toStr()[i];
}
}
bool resize( uint newlen )
{
if (u.s.isShort && newlen<=SHORT_STR_CAPACITY) // resize short string
{
if (newlen>0)
{
//printf("%p:StringRep:resize short2short\n",this);
u.s.len = newlen-1;
u.s.str[newlen-1]='\0';
}
else
{
//printf("%p:StringRep:resize short2empty\n",this);
u.s.len = 0;
}
}
else if (u.s.isShort) // turn short string into long string
{
//printf("%p:StringRep:resize short2long\n",this);
StringRep tmp = *this;
u.s.isShort=FALSE;
u.l.d = LSData::create(newlen);
if (tmp.u.s.len>0)
{
memcpy(u.l.d->toStr(),tmp.u.s.str,tmp.u.s.len+1);
}
else
{
u.l.d->toStr()[0]='\0';
}
}
else if (!u.s.isShort && newlen<=SHORT_STR_CAPACITY) // turn long string into short string
{
if (newlen>0)
{
//printf("%p:StringRep:resize long2short\n",this);
StringRep tmp(newlen); // copy short part into tmp buffer
memcpy(tmp.u.s.str,u.l.d->toStr(),newlen-1);
tmp.u.s.str[newlen-1]='\0';
u.l.d->dispose();
u.s = tmp.u.s;
}
else
{
//printf("%p:StringRep:resize long2empty\n",this);
u.l.d->dispose();
u.s.isShort=TRUE;
u.s.len=0;
}
}
else // resize long string
{
//printf("%p:StringRep:resize long2long\n",this);
u.l.d = u.l.d->resize(u.l.d,newlen);
}
return TRUE;
}
bool fill( char c, int len )
{
if (len<0) len=length();
if (len!=(int)length())
{
if (len>0)
{
resize(len+1);
}
else
{
if (!u.s.isShort)
{
u.l.d->dispose();
}
u.s.isShort=TRUE;
u.s.len=0;
}
}
if (len>0)
{
memset(data(),c,len);
}
return TRUE;
}
private:
union
{
ShortStringRep s;
LongStringRep l;
} u;
};
StringRep m_rep;
};
/*****************************************************************************
QCString stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
Q_EXPORT QDataStream &operator<<( QDataStream &, const QCString & );
Q_EXPORT QDataStream &operator>>( QDataStream &, QCString & );
#endif
/*****************************************************************************
RCString non-member operators
*****************************************************************************/
Q_EXPORT inline bool operator==( const RCString &s1, const RCString &s2 )
{ return qstrcmp(s1.data(),s2.data()) == 0; }
Q_EXPORT inline bool operator==( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) == 0; }
Q_EXPORT inline bool operator==( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) == 0; }
Q_EXPORT inline bool operator!=( const RCString &s1, const RCString &s2 )
{ return qstrcmp(s1.data(),s2.data()) != 0; }
Q_EXPORT inline bool operator!=( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) != 0; }
Q_EXPORT inline bool operator!=( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) != 0; }
Q_EXPORT inline bool operator<( const RCString &s1, const RCString& s2 )
{ return qstrcmp(s1.data(),s2.data()) < 0; }
Q_EXPORT inline bool operator<( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) < 0; }
Q_EXPORT inline bool operator<( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) < 0; }
Q_EXPORT inline bool operator<=( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) <= 0; }
Q_EXPORT inline bool operator<=( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) <= 0; }
Q_EXPORT inline bool operator>( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) > 0; }
Q_EXPORT inline bool operator>( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) > 0; }
Q_EXPORT inline bool operator>=( const RCString &s1, const char *s2 )
{ return qstrcmp(s1.data(),s2) >= 0; }
Q_EXPORT inline bool operator>=( const char *s1, const RCString &s2 )
{ return qstrcmp(s1,s2.data()) >= 0; }
Q_EXPORT inline RCString operator+( const RCString &s1, const RCString &s2 )
{
RCString tmp(s1);
tmp += s2;
return tmp;
}
inline RCString operator+( const RCString &s1, const QGString &s2 );
inline RCString operator+( const QGString &s1, const RCString &s2 );
Q_EXPORT inline RCString operator+( const RCString &s1, const char *s2 )
{
RCString tmp(s1);
tmp += s2;
return tmp;
}
Q_EXPORT inline RCString operator+( const char *s1, const RCString &s2 )
{
RCString tmp(s1);
tmp += s2;
return tmp;
}
Q_EXPORT inline RCString operator+( const RCString &s1, char c2 )
{
RCString tmp( s1.data() );
tmp += c2;
return tmp;
}
Q_EXPORT inline RCString operator+( char c1, const RCString &s2 )
{
RCString tmp;
tmp += c1;
tmp += s2;
return tmp;
}
inline const char *qPrint(const char *s)
{
if (s) return s; else return "";
}
inline const char *qPrint(const RCString &s)
{
if (!s.isEmpty()) return s.data(); else return "";
}
#endif
/******************************************************************************
*
* Copyright (C) 1997-2004 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
* Documents produced by Doxygen are derivative works derived from the
* input used in their production; they are not affected by this license.
*
*/
// with this switch you can choose between the original qcstring implementation,
// which implicitly shares data so copying is faster, but requires at least 12 bytes, and
// the new implementation in this file, which has a smaller footprint (only 4 bytes for
// an empty string), but always copies strings.
#define SMALLSTRING
#include "qcstring.h"
#ifndef SMALLSTRING
#include "qcstring.cpp"
#else
#define SCString QCString
#include <qstring.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <qregexp.h>
#include <qdatastream.h>
SCString::SCString(int size)
{
if (size>0)
{
m_data = (char *)malloc(size);
if (m_data)
{
if (size>1) memset(m_data,' ',size-1);
m_data[size-1]='\0';
}
}
else
{
m_data=0;
}
}
SCString::SCString( const SCString &s )
{
duplicate(s);
}
SCString::SCString( const char *str )
{
duplicate(str);
}
SCString::SCString( const char *str, uint maxlen )
{
uint l;
if (str && ( l = QMIN(qstrlen(str),maxlen) ))
{
m_data=(char *)malloc(l+1);
strncpy(m_data,str,l+1);
m_data[l]='\0';
}
else
{
m_data=0;
}
}
SCString::~SCString()
{
if (m_data) free(m_data);
m_data=0;
}
SCString &SCString::assign( const char *str )
{
if (m_data==str) return *this;
if (m_data) free(m_data);
duplicate(str);
return *this;
}
bool SCString::resize( uint newlen )
{
if (newlen==0)
{
if (m_data) { free(m_data); m_data=0; }
return TRUE;
}
if (m_data==0) // newlen>0
{
m_data = (char *)malloc(newlen);
}
else
{
m_data = (char *)realloc(m_data,newlen);
}
if (m_data==0) return FALSE;
m_data[newlen-1]='\0';
return TRUE;
}
bool SCString::fill( char c, int len )
{
uint l=length();
if (len<0) len=l;
if ((uint)len!=l)
{
if (m_data) free(m_data);
if (len>0)
{
m_data=(char *)malloc(len+1);
if (m_data==0) return FALSE;
m_data[len]='\0';
}
else
{
m_data=0;
}
}
if (len>0)
{
uint i;
for (i=0;i<(uint)len;i++) m_data[i]=c;
}
return TRUE;
}
SCString &SCString::sprintf( const char *format, ... )
{
va_list ap;
va_start( ap, format );
uint l = length();
const uint minlen=4095;
if (l<minlen)
{
if (m_data)
m_data = (char *)realloc(m_data,minlen+1);
else
m_data = (char *)malloc(minlen+1);
m_data[minlen]='\0';
}
vsnprintf( m_data, minlen, format, ap );
resize( qstrlen(m_data) + 1 ); // truncate
va_end( ap );
return *this;
}
int SCString::find( char c, int index, bool cs ) const
{
uint len = length();
if ( m_data==0 || (uint)index>len ) // index outside string
return -1;
register const char *d;
if ( cs ) // case sensitive
{
d = strchr( m_data+index, c );
}
else
{
d = m_data+index;
c = tolower( (uchar) c );
while ( *d && tolower((uchar) *d) != c )
d++;
if ( !*d && c ) // not found
d = 0;
}
return d ? (int)(d - m_data) : -1;
}
int SCString::find( const char *str, int index, bool cs ) const
{
uint l = length();
if ( m_data==0 || (uint)index > l ) // index outside string
return -1;
if ( !str ) // no search string
return -1;
if ( !*str ) // zero-length search string
return index;
register const char *d;
if ( cs ) // case sensitive
{
d = strstr( m_data+index, str );
}
else // case insensitive
{
d = m_data+index;
int len = qstrlen( str );
while ( *d )
{
if ( qstrnicmp(d, str, len) == 0 )
break;
d++;
}
if ( !*d ) // not found
d = 0;
}
return d ? (int)(d - m_data) : -1;
}
int SCString::find( const QCString &str, int index, bool cs ) const
{
return find(str.data(),index,cs);
}
int SCString::find( const QRegExp &rx, int index ) const
{
QString d = QString::fromLatin1( m_data );
return d.find( rx, index );
}
int SCString::findRev( char c, int index, bool cs) const
{
const char *b = m_data;
const char *d;
uint len = length();
if ( b == 0 ) return -1; // empty string
if ( index < 0 ) // neg index ==> start from end
{
if ( len == 0 ) return -1;
if ( cs )
{
d = strrchr( b, c );
return d ? (int)(d - b) : -1;
}
index = len;
}
else if ( (uint)index > len ) // bad index
{
return -1;
}
d = b+index;
if ( cs ) // case sensitive
{
while ( d >= b && *d != c )
d--;
}
else // case insensitive
{
c = tolower( (uchar) c );
while ( d >= b && tolower((uchar) *d) != c )
d--;
}
return d >= b ? (int)(d - b) : -1;
}
int SCString::findRev( const char *str, int index, bool cs) const
{
int slen = qstrlen(str);
uint len = length();
if ( index < 0 ) // neg index ==> start from end
index = len-slen;
else if ( (uint)index > len ) // bad index
return -1;
else if ( (uint)(index + slen) > len ) // str would be too long
index = len - slen;
if ( index < 0 )
return -1;
register char *d = m_data + index;
if ( cs ) // case sensitive
{
for ( int i=index; i>=0; i-- )
if ( qstrncmp(d--,str,slen)==0 )
return i;
}
else // case insensitive
{
for ( int i=index; i>=0; i-- )
if ( qstrnicmp(d--,str,slen)==0 )
return i;
}
return -1;
}
int SCString::findRev( const QRegExp &rx, int index ) const
{
QString d = QString::fromLatin1( m_data );
return d.findRev( rx, index );
}
int SCString::contains( char c, bool cs ) const
{
int count = 0;
char *d = m_data;
if ( !d )
return 0;
if ( cs ) // case sensitive
{
while ( *d )
if ( *d++ == c )
count++;
}
else // case insensitive
{
c = tolower( (uchar) c );
while ( *d ) {
if ( tolower((uchar) *d) == c )
count++;
d++;
}
}
return count;
}
int SCString::contains( const char *str, bool cs ) const
{
int count = 0;
char *d = data();
if ( !d )
return 0;
int len = qstrlen( str );
while ( *d ) // counts overlapping strings
{
if ( cs )
{
if ( qstrncmp( d, str, len ) == 0 )
count++;
}
else
{
if ( qstrnicmp(d, str, len) == 0 )
count++;
}
d++;
}
return count;
}
int SCString::contains( const QRegExp &rx ) const
{
QString d = QString::fromLatin1( m_data );
return d.contains( rx );
}
SCString SCString::left( uint len ) const
{
if ( isEmpty() )
{
return SCString();
}
else if ( len >= length() )
{
return *this;
}
else
{
SCString s( len+1 );
strncpy( s.data(), m_data, len );
*(s.data()+len) = '\0';
return s;
}
}
SCString SCString::right( uint len ) const
{
if ( isEmpty() )
{
return SCString();
}
else
{
uint l = length();
if ( len > l ) len = l;
char *p = m_data + (l - len);
return SCString( p );
}
}
SCString SCString::mid( uint index, uint len) const
{
uint slen = length();
if ( len == 0xffffffff ) len = slen-index;
if ( isEmpty() || index >= slen )
{
return SCString();
}
else
{
register char *p = data()+index;
SCString s( len+1 );
strncpy( s.data(), p, len );
*(s.data()+len) = '\0';
return s;
}
}
SCString SCString::lower() const
{
SCString s( m_data );
register char *p = s.data();
if ( p )
{
while ( *p )
{
*p = tolower((uchar) *p);
p++;
}
}
return s;
}
SCString SCString::upper() const
{
SCString s( m_data );
register char *p = s.data();
if ( p ) {
while ( *p ) {
*p = toupper((uchar)*p);
p++;
}
}
return s;
}
SCString SCString::stripWhiteSpace() const
{
if ( isEmpty() ) // nothing to do
return *this;
register char *s = m_data;
int reslen = length();
if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) )
return *this; // returns a copy
SCString result(s);
s = result.data();
int start = 0;
int end = reslen - 1;
while ( isspace((uchar) s[start]) ) // skip white space from start
start++;
if ( s[start] == '\0' )
{ // only white space
return SCString();
}
while ( end && isspace((uchar) s[end]) ) // skip white space from end
end--;
end -= start - 1;
memmove( result.data(), &s[start], end );
result.resize( end + 1 );
return result;
}
SCString SCString::simplifyWhiteSpace() const
{
if ( isEmpty() ) // nothing to do
return *this;
SCString result( length()+1 );
char *from = data();
char *to = result.data();
char *first = to;
while ( TRUE )
{
while ( *from && isspace((uchar) *from) )
from++;
while ( *from && !isspace((uchar)*from) )
*to++ = *from++;
if ( *from )
*to++ = 0x20; // ' '
else
break;
}
if ( to > first && *(to-1) == 0x20 )
to--;
*to = '\0';
result.resize( (int)((long)to - (long)result.data()) + 1 );
return result;
}
SCString &SCString::insert( uint index, const char *s )
{
int len = qstrlen(s);
if ( len == 0 )
return *this;
uint olen = length();
int nlen = olen + len;
if ( index >= olen ) // insert after end of string
{
m_data = (char *)realloc(m_data,nlen+index-olen+1);
if ( m_data )
{
memset( m_data+olen, ' ', index-olen );
memcpy( m_data+index, s, len+1 );
}
}
else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert
{
memmove( m_data+index+len, m_data+index, olen-index+1 );
memcpy( m_data+index, s, len );
}
return *this;
}
SCString &SCString::insert( uint index, char c ) // insert char
{
char buf[2];
buf[0] = c;
buf[1] = '\0';
return insert( index, buf );
}
SCString& SCString::operator+=( const char *str )
{
if ( !str ) return *this; // nothing to append
uint len1 = length();
uint len2 = qstrlen(str);
char *newData = (char *)realloc( m_data, len1 + len2 + 1 );
if (newData)
{
m_data = newData;
memcpy( m_data + len1, str, len2 + 1 );
}
return *this;
}
SCString &SCString::operator+=( char c )
{
uint len = length();
char *newData = (char *)realloc( m_data, length()+2 );
if (newData)
{
m_data = newData;
m_data[len] = c;
m_data[len+1] = '\0';
}
return *this;
}
SCString &SCString::remove( uint index, uint len )
{
uint olen = length();
if ( index + len >= olen ) // range problems
{
if ( index < olen ) // index ok
{
resize( index+1 );
}
}
else if ( len != 0 )
{
memmove( m_data+index, m_data+index+len, olen-index-len+1 );
resize( olen-len+1 );
}
return *this;
}
SCString &SCString::replace( uint index, uint len, const char *s )
{
remove( index, len );
insert( index, s );
return *this;
}
SCString &SCString::replace( const QRegExp &rx, const char *str )
{
QString d = QString::fromLatin1( m_data );
QString r = QString::fromLatin1( str );
d.replace( rx, r );
return assign(d.ascii());
}
long SCString::toLong( bool *ok ) const
{
QString s(m_data);
return s.toLong(ok);
}
ulong SCString::toULong( bool *ok ) const
{
QString s(m_data);
return s.toULong(ok);
}
short SCString::toShort( bool *ok ) const
{
QString s(m_data);
return s.toShort(ok);
}
ushort SCString::toUShort( bool *ok ) const
{
QString s(m_data);
return s.toUShort(ok);
}
int SCString::toInt( bool *ok ) const
{
QString s(m_data);
return s.toInt(ok);
}
uint SCString::toUInt( bool *ok ) const
{
QString s(m_data);
return s.toUInt(ok);
}
SCString &SCString::setNum( long n )
{
char buf[20];
register char *p = &buf[19];
bool neg;
if ( n < 0 )
{
neg = TRUE;
n = -n;
}
else
{
neg = FALSE;
}
*p = '\0';
do
{
*--p = ((int)(n%10)) + '0';
n /= 10;
} while ( n );
if ( neg ) *--p = '-';
operator=( p );
return *this;
}
SCString &SCString::setNum( ulong n )
{
char buf[20];
register char *p = &buf[19];
*p = '\0';
do
{
*--p = ((int)(n%10)) + '0';
n /= 10;
} while ( n );
operator=( p );
return *this;
}
void SCString::msg_index( uint index )
{
#if defined(CHECK_RANGE)
qWarning( "SCString::at: Absolute index %d out of range", index );
#else
Q_UNUSED( index )
#endif
}
bool SCString::stripPrefix(const char *prefix)
{
if (prefix==0) return FALSE;
uint plen = qstrlen(prefix);
if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches
{
uint len = qstrlen(m_data);
uint newlen = len-plen+1;
qmemmove(m_data,m_data+plen,newlen);
resize(newlen);
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
void *qmemmove( void *dst, const void *src, uint len )
{
register char *d;
register char *s;
if ( dst > src ) {
d = (char *)dst + len - 1;
s = (char *)src + len - 1;
while ( len-- )
*d-- = *s--;
} else if ( dst < src ) {
d = (char *)dst;
s = (char *)src;
while ( len-- )
*d++ = *s++;
}
return dst;
}
char *qstrdup( const char *str )
{
if ( !str )
return 0;
char *dst = new char[strlen(str)+1];
CHECK_PTR( dst );
return strcpy( dst, str );
}
char *qstrncpy( char *dst, const char *src, uint len )
{
if ( !src )
return 0;
strncpy( dst, src, len );
if ( len > 0 )
dst[len-1] = '\0';
return dst;
}
int qstricmp( const char *str1, const char *str2 )
{
register const uchar *s1 = (const uchar *)str1;
register const uchar *s2 = (const uchar *)str2;
int res;
uchar c;
if ( !s1 || !s2 )
return s1 == s2 ? 0 : (int)((long)s2 - (long)s1);
for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ )
if ( !c ) // strings are equal
break;
return res;
}
int qstrnicmp( const char *str1, const char *str2, uint len )
{
register const uchar *s1 = (const uchar *)str1;
register const uchar *s2 = (const uchar *)str2;
int res;
uchar c;
if ( !s1 || !s2 )
return (int)((long)s2 - (long)s1);
for ( ; len--; s1++, s2++ ) {
if ( (res = (c=tolower(*s1)) - tolower(*s2)) )
return res;
if ( !c ) // strings are equal
break;
}
return 0;
}
#ifndef QT_NO_DATASTREAM
QDataStream &operator<<( QDataStream &s, const QByteArray &a )
{
return s.writeBytes( a.data(), a.size() );
}
QDataStream &operator>>( QDataStream &s, QByteArray &a )
{
Q_UINT32 len;
s >> len; // read size of array
if ( len == 0 || s.eof() ) { // end of file reached
a.resize( 0 );
return s;
}
if ( !a.resize( (uint)len ) ) { // resize array
#if defined(CHECK_NULL)
qWarning( "QDataStream: Not enough memory to read QByteArray" );
#endif
len = 0;
}
if ( len > 0 ) // not null array
s.readRawBytes( a.data(), (uint)len );
return s;
}
QDataStream &operator<<( QDataStream &s, const SCString &str )
{
return s.writeBytes( str.data(), str.size() );
}
QDataStream &operator>>( QDataStream &s, SCString &str )
{
Q_UINT32 len;
s >> len; // read size of string
if ( len == 0 || s.eof() ) { // end of file reached
str.resize( 0 );
return s;
}
if ( !str.resize( (uint)len )) {// resize string
#if defined(CHECK_NULL)
qWarning( "QDataStream: Not enough memory to read QCString" );
#endif
len = 0;
}
if ( len > 0 ) // not null array
s.readRawBytes( str.data(), (uint)len );
return s;
}
#endif //QT_NO_DATASTREAM
#endif
/******************************************************************************
*
* Copyright (C) 1997-2004 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
* granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
* Documents produced by Doxygen are derivative works derived from the
* input used in their production; they are not affected by this license.
*
*/
#ifndef SCSTRING_H
#define SCSTRING_H
#include <stdlib.h>
class QRegExp;
/** This is an alternative implementation of QCString. It provides basically
* the same functions but uses less memory for administration. This class
* is just a wrapper around a plain C string requiring only 4 bytes "overhead".
* QCString features sharing of data and stores the string length, but
* requires 4 + 12 bytes for this (even for the empty string). As doxygen
* uses a LOT of string during a run it saves a lot of memory to use a
* more memory efficient implementation at the cost of relatively low
* runtime overhead.
*/
class SCString
{
public:
SCString() : m_data(0) {} // make null string
SCString( const SCString &s );
SCString( int size );
SCString( const char *str );
SCString( const char *str, uint maxlen );
~SCString();
SCString &operator=( const SCString &s );// deep copy
SCString &operator=( const char *str ); // deep copy
bool isNull() const;
bool isEmpty() const;
uint length() const;
uint size() const { return m_data ? length()+1 : 0; }
char * data() const { return m_data; }
bool resize( uint newlen );
bool truncate( uint pos );
bool fill( char c, int len = -1 );
SCString copy() const;
SCString &sprintf( const char *format, ... );
int find( char c, int index=0, bool cs=TRUE ) const;
int find( const char *str, int index=0, bool cs=TRUE ) const;
int find( const QRegExp &, int index=0 ) const;
int find( const QCString &str, int index, bool cs ) const;
int findRev( char c, int index=-1, bool cs=TRUE) const;
int findRev( const char *str, int index=-1, bool cs=TRUE) const;
int findRev( const QRegExp &, int index=-1 ) const;
int contains( char c, bool cs=TRUE ) const;
int contains( const char *str, bool cs=TRUE ) const;
int contains( const QRegExp & ) const;
bool stripPrefix(const char *prefix);
SCString left( uint len ) const;
SCString right( uint len ) const;
SCString mid( uint index, uint len=0xffffffff) const;
SCString lower() const;
SCString upper() const;
SCString stripWhiteSpace() const;
SCString simplifyWhiteSpace() const;
SCString &assign( const char *str );
SCString &insert( uint index, const char * );
SCString &insert( uint index, char );
SCString &append( const char *s );
SCString &prepend( const char *s );
SCString &remove( uint index, uint len );
SCString &replace( uint index, uint len, const char * );
SCString &replace( const QRegExp &, const char * );
short toShort( bool *ok=0 ) const;
ushort toUShort( bool *ok=0 ) const;
int toInt( bool *ok=0 ) const;
uint toUInt( bool *ok=0 ) const;
long toLong( bool *ok=0 ) const;
ulong toULong( bool *ok=0 ) const;
SCString &setNum( short );
SCString &setNum( ushort );
SCString &setNum( int );
SCString &setNum( uint );
SCString &setNum( long );
SCString &setNum( ulong );
QCString &setNum( float, char f='g', int prec=6 );
QCString &setNum( double, char f='g', int prec=6 );
operator const char *() const;
SCString &operator+=( const char *str );
SCString &operator+=( char c );
char &at( uint index ) const;
char &operator[]( int i ) const { return at(i); }
private:
static void msg_index( uint );
void duplicate( const SCString &s );
void duplicate( const char *str);
SCString &duplicate( const char *str, int);
char * m_data;
};
inline char &SCString::at( uint index ) const
{
return m_data[index];
}
inline void SCString::duplicate( const SCString &s )
{
if (!s.isEmpty())
{
uint l = strlen(s.data());
m_data = (char *)malloc(l+1);
if (m_data) memcpy(m_data,s.data(),l+1);
}
else
m_data=0;
}
inline void SCString::duplicate( const char *str)
{
if (str && str[0]!='\0')
{
uint l = strlen(str);
m_data = (char *)malloc(l+1);
if (m_data) memcpy(m_data,str,l+1);
}
else
m_data=0;
}
inline SCString &SCString::duplicate( const char *str, int)
{
if (m_data) free(m_data);
duplicate(str);
return *this;
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment