summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitri van Heesch <dimitri@stack.nl>2014-10-21 19:31:35 (GMT)
committerDimitri van Heesch <dimitri@stack.nl>2014-10-21 19:31:35 (GMT)
commita9dcbfe28625673f4d13bc5b3cde694c24062e19 (patch)
tree978138b6c6ba28a6e62a6dd9cfb0f5e2a6de6391
parent9323ae470ad514586706dc8647501361fe208f36 (diff)
downloadDoxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.zip
Doxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.tar.gz
Doxygen-a9dcbfe28625673f4d13bc5b3cde694c24062e19.tar.bz2
Fixed refcounting bug in new string implementation
-rw-r--r--qtools/qcstring.h27
-rw-r--r--qtools/rcstring.h791
2 files changed, 15 insertions, 803 deletions
diff --git a/qtools/qcstring.h b/qtools/qcstring.h
index 7170455..5c3a0de 100644
--- a/qtools/qcstring.h
+++ b/qtools/qcstring.h
@@ -498,19 +498,22 @@ public:
}
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
+ if (&s!=this)
{
- u.l.isShort=FALSE;
- u.l.d = s.u.l.d;
- u.l.d->refCount++;
+ 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;
}
diff --git a/qtools/rcstring.h b/qtools/rcstring.h
deleted file mode 100644
index 01b5a5c..0000000
--- a/qtools/rcstring.h
+++ /dev/null
@@ -1,791 +0,0 @@
-/******************************************************************************
- *
- * 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
-