From 7d933a9f99dacb83937534719103218470e2a5ab Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Tue, 21 Oct 2014 22:19:39 +0200 Subject: Reverted back to old string implementation. New one needs more work. --- qtools/qcstring.cpp | 620 ++++++++++++++++++++++++--------------- qtools/qcstring.h | 786 ++++++++++++++++---------------------------------- qtools/qtools.pro.in | 3 +- qtools/scstring.cpp | 798 +++++++++++++++++++++++++++++++++++++++++++++++++++ qtools/scstring.h | 155 ++++++++++ 5 files changed, 1583 insertions(+), 779 deletions(-) create mode 100644 qtools/scstring.cpp create mode 100644 qtools/scstring.h diff --git a/qtools/qcstring.cpp b/qtools/qcstring.cpp index 7bf6f50..4038d55 100644 --- a/qtools/qcstring.cpp +++ b/qtools/qcstring.cpp @@ -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,148 +24,281 @@ #include #include -QCString &QCString::sprintf( const char *format, ... ) + +QCString::QCString(int size) { - va_list ap; - va_start( ap, format ); - const int minlen=256; - if (length()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 ) +{ + if (m_data) free(m_data); + duplicate(str); return *this; } -int QCString::find( char c, int index, bool cs ) const +bool QCString::resize( uint newlen ) { - if (index<0 || index>=(int)length()) return -1; // index outside string - register const char *pos; - if (cs) + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + return TRUE; + } + if (m_data==0) // newlen>0 { - pos = strchr(data()+index,c); + m_data = (char *)malloc(newlen); } else { - pos = data()+index; - c = tolower((unsigned char)c); - while (*pos && tolower((unsigned char)*pos)!=c) pos++; - if (!*pos && c) pos=0; // not found + m_data = (char *)realloc(m_data,newlen); } - return pos ? (int)(pos - data()) : -1; + if (m_data==0) return FALSE; + m_data[newlen-1]='\0'; + return TRUE; } -int QCString::find( const char *str, int index, bool cs ) const +bool QCString::fill( char c, int len ) { - 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 + uint l=length(); + if (len<0) len=l; + if ((uint)len!=l) { - pos = strstr(data()+index,str); + 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; + } } - else // case insensitive + if (len>0) { - pos = data(); - int len = strlen(str); - while (*pos) + 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 (llen ) // 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 ) { - if (strncasecmp(pos,str,len)==0) break; - pos++; + if ( qstrnicmp(d, str, len) == 0 ) + break; + d++; } - if (!*pos) pos = 0; // not found + if ( !*d ) // not found + d = 0; } - return pos ? (int)(pos - data()) : -1; + return d ? (int)(d - m_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( data() ); + QString d = QString::fromLatin1( m_data ); return d.find( rx, index ); } int QCString::findRev( char c, int index, bool cs) const { -// 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 + 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 (cs) + if ( len == 0 ) return -1; + if ( cs ) { - pos = strrchr(b,c); - return pos ? (int)(pos - b) : -1; + d = strrchr( b, c ); + return d ? (int)(d - b) : -1; } - index=len; - } - else if (index>len) // bad index - { + index = len; + } + else if ( (uint)index > len ) // bad index + { return -1; } - pos = b+index; - if (cs) + d = b+index; + if ( cs ) // case sensitive { - while ( pos>=b && *pos!=c) pos--; - } - else + while ( d >= b && *d != c ) + d--; + } + else // case insensitive { - c = tolower((unsigned char)c); - while ( pos>=b && tolower((unsigned char)*pos)!=c) pos--; + c = tolower( (uchar) c ); + while ( d >= b && tolower((uchar) *d) != c ) + d--; } - //printf("pos=%p b=%p diff=%d\n",pos,b,(int)(pos-b)); - return pos>=b ? (int)(pos - b) : -1; + return d >= b ? (int)(d - b) : -1; } int QCString::findRev( const char *str, int index, bool cs) const { - 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; + 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 QCString::findRev( const QRegExp &rx, int index ) const { - QString d = QString::fromLatin1( data() ); + QString d = QString::fromLatin1( m_data ); return d.findRev( rx, index ); } int QCString::contains( char c, bool cs ) const { - 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++; + 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; @@ -173,106 +306,96 @@ int QCString::contains( char c, bool cs ) const int QCString::contains( const char *str, bool cs ) const { - if (str==0 || length()==0) return 0; - int count=0; - const char *pos = data(); - int len = strlen(str); - while (*pos) + int count = 0; + char *d = data(); + if ( !d ) + return 0; + int len = qstrlen( str ); + while ( *d ) // counts overlapping strings { - if (cs) + if ( cs ) { - if (strncmp(pos,str,len)==0) count++; - } - else + if ( qstrncmp( d, str, len ) == 0 ) + count++; + } + else { - if (strncasecmp(pos,str,len)==0) count++; + if ( qstrnicmp(d, str, len) == 0 ) + count++; } - pos++; + d++; } return count; } int QCString::contains( const QRegExp &rx ) const -{ - QString d = QString::fromLatin1( data() ); +{ + QString d = QString::fromLatin1( m_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 QCString(data()); - } - else + return *this; + } + else { QCString s( len+1 ); - memcpy( s.data(), data(), len); + strncpy( s.data(), m_data, len ); + *(s.data()+len) = '\0'; return s; } } QCString QCString::right( uint len ) const { - if (isEmpty()) + if ( isEmpty() ) { return QCString(); - } - else + } + else { - int l = length(); - if ((int)len>l) len=l; - const char *pos = data() + (l-len); - return QCString(pos); - } + uint l = length(); + if ( len > l ) len = l; + char *p = m_data + (l - len); + return QCString( p ); + } } QCString QCString::mid( uint index, uint len) const { - int slen = length(); - if (len==0xffffffff) len = slen-index; - if (isEmpty() || (int)index>=slen) + uint slen = length(); + if ( len == 0xffffffff ) len = slen-index; + if ( isEmpty() || index >= slen ) { return QCString(); - } - else + } + else { register char *p = data()+index; - QCString s(len+1); - memcpy(s.data(),p,len); + QCString s( len+1 ); + strncpy( s.data(), p, len ); + *(s.data()+len) = '\0'; return s; } } QCString QCString::lower() const { - if (length()==0) return QCString(); - QCString s(data()); - register char *pos = s.data(); - if (pos) + QCString s( m_data ); + register char *p = s.data(); + if ( p ) { - while (*pos) + while ( *p ) { - *pos = tolower((unsigned char)*pos); - pos++; + *p = tolower((uchar) *p); + p++; } } return s; @@ -280,44 +403,41 @@ QCString QCString::lower() const QCString QCString::upper() const { - if (length()==0) return QCString(); - QCString s(data()); - register char *pos = s.data(); - if (pos) - { - while (*pos) - { - *pos = toupper((unsigned char)*pos); - pos++; + QCString s( m_data ); + register char *p = s.data(); + if ( p ) { + while ( *p ) { + *p = toupper((uchar)*p); + p++; } } return s; } -QCString QCString::stripWhiteSpace() const +QCString QCString::stripWhiteSpace() const { if ( isEmpty() ) // nothing to do return *this; - register char *s = data(); + register char *s = m_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; - qmemmove( result.data(), &s[start], end ); + memmove( result.data(), &s[start], end ); result.resize( end + 1 ); return result; } @@ -331,7 +451,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++; @@ -349,66 +469,84 @@ 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; - 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); + 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; } -QCString &QCString::insert( uint index, char c) +QCString &QCString::insert( uint index, char c ) // insert char { char buf[2]; buf[0] = c; buf[1] = '\0'; return insert( index, buf ); } -QCString &QCString::append( const char *s ) + +QCString& QCString::operator+=( const char *str ) { - return operator+=(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; } -QCString &QCString::prepend( const char *s ) + +QCString &QCString::operator+=( char c ) { - return insert(0,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; } + 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 ) { - qmemmove( data()+index, data()+index+len, olen-index-len+1 ); + memmove( m_data+index, m_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 ); @@ -417,85 +555,65 @@ QCString &QCString::replace( uint index, uint len, const char *s) QCString &QCString::replace( const QRegExp &rx, const char *str ) { - QString d = QString::fromLatin1( data() ); + QString d = QString::fromLatin1( m_data ); QString r = QString::fromLatin1( str ); d.replace( rx, r ); operator=( d.ascii() ); return *this; } -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 +long QCString::toLong( bool *ok ) const { - QString s(data()); + QString s(m_data); return s.toLong(ok); } -ulong QCString::toULong(bool *ok) const +ulong QCString::toULong( bool *ok ) const { - QString s(data()); + QString s(m_data); return s.toULong(ok); } -QCString &QCString::setNum(short n) +short QCString::toShort( bool *ok ) const { - return setNum((long)n); + QString s(m_data); + return s.toShort(ok); } -QCString &QCString::setNum(ushort n) +ushort QCString::toUShort( bool *ok ) const { - return setNum((ulong)n); + QString s(m_data); + return s.toUShort(ok); } -QCString &QCString::setNum(int n) +int QCString::toInt( bool *ok ) const { - return setNum((long)n); + QString s(m_data); + return s.toInt(ok); } -QCString &QCString::setNum(uint n) +uint QCString::toUInt( bool *ok ) const { - return setNum((ulong)n); + QString s(m_data); + return s.toUInt(ok); } -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; @@ -505,12 +623,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; @@ -519,7 +637,31 @@ 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 ) { diff --git a/qtools/qcstring.h b/qtools/qcstring.h index 8acd9ff..f7d2c95 100644 --- a/qtools/qcstring.h +++ b/qtools/qcstring.h @@ -1,16 +1,38 @@ /**************************************************************************** +** ** -** Copyright (C) 1997-2004 by Dimitri van Heesch. +** Definition of the extended char array operations, +** and QByteArray and QCString classes ** -** 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. +** Created : 920609 ** -** 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. +** 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. ** **********************************************************************/ @@ -21,7 +43,6 @@ #include "qarray.h" #endif // QT_H -#include #include #include @@ -33,7 +54,6 @@ #include #endif -#include class QGString; @@ -57,6 +77,7 @@ 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 *****************************************************************************/ @@ -106,6 +127,39 @@ 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 *****************************************************************************/ @@ -115,6 +169,7 @@ template class Q_EXPORT QArray; #endif typedef QArray QByteArray; + /***************************************************************************** QByteArray stream functions *****************************************************************************/ @@ -126,541 +181,143 @@ Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & ); class QRegExp; /** This is an alternative implementation of QCString. It provides basically - * the same functions but uses reference counting and copy on write. + * 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 QCString +class QCString { public: - /** 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); - } - + 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); } + private: + static void msg_index( uint ); + void duplicate( const QCString &s ); + void duplicate( const char *str); + QCString &duplicate( const char *str, int); - 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 (size<=SHORT_STR_CAPACITY) // 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 = lentoStr(),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 (&s!=this) - { - 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 (lentoStr(),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; + char * m_data; }; +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 *****************************************************************************/ @@ -670,6 +327,56 @@ 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 *****************************************************************************/ @@ -769,4 +476,5 @@ inline const char *qPrint(const QCString &s) if (!s.isEmpty()) return s.data(); else return ""; } + #endif // QCSTRING_H diff --git a/qtools/qtools.pro.in b/qtools/qtools.pro.in index ba8a086..f287d34 100644 --- a/qtools/qtools.pro.in +++ b/qtools/qtools.pro.in @@ -7,6 +7,7 @@ HEADERS = qarray.h \ qcollection.h \ qconfig.h \ qcstring.h \ + scstring.h \ qdatastream.h \ qdatetime.h \ qdict.h \ @@ -53,7 +54,7 @@ HEADERS = qarray.h \ SOURCES = qbuffer.cpp \ qcollection.cpp \ - qcstring.cpp \ + scstring.cpp \ qdatastream.cpp \ qdatetime.cpp \ qdir.cpp \ diff --git a/qtools/scstring.cpp b/qtools/scstring.cpp new file mode 100644 index 0000000..26d3a52 --- /dev/null +++ b/qtools/scstring.cpp @@ -0,0 +1,798 @@ +/****************************************************************************** + * + * 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 +#include +#include +#include +#include +#include +#include + + +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 (llen ) // 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 diff --git a/qtools/scstring.h b/qtools/scstring.h new file mode 100644 index 0000000..a9b462c --- /dev/null +++ b/qtools/scstring.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * 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 + +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 + -- cgit v0.12