31 files changed, 1115 insertions, 678 deletions
diff --git a/qmake/tools/qbitarray.cpp b/qmake/tools/qbitarray.cpp index 4f4e14b..1aaf963 100644 --- a/qmake/tools/qbitarray.cpp +++ b/qmake/tools/qbitarray.cpp @@ -136,129 +136,130 @@ /*! Constructs an empty bit array. */ QBitArray::QBitArray() : QByteArray( 0, 0 ) { bitarr_data *x = new bitarr_data; Q_CHECK_PTR( x ); x->nbits = 0; setSharedBlock( x ); } /*! Constructs a bit array of \a size bits. The bits are uninitialized. \sa fill() */ QBitArray::QBitArray( uint size ) : QByteArray( 0, 0 ) { bitarr_data *x = new bitarr_data; Q_CHECK_PTR( x ); x->nbits = 0; setSharedBlock( x ); resize( size ); } /*! \fn QBitArray::QBitArray( const QBitArray &a ) Constructs a shallow copy of \a a. */ /*! \fn QBitArray &QBitArray::operator=( const QBitArray &a ) Assigns a shallow copy of \a a to this bit array and returns a reference to this array. */ /*! Pad last byte with 0-bits. */ void QBitArray::pad0() { uint sz = size(); if ( sz && sz%8 ) *(data()+sz/8) &= (1 << (sz%8)) - 1; } /*! \fn uint QBitArray::size() const Returns the bit array's size (number of bits). \sa resize() */ /*! Resizes the bit array to \a size bits and returns TRUE if the bit - array could be resized; otherwise returns FALSE. + array could be resized; otherwise returns FALSE. The array becomes + a null array if \a size == 0. If the array is expanded, the new bits are set to 0. \sa size() */ bool QBitArray::resize( uint size ) { uint s = this->size(); if ( !QByteArray::resize( (size+7)/8 ) ) return FALSE; // cannot resize SHBLOCK->nbits = size; if ( size != 0 ) { // not null array int ds = (int)(size+7)/8 - (int)(s+7)/8;// number of bytes difference if ( ds > 0 ) // expanding array memset( data() + (s+7)/8, 0, ds ); // reset new data } return TRUE; } /*! Fills the bit array with \a v (1's if \a v is TRUE, or 0's if \a v is FALSE). fill() resizes the bit array to \a size bits if \a size is nonnegative. Returns FALSE if a nonnegative \e size was specified and the bit array could not be resized; otherwise returns TRUE. \sa resize() */ bool QBitArray::fill( bool v, int size ) { if ( size >= 0 ) { // resize first if ( !resize( size ) ) return FALSE; // cannot resize } else { size = this->size(); } if ( size > 0 ) memset( data(), v ? 0xff : 0, (size + 7) / 8 ); if ( v ) pad0(); return TRUE; } /*! Detaches from shared bit array data and makes sure that this bit array is the only one referring to the data. If multiple bit arrays share common data, this bit array dereferences the data and gets a copy of the data. Nothing happens if there is only a single reference. \sa copy() */ void QBitArray::detach() { int nbits = SHBLOCK->nbits; diff --git a/qmake/tools/qbuffer.cpp b/qmake/tools/qbuffer.cpp index b213dd9..0fc90e4 100644 --- a/qmake/tools/qbuffer.cpp +++ b/qmake/tools/qbuffer.cpp @@ -135,130 +135,130 @@ QBuffer::~QBuffer() Replaces the buffer's contents with \a buf and returns TRUE. Does nothing (and returns FALSE) if isOpen() is TRUE. Note that if you open the buffer in write mode (\c IO_WriteOnly or IO_ReadWrite) and write something into the buffer, \a buf is also modified because QByteArray is an explicitly shared class. \sa buffer(), open(), close() */ bool QBuffer::setBuffer( QByteArray buf ) { if ( isOpen() ) { #if defined(QT_CHECK_STATE) qWarning( "QBuffer::setBuffer: Buffer is open" ); #endif return FALSE; } a = buf; a_len = a.size(); a_inc = (a_len > 512) ? 512 : a_len; // initial increment if ( a_inc < 16 ) a_inc = 16; ioIndex = 0; return TRUE; } /*! \fn QByteArray QBuffer::buffer() const Returns this buffer's byte array. \sa setBuffer() */ /*! \reimp Opens the buffer in mode \a m. Returns TRUE if successful; otherwise returns FALSE. The buffer must be opened before use. The mode parameter \a m must be a combination of the following flags. \list \i \c IO_ReadOnly opens the buffer in read-only mode. \i \c IO_WriteOnly opens the buffer in write-only mode. \i \c IO_ReadWrite opens the buffer in read/write mode. \i \c IO_Append sets the buffer index to the end of the buffer. \i \c IO_Truncate truncates the buffer. \endlist \sa close(), isOpen() */ bool QBuffer::open( int m ) { if ( isOpen() ) { // buffer already open #if defined(QT_CHECK_STATE) qWarning( "QBuffer::open: Buffer already open" ); #endif return FALSE; } setMode( m ); if ( m & IO_Truncate ) { // truncate buffer - a.resize( 0 ); - a_len = 0; + a.resize( 1 ); + a_len = 1; } if ( m & IO_Append ) { // append to end of buffer ioIndex = a.size(); } else { ioIndex = 0; } a_inc = 16; setState( IO_Open ); setStatus( 0 ); return TRUE; } /*! \reimp Closes an open buffer. \sa open() */ void QBuffer::close() { if ( isOpen() ) { setFlags( IO_Direct ); ioIndex = 0; a_inc = 16; } } /*! \reimp The flush function does nothing for a QBuffer. */ void QBuffer::flush() { return; } /*! \fn QIODevice::Offset QBuffer::at() const \reimp */ /*! \fn QIODevice::Offset QBuffer::size() const \reimp */ /*! \reimp */ bool QBuffer::at( Offset pos ) { #if defined(QT_CHECK_STATE) if ( !isOpen() ) { qWarning( "QBuffer::at: Buffer is not open" ); return FALSE; } diff --git a/qmake/tools/qcomlibrary.cpp b/qmake/tools/qcomlibrary.cpp index a7162fc..2a1b75a 100644 --- a/qmake/tools/qcomlibrary.cpp +++ b/qmake/tools/qcomlibrary.cpp @@ -2,128 +2,132 @@ ** $Id$ ** ** Implementation of QComLibrary class ** ** Copyright (C) 2001-2002 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. ** **********************************************************************/ #include "qcomlibrary_p.h" #ifndef QT_NO_COMPONENT #include <qapplication.h> #include <qsettings.h> #include <qfileinfo.h> #include <qdatetime.h> #include <qcleanuphandler.h> #include <errno.h> #ifdef QT_THREAD_SUPPORT # include "qmutexpool_p.h" #endif // QT_THREAD_SUPPORT #ifndef QT_DEBUG_COMPONENT # if defined(QT_DEBUG) # define QT_DEBUG_COMPONENT 1 # endif #endif QComLibrary::QComLibrary( const QString &filename ) : QLibrary( filename ), entry( 0 ), libiface( 0 ), qt_version( 0 ) { } QComLibrary::~QComLibrary() { if ( autoUnload() ) unload(); + if ( libiface ) + libiface->release(); + if ( entry ) + entry->release(); } bool QComLibrary::unload() { if ( libiface ) { libiface->cleanup(); if ( !libiface->canUnload() ) return FALSE; libiface->release(); libiface = 0; } int refs = entry ? entry->release() : 0; if ( refs ) return FALSE; entry = 0; return QLibrary::unload(); } static bool qt_verify( const QString& library, uint version, uint flags, const QCString &key, bool warn ) { uint our_flags = 1; #if defined(QT_THREAD_SUPPORT) our_flags |= 2; #endif if ( (flags & 1) == 0 ) { if ( warn ) qWarning( "Conflict in %s:\n" " Plugin cannot be queried successfully!", (const char*) QFile::encodeName(library) ); } else if ( ( version > QT_VERSION ) || ( ( QT_VERSION & 0xff0000 ) > ( version & 0xff0000 ) ) ) { if ( warn ) qWarning( "Conflict in %s:\n" " Plugin uses incompatible Qt library (%d.%d.%d)!", (const char*) QFile::encodeName(library), (version&0xff0000) >> 16, (version&0xff00) >> 8, version&0xff ); } else if ( (flags & 2) != (our_flags & 2) ) { if ( warn ) qWarning( "Conflict in %s:\n" " Plugin uses %s Qt library!", (const char*) QFile::encodeName(library), (flags & 2) ? "multi threaded" : "single threaded" ); } else if ( key != QT_BUILD_KEY ) { if ( warn ) qWarning( "Conflict in %s:\n" " Plugin uses incompatible Qt library!\n" " expected build key \"%s\", got \"%s\".", (const char*) QFile::encodeName(library), QT_BUILD_KEY, key.isEmpty() ? "<null>" : (const char *) key ); } else { return TRUE; } return FALSE; } struct qt_token_info { qt_token_info( const char *f, const ulong fc ) : fields( f ), field_count( fc ), results( fc ), lengths( fc ) @@ -330,203 +334,196 @@ static bool qt_unix_query( const QString &library, uint *version, uint *flags, #ifdef USE_MMAP char *mapaddr = 0; size_t maplen = file.size(); mapaddr = (char *) mmap( mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0 ); if ( mapaddr != MAP_FAILED ) { // mmap succeeded filedata = mapaddr; fdlen = maplen; } else { // mmap failed qWarning( "mmap: %s", strerror( errno ) ); #endif // USE_MMAP // try reading the data into memory instead data = file.readAll(); filedata = data.data(); fdlen = data.size(); #ifdef USE_MMAP } #endif // USE_MMAP // verify that the pattern is present in the plugin const char *pattern = "pattern=QT_UCM_VERIFICATION_DATA"; const ulong plen = qstrlen( pattern ); long pos = qt_find_pattern( filedata, fdlen, pattern, plen ); bool ret = FALSE; if ( pos >= 0 ) { ret = qt_parse_pattern( filedata + pos, version, flags, key ); } #ifdef USE_MMAP if ( mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0 ) { qWarning( "munmap: %s", strerror( errno ) ); } #endif // USE_MMAP file.close(); return ret; } #endif // Q_OS_UNIX static QSettings *cache = 0; static QSingleCleanupHandler<QSettings> cleanup_cache; void QComLibrary::createInstanceInternal() { if ( library().isEmpty() ) return; QFileInfo fileinfo( library() ); QString lastModified = fileinfo.lastModified().toString(); QString regkey = QString("/Qt Plugins %1.%2/%3") .arg( ( QT_VERSION & 0xff0000 ) >> 16 ) .arg( ( QT_VERSION & 0xff00 ) >> 8 ) .arg( library() ); QStringList reg; uint flags = 0; QCString key; bool query_done = FALSE; bool warn_mismatch = TRUE; - if ( ! query_done ) { - #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &cache ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &cache ) : 0 ); #endif // QT_THREAD_SUPPORT - if ( ! cache ) { - cache = new QSettings; - cache->insertSearchPath( QSettings::Windows, "/Trolltech" ); - cleanup_cache.set( &cache ); - } + if ( ! cache ) { + cache = new QSettings; + cache->insertSearchPath( QSettings::Windows, "/Trolltech" ); + cleanup_cache.set( &cache ); + } - reg = cache->readListEntry( regkey ); - if ( reg.count() == 4 ) { - // check timestamp - if ( lastModified == reg[3] ) { - qt_version = reg[0].toUInt(0, 16); - flags = reg[1].toUInt(0, 16); - key = reg[2].latin1(); + reg = cache->readListEntry( regkey ); + if ( reg.count() == 4 ) { + // check timestamp + if ( lastModified == reg[3] ) { + qt_version = reg[0].toUInt(0, 16); + flags = reg[1].toUInt(0, 16); + key = reg[2].latin1(); - query_done = TRUE; - warn_mismatch = FALSE; - } + query_done = TRUE; + warn_mismatch = FALSE; } } #if defined(Q_OS_UNIX) if ( ! query_done ) { // get the query information directly from the plugin without loading if ( qt_unix_query( library(), &qt_version, &flags, &key ) ) { // info read succesfully from library query_done = TRUE; } } #else // !Q_OS_UNIX if ( ! query_done ) { // get the query information by loading the plugin if ( !isLoaded() ) { Q_ASSERT( entry == 0 ); if ( !load() ) return; } # ifdef Q_CC_BOR typedef const char * __stdcall (*UCMQueryVerificationDataProc)(); # else typedef const char * (*UCMQueryVerificationDataProc)(); # endif UCMQueryVerificationDataProc ucmQueryVerificationdataProc; ucmQueryVerificationdataProc = (UCMQueryVerificationDataProc) resolve( "qt_ucm_query_verification_data" ); if ( !ucmQueryVerificationdataProc || !qt_parse_pattern( ucmQueryVerificationdataProc(), &qt_version, &flags, &key ) ) { qt_version = flags = 0; key = "unknown"; } else { query_done = TRUE; } } #endif // Q_OS_UNIX QStringList queried; queried << QString::number( qt_version,16 ) << QString::number( flags, 16 ) << key << lastModified; if ( queried != reg ) { - -#ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &cache ) ); -#endif // QT_THREAD_SUPPORT - cache->writeEntry( regkey, queried ); // delete the cache, which forces the settings to be written delete cache; cache = 0; } if ( ! query_done ) { if ( warn_mismatch ) { qWarning( "Conflict in %s:\n Plugin cannot be queried successfully!", (const char*) QFile::encodeName( library() ) ); } unload(); return; } if ( ! qt_verify( library(), qt_version, flags, key, warn_mismatch ) ) { unload(); return; } else if ( !isLoaded() ) { Q_ASSERT( entry == 0 ); if ( !load() ) return; } #ifdef Q_CC_BOR typedef QUnknownInterface* __stdcall (*UCMInstanceProc)(); #else typedef QUnknownInterface* (*UCMInstanceProc)(); #endif UCMInstanceProc ucmInstanceProc; ucmInstanceProc = (UCMInstanceProc) resolve( "ucm_instantiate" ); #if defined(QT_DEBUG_COMPONENT) if ( !ucmInstanceProc ) qWarning( "%s: Not a UCOM library.", (const char*) QFile::encodeName(library()) ); #endif entry = ucmInstanceProc ? ucmInstanceProc() : 0; if ( entry ) { if ( entry->queryInterface( IID_QLibrary, (QUnknownInterface**)&libiface ) == QS_OK ) { if ( libiface && !libiface->init() ) { libiface->release(); libiface = 0; unload(); return; } } } else { #if defined(QT_DEBUG_COMPONENT) qWarning( "%s: No exported component provided.", (const char*) QFile::encodeName(library()) ); #endif unload(); } } QRESULT QComLibrary::queryInterface( const QUuid& request, QUnknownInterface** iface ) { if ( !entry ) createInstanceInternal(); return entry ? entry->queryInterface( request, iface ) : QE_NOCOMPONENT; } uint QComLibrary::qtVersion() { if ( !entry ) diff --git a/qmake/tools/qconfig.cpp b/qmake/tools/qconfig.cpp index 433827c..5297a4e 100644 --- a/qmake/tools/qconfig.cpp +++ b/qmake/tools/qconfig.cpp @@ -1,17 +1,17 @@ /* Install paths from configure */ -static const char QT_INSTALL_PREFIX [256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2"; -static const char QT_INSTALL_BINS [256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2/bin"; -static const char QT_INSTALL_DOCS [256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2/doc"; -static const char QT_INSTALL_HEADERS[256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2/include"; -static const char QT_INSTALL_LIBS [256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2/lib"; -static const char QT_INSTALL_PLUGINS[256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2/plugins"; -static const char QT_INSTALL_DATA [256] = "/usr/src/coding/projects/userspace/qt-embedded-free-3.1.0-b2"; +static const char QT_INSTALL_PREFIX [256] = "/opt/qt-x11-free-3.1.2"; +static const char QT_INSTALL_BINS [256] = "/opt/qt-x11-free-3.1.2/bin"; +static const char QT_INSTALL_DOCS [256] = "/opt/qt-x11-free-3.1.2/doc"; +static const char QT_INSTALL_HEADERS[256] = "/opt/qt-x11-free-3.1.2/include"; +static const char QT_INSTALL_LIBS [256] = "/opt/qt-x11-free-3.1.2/lib"; +static const char QT_INSTALL_PLUGINS[256] = "/opt/qt-x11-free-3.1.2/plugins"; +static const char QT_INSTALL_DATA [256] = "/opt/qt-x11-free-3.1.2"; const char *qInstallPath() { return QT_INSTALL_PREFIX; } const char *qInstallPathDocs() { return QT_INSTALL_DOCS; } const char *qInstallPathHeaders() { return QT_INSTALL_HEADERS; } const char *qInstallPathLibs() { return QT_INSTALL_LIBS; } const char *qInstallPathBins() { return QT_INSTALL_BINS; } const char *qInstallPathPlugins() { return QT_INSTALL_PLUGINS; } const char *qInstallPathData() { return QT_INSTALL_DATA; } diff --git a/qmake/tools/qcriticalsection_p.cpp b/qmake/tools/qcriticalsection_p.cpp index 60fc8bd..c375730 100644 --- a/qmake/tools/qcriticalsection_p.cpp +++ b/qmake/tools/qcriticalsection_p.cpp @@ -1,71 +1,69 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QCriticalSection class ** -** Created : -** ** Copyright (C) 2001 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. ** **********************************************************************/ #if defined(QT_THREAD_SUPPORT) #include "qt_windows.h" #include <private/qcriticalsection_p.h> class QCriticalSectionPrivate { public: QCriticalSectionPrivate() {} CRITICAL_SECTION section; }; QCriticalSection::QCriticalSection() { d = new QCriticalSectionPrivate; InitializeCriticalSection( &d->section ); } QCriticalSection::~QCriticalSection() { DeleteCriticalSection( &d->section ); delete d; } void QCriticalSection::enter() { EnterCriticalSection( &d->section ); } void QCriticalSection::leave() { diff --git a/qmake/tools/qcstring.cpp b/qmake/tools/qcstring.cpp index cf1b853..4651b97 100644 --- a/qmake/tools/qcstring.cpp +++ b/qmake/tools/qcstring.cpp @@ -80,128 +80,139 @@ void *qmemmove( void *dst, const void *src, uint len ) d = (char *)dst; s = (char *)src; while ( len-- ) *d++ = *s++; } return dst; } /*! \relates QCString Returns a duplicate string. Allocates space for a copy of \a src, copies it, and returns a pointer to the copy. If \a src is 0, it immediately returns 0. The returned string must be deleted using \c delete[]. */ char *qstrdup( const char *src ) { if ( !src ) return 0; char *dst = new char[strlen(src)+1]; Q_CHECK_PTR( dst ); return strcpy( dst, src ); } /*! \fn char *qstrcpy( char *dst, const char *src ) \relates QCString A safe strcpy() function. Copies all characters up to and including the '\0' from \a src into \a dst and returns a pointer to \a dst. */ /*! \relates QCString A safe strncpy() function. Copies at most \a len bytes from \a src (stopping at \a len or the terminating '\0' whichever comes first) into \a dst and returns a pointer to \a dst. Guarantees that \a dst is '\0'-terminated. If \a src or \a dst is 0, returns 0 immediately. \sa qstrcpy() */ char *qstrncpy( char *dst, const char *src, uint len ) { if ( !src || !dst ) return 0; strncpy( dst, src, len ); if ( len > 0 ) dst[len-1] = '\0'; return dst; } /*! + \fn uint qstrlen( const char *str ); + + \relates QCString + + A safe strlen function. + + Returns the number of characters that precede the terminating '\0'. + or 0 if \a str is 0. +*/ + +/*! \fn int qstrcmp( const char *str1, const char *str2 ); \relates QCString A safe strcmp() function. Compares \a str1 and \a str2. Returns a negative value if \a str1 is less than \a str2, 0 if \a str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. Special case I: Returns 0 if \a str1 and \a str2 are both 0. Special case II: Returns a random nonzero value if \a str1 is 0 or \a str2 is 0 (but not both). \sa qstrncmp() qstricmp() qstrnicmp() \link #asciinotion Note on character comparisons \endlink */ /*! \fn int qstrncmp( const char *str1, const char *str2, uint len ); \relates QCString A safe strncmp() function. Compares at most \a len bytes of \a str1 and \a str2. Returns a negative value if \a str1 is less than \a str2, 0 if \a str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. Special case I: Returns 0 if \a str1 and \a str2 are both 0. Special case II: Returns a random nonzero value if \a str1 is 0 or \a str2 is 0 (but not both). \sa qstrcmp(), qstricmp(), qstrnicmp() \link #asciinotion Note on character comparisons \endlink */ /*! \relates QCString A safe stricmp() function. Compares \a str1 and \a str2 ignoring the case. Returns a negative value if \a str1 is less than \a str2, 0 if \a str1 is equal to \a str2 or a positive value if \a str1 is greater than \a str2. Special case I: Returns 0 if \a str1 and \a str2 are both 0. Special case II: Returns a random nonzero value if \a str1 is 0 or \a str2 is 0 (but not both). \sa qstrcmp(), qstrncmp(), qstrnicmp() \link #asciinotion Note on character comparisons \endlink */ int qstricmp( const char *str1, const char *str2 ) { register const uchar *s1 = (const uchar *)str1; @@ -238,222 +249,241 @@ int qstricmp( const char *str1, const char *str2 ) 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 s1 ? 1 : ( s2 ? -1 : 0 ); for ( ; len--; s1++, s2++ ) { if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) return res; if ( !c ) // strings are equal break; } return 0; } static Q_UINT16 crc_tbl[16]; static bool crc_tbl_init = FALSE; static void createCRC16Table() // build CRC16 lookup table { register uint i; register uint j; uint v0, v1, v2, v3; for ( i = 0; i < 16; i++ ) { v0 = i & 1; v1 = ( i >> 1 ) & 1; v2 = ( i >> 2 ) & 1; v3 = ( i >> 3 ) & 1; j = 0; #undef SET_BIT #define SET_BIT(x, b, v) (x) |= (v) << (b) SET_BIT( j, 0, v0 ); SET_BIT( j, 7, v0 ); SET_BIT( j, 12, v0 ); SET_BIT( j, 1, v1 ); SET_BIT( j, 8, v1 ); SET_BIT( j, 13, v1 ); SET_BIT( j, 2, v2 ); SET_BIT( j, 9, v2 ); SET_BIT( j, 14, v2 ); SET_BIT( j, 3, v3 ); SET_BIT( j, 10, v3 ); SET_BIT( j, 15, v3 ); crc_tbl[i] = j; } } /*! \relates QMemArray Returns the CRC-16 checksum of \a len bytes starting at \a data. The checksum is independent of the byte order (endianness). */ Q_UINT16 qChecksum( const char *data, uint len ) { if ( !crc_tbl_init ) { // create lookup table #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &crc_tbl_init ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &crc_tbl_init ) : 0 ); #endif // QT_THREAD_SUPPORT if ( !crc_tbl_init ) { createCRC16Table(); crc_tbl_init = TRUE; } } register Q_UINT16 crc = 0xffff; uchar c; uchar *p = (uchar *)data; while ( len-- ) { c = *p++; crc = ( (crc >> 4) & 0x0fff ) ^ crc_tbl[((crc ^ c) & 15)]; c >>= 4; crc = ( (crc >> 4) & 0x0fff ) ^ crc_tbl[((crc ^ c) & 15)]; } return ~crc & 0xffff; } -/*! \fn QByteArray qCompress( const QByteArray& data) - \relates QByteArray - \overload +/*! + \fn QByteArray qCompress( const QByteArray& data ) + + \relates QByteArray + + Compresses the array \a data and returns the compressed byte + array. + + \sa qUncompress() */ /*! - \relates QByteArray + \relates QByteArray - Compresses the array \a data which is \a nbytes long and returns the - compressed byte array. + \overload - \sa qUncompress() + Compresses the array \a data which is \a nbytes long and returns the + compressed byte array. */ #ifndef QT_NO_COMPRESS QByteArray qCompress( const uchar* data, int nbytes ) { if ( nbytes == 0 ) { QByteArray tmp( 4 ); tmp.fill( 0 ); return tmp; } if ( !data ) { #if defined(QT_CHECK_RANGE) qWarning( "qCompress: data is NULL." ); #endif return QByteArray(); } ulong len = nbytes * 2; QByteArray bazip; int res; do { bazip.resize( len + 4 ); res = ::compress( (uchar*)bazip.data()+4, &len, (uchar*)data, nbytes ); switch ( res ) { case Z_OK: bazip.resize( len + 4 ); bazip[0] = ( nbytes & 0xff000000 ) >> 24; bazip[1] = ( nbytes & 0x00ff0000 ) >> 16; bazip[2] = ( nbytes & 0x0000ff00 ) >> 8; bazip[3] = ( nbytes & 0x000000ff ); break; case Z_MEM_ERROR: #if defined(QT_CHECK_RANGE) qWarning( "qCompress: Z_MEM_ERROR: Not enough memory." ); #endif bazip.resize( 0 ); break; case Z_BUF_ERROR: len *= 2; break; } } while ( res == Z_BUF_ERROR ); return bazip; } #endif -/*! \fn QByteArray qUncompress( const QByteArray& data ) - \relates QByteArray - \overload +/*! + \fn QByteArray qUncompress( const QByteArray& data ) + + \relates QByteArray + + Uncompresses the array \a data and returns the uncompressed byte + array. + + Returns an empty QByteArray if the input data was corrupt. + \omit + ADD THE FOLLOWING FOR Qt 4.0 + This function will uncompress data compressed with qCompress() + from this and any earlier Qt version, back to Qt 3.1 when this + feature was added. + \endomit + + \sa qCompress() */ /*! - \relates QByteArray - - Uncompresses the array \a data which is \a nbytes long and returns - the uncompressed byte array. + \relates QByteArray - Returns an empty QByteArray if the input data was corrupt. + \overload - \sa qCompress() + Uncompresses the array \a data which is \a nbytes long and returns + the uncompressed byte array. */ #ifndef QT_NO_COMPRESS QByteArray qUncompress( const uchar* data, int nbytes ) { if ( !data ) { #if defined(QT_CHECK_RANGE) qWarning( "qUncompress: data is NULL." ); #endif return QByteArray(); } if ( nbytes <= 4 ) { #if defined(QT_CHECK_RANGE) if ( nbytes < 4 || ( data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0 ) ) qWarning( "qUncompress: Input data is corrupted." ); #endif return QByteArray(); } ulong expectedSize = ( data[0] << 24 ) | ( data[1] << 16 ) | ( data[2] << 8 ) | data[3]; ulong len = QMAX( expectedSize, 1 ); QByteArray baunzip; int res; do { baunzip.resize( len ); res = ::uncompress( (uchar*)baunzip.data(), &len, (uchar*)data+4, nbytes-4 ); switch ( res ) { case Z_OK: if ( len != baunzip.size() ) baunzip.resize( len ); break; case Z_MEM_ERROR: #if defined(QT_CHECK_RANGE) qWarning( "qUncompress: Z_MEM_ERROR: Not enough memory." ); #endif break; case Z_BUF_ERROR: len *= 2; break; case Z_DATA_ERROR: #if defined(QT_CHECK_RANGE) qWarning( "qUncompress: Z_DATA_ERROR: Input data is corrupted." ); #endif break; } } while ( res == Z_BUF_ERROR ); if ( res != Z_OK ) baunzip = QByteArray(); return baunzip; } #endif /***************************************************************************** QByteArray documentation *****************************************************************************/ /*! \class QByteArray \reentrant \brief The QByteArray class provides an array of bytes. @@ -875,135 +905,139 @@ bool QCString::fill( char c, int len ) } /*! \fn QCString QCString::copy() const Returns a deep copy of this string. \sa detach() */ /*! Finds the first occurrence of the character \a c, starting at position \a index. The search is case sensitive if \a cs is TRUE, or case insensitive if \a cs is FALSE. Returns the position of \a c, or -1 if \a c could not be found. \sa \link #asciinotion Note on character comparisons \endlink */ int QCString::find( char c, int index, bool cs ) const { if ( (uint)index >= size() ) // index outside string return -1; register const char *d; if ( cs ) { // case sensitive d = strchr( data()+index, c ); } else { d = data()+index; c = tolower( (uchar) c ); while ( *d && tolower((uchar) *d) != c ) d++; if ( !*d && c ) // not found d = 0; } return d ? (int)(d - data()) : -1; } #define REHASH( a ) \ if ( sl_minus_1 < sizeof(uint) * CHAR_BIT ) \ hashHaystack -= (a) << sl_minus_1; \ hashHaystack <<= 1 /*! \overload Finds the first occurrence of the string \a str, starting at position \a index. The search is case sensitive if \a cs is TRUE, or case insensitive if \a cs is FALSE. Returns the position of \a str, or -1 if \a str could not be found. \sa \link #asciinotion Note on character comparisons \endlink */ int QCString::find( const char *str, int index, bool cs ) const { + return find( str, index, cs, length() ); +} + +int QCString::find( const char *str, int index, bool cs, uint l ) const +{ if ( (uint)index >= size() ) return -1; if ( !str ) return -1; if ( !*str ) return index; - const uint l = length(); const uint sl = qstrlen( str ); if ( sl + index > l ) return -1; if ( sl == 1 ) return find( *str, index, cs ); /* See QString::find() for details. */ const char* needle = str; const char* haystack = data() + index; const char* end = data() + (l-sl); const uint sl_minus_1 = sl-1; uint hashNeedle = 0, hashHaystack = 0,i; if ( cs ) { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + needle[i] ); hashHaystack = ((hashHaystack<<1) + haystack[i] ); } hashHaystack -= *(haystack+sl_minus_1); while ( haystack <= end ) { hashHaystack += *(haystack+sl_minus_1); if ( hashHaystack == hashNeedle && *needle == *haystack && qstrncmp( needle, haystack, sl ) == 0 ) return haystack - data(); REHASH( *haystack ); ++haystack; } } else { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + tolower( needle[i] ) ); hashHaystack = ((hashHaystack<<1) + tolower( haystack[i] ) ); } hashHaystack -= tolower(*(haystack+sl_minus_1)); while ( haystack <= end ) { hashHaystack += tolower(*(haystack+sl_minus_1)); if ( hashHaystack == hashNeedle && qstrnicmp( needle, haystack, sl ) == 0 ) return haystack - data(); REHASH( tolower(*haystack) ); ++haystack; } } return -1; } /*! Finds the first occurrence of the character \a c, starting at position \a index and searching backwards. The search is case sensitive if \a cs is TRUE, or case insensitive if \a cs is FALSE. Returns the position of \a c, or -1 if \a c could not be found. @@ -1091,150 +1125,150 @@ int QCString::findRev( const char *str, int index, bool cs ) const } hashHaystack -= tolower(*haystack); while ( haystack >= end ) { hashHaystack += tolower(*haystack); if ( hashHaystack == hashNeedle && qstrnicmp( needle, haystack, sl ) == 0 ) return haystack-data(); --haystack; REHASH( tolower(*(haystack+sl)) ); } } return -1; } /*! Returns the number of times the character \a c occurs in the string. The match is case sensitive if \a cs is TRUE, or case insensitive if \a cs if FALSE. \sa \link #asciinotion Note on character comparisons \endlink */ int QCString::contains( char c, bool cs ) const { int count = 0; char *d = 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; } /*! \overload Returns the number of times \a str occurs in the string. The match is case sensitive if \a cs is TRUE, or case insensitive if \a cs if FALSE. This function counts overlapping substrings, for example, "banana" contains two occurrences of "ana". \sa findRev() \link #asciinotion Note on character comparisons \endlink */ int QCString::contains( const char *str, bool cs ) const { int count = 0; int i = -1; + uint l = length(); // use find for the faster hashing algorithm - while ( ( i = find ( str, i+1, cs ) ) != -1 ) + while ( ( i = find ( str, i+1, cs, l ) ) != -1 ) count++; return count; } /*! Returns a substring that contains the \a len leftmost characters of the string. The whole string is returned if \a len exceeds the length of the string. Example: \code QCString s = "Pineapple"; QCString t = s.left( 4 ); // t == "Pine" \endcode \sa right(), mid() */ - QCString QCString::left( uint len ) const { if ( isEmpty() ) { QCString empty; return empty; } else if ( len >= size() ) { QCString same( data() ); return same; } else { QCString s( len+1 ); strncpy( s.data(), data(), len ); *(s.data()+len) = '\0'; return s; } } /*! Returns a substring that contains the \a len rightmost characters of the string. The whole string is returned if \a len exceeds the length of the string. Example: \code QCString s = "Pineapple"; QCString t = s.right( 5 ); // t == "apple" \endcode \sa left(), mid() */ QCString QCString::right( uint len ) const { if ( isEmpty() ) { QCString empty; return empty; } else { uint l = length(); if ( len > l ) len = l; char *p = data() + (l - len); return QCString( p ); } } /*! Returns a substring that contains at most \a len characters from this string, starting at position \a index. Returns a null string if the string is empty or if \a index is out of range. Returns the whole string from \a index if \a index+len exceeds the length of the string. Example: \code QCString s = "Two pineapples"; QCString t = s.mid( 4, 3 ); // t == "pin" \endcode \sa left(), right() */ QCString QCString::mid( uint index, uint len ) const @@ -1436,471 +1470,474 @@ QCString QCString::stripWhiteSpace() const White space means the decimal ASCII codes 9, 10, 11, 12, 13 and 32. \code QCString s = " lots\t of\nwhite space "; QCString t = s.simplifyWhiteSpace(); // t == "lots of white space" \endcode \sa stripWhiteSpace() */ QCString QCString::simplifyWhiteSpace() const { if ( isEmpty() ) // nothing to do return copy(); QCString result( size() ); char *from = data(); char *to = result.data(); char *first = to; for ( ;; ) { while ( 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)(to - result.data()) + 1 ); return result; } /*! \overload Inserts string \a s into the string at position \a index. If \a index is beyond the end of the string, the string is padded with spaces (ASCII 32) to length \a index and then \a s is appended. \code QCString s = "I like fish"; s.insert( 2, "don't "); // s == "I don't like fish" s = "x"; // index 01234 s.insert( 3, "yz" ); // s == "x yz" \endcode */ QCString &QCString::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 detach(); - if ( QByteArray::resize(nlen+index-olen+1) ) { + if ( QByteArray::resize(nlen+index-olen+1, QByteArray::SpeedOptim ) ) { memset( data()+olen, ' ', index-olen ); memcpy( data()+index, s, len+1 ); } - } else if ( QByteArray::resize(nlen+1) ) { // normal insert + } else { detach(); - memmove( data()+index+len, data()+index, olen-index+1 ); - memcpy( data()+index, s, len ); + if ( QByteArray::resize(nlen+1, QByteArray::SpeedOptim ) ) { // normal insert + memmove( data()+index+len, data()+index, olen-index+1 ); + memcpy( data()+index, s, len ); + } } return *this; } /*! Inserts character \a c into the string at position \a index and returns a reference to the string. If \a index is beyond the end of the string, the string is padded with spaces (ASCII 32) to length \a index and then \a c is appended. Example: \code QCString s = "Yes"; s.insert( 3, '!'); // s == "Yes!" \endcode \sa remove(), replace() */ QCString &QCString::insert( uint index, char c ) // insert char { char buf[2]; buf[0] = c; buf[1] = '\0'; return insert( index, buf ); } /*! \fn QCString &QCString::prepend( const char *s ) Prepend \a s to the string. Equivalent to insert(0, s). \sa insert() */ /*! Removes \a len characters from the string, starting at position \a index, and returns a reference to the string. If \a index is out of range, nothing happens. If \a index is valid, but \a index + \a len is larger than the length of the string, the string is truncated at position \a index. \code QCString s = "Montreal"; s.remove( 1, 4 ); // s == "Meal" \endcode \sa insert(), replace() */ QCString &QCString::remove( uint index, uint len ) { uint olen = length(); if ( index + len >= olen ) { // range problems if ( index < olen ) { // index ok detach(); resize( index+1 ); } } else if ( len != 0 ) { detach(); memmove( data()+index, data()+index+len, olen-index-len+1 ); - QByteArray::resize(olen-len+1); + QByteArray::resize(olen-len+1, QByteArray::SpeedOptim ); } return *this; } /*! Replaces \a len characters from the string, starting at position \a index, with \a str, and returns a reference to the string. If \a index is out of range, nothing is removed and \a str is appended at the end of the string. If \a index is valid, but \a index + \a len is larger than the length of the string, \a str replaces the rest of the string from position \a index. \code QCString s = "Say yes!"; s.replace( 4, 3, "NO" ); // s == "Say NO!" \endcode \sa insert(), remove() */ QCString &QCString::replace( uint index, uint len, const char *str ) { remove( index, len ); insert( index, str ); return *this; } /*! \overload Replaces every occurrence of the character \a c in the string with \a after. Returns a reference to the string. Example: \code QCString s = "a,b,c"; s.replace( ',', " or " ); // s == "a or b or c" \endcode */ QCString &QCString::replace( char c, const char *after ) { char str[2]; str[0] = c; str[1] = '\0'; return replace( str, after ); } /*! \overload Replaces every occurrence of the string \a before in the string with the string \a after. Returns a reference to the string. Example: \code QCString s = "Greek is Greek"; s.replace( "Greek", "English" ); // s == "English is English" \endcode */ + QCString &QCString::replace( const char *before, const char *after ) { if ( before == after || isNull() ) return *this; detach(); int index = 0; const int bl = before ? strlen( before ) : 0; const int al = after ? strlen( after ) : 0; char *d = data(); uint len = length(); if ( bl == al ) { if ( bl ) { - while( (index = find( before, index ) ) != -1 ) { + while( (index = find( before, index, TRUE, len ) ) != -1 ) { memcpy( d+index, after, al ); index += bl; } } } else if ( al < bl ) { uint to = 0; uint movestart = 0; uint num = 0; - while( (index = find( before, index ) ) != -1 ) { + while( (index = find( before, index, TRUE, len ) ) != -1 ) { if ( num ) { int msize = index - movestart; if ( msize > 0 ) { memmove( d + to, d + movestart, msize ); to += msize; } } else { to = index; } if ( al ) { memcpy( d + to, after, al ); to += al; } index += bl; movestart = index; num++; } if ( num ) { int msize = len - movestart; if ( msize > 0 ) memmove( d + to, d + movestart, msize ); resize( len - num*(bl-al) + 1 ); } } else { // the most complex case. We don't want to loose performance by doing repeated // copies and reallocs of the string. while( index != -1 ) { uint indices[4096]; uint pos = 0; while( pos < 4095 ) { - index = find(before, index); + index = find(before, index, TRUE, len); if ( index == -1 ) break; indices[pos++] = index; index += bl; // avoid infinite loop if ( !bl ) index++; } if ( !pos ) break; // we have a table of replacement positions, use them for fast replacing int adjust = pos*(al-bl); // index has to be adjusted in case we get back into the loop above. if ( index != -1 ) index += adjust; uint newlen = len + adjust; int moveend = len; if ( newlen > len ) { resize( newlen + 1 ); len = newlen; } d = data(); while( pos ) { pos--; int movestart = indices[pos] + bl; int insertstart = indices[pos] + pos*(al-bl); int moveto = insertstart + al; memmove( d + moveto, d + movestart, (moveend - movestart) ); if ( after ) memcpy( d + insertstart, after, al ); moveend = movestart - bl; } } } return *this; } /*! \overload Replaces every occurrence of \a c1 with the char \a c2. Returns a reference to the string. */ QCString &QCString::replace( char c1, char c2 ) { detach(); uint i = 0; char *d = data(); uint len = length(); while ( i < len ) { if ( d[i] == c1 ) d[i] = c2; i++; } return *this; } #ifndef QT_NO_REGEXP_CAPTURE /*! \overload Finds the first occurrence of the regular expression \a rx, starting at position \a index. Returns the position of the next match, or -1 if \a rx was not found. \warning If you want to apply this function repeatedly to the same string it is more efficient to convert the string to a QString and apply the function to that. */ int QCString::find( const QRegExp& rx, int index ) const { - QString d = QString::fromLatin1( data() ); + QString d = QString::fromAscii( data() ); return d.find( rx, index ); } /*! \overload Finds the first occurrence of the regular expression \a rx, starting at position \a index and searching backwards. Returns the position of the next match (backwards), or -1 if \a rx was not found. \warning If you want to apply this function repeatedly to the same string it is more efficient to convert the string to a QString and apply the function to that. */ int QCString::findRev( const QRegExp& rx, int index ) const { - QString d = QString::fromLatin1( data() ); + QString d = QString::fromAscii( data() ); return d.findRev( rx, index ); } /*! \overload Counts the number of overlapping occurrences of \a rx in the string. Example: \code QString s = "banana and panama"; QRegExp r = QRegExp( "a[nm]a", TRUE, FALSE ); s.contains( r ); // 4 matches \endcode \sa find(), findRev() \warning If you want to apply this function repeatedly to the same string it is more efficient to convert the string to a QString and apply the function to that. */ int QCString::contains( const QRegExp &rx ) const { - QString d = QString::fromLatin1( data() ); + QString d = QString::fromAscii( data() ); return d.contains( rx ); } /*! \overload Replaces every occurrence of \a rx in the string with \a str. Returns a reference to the string. Example: \code QString s = "banana"; s.replace( QRegExp("a.*a"), "" ); // becomes "b" s = "banana"; s.replace( QRegExp("^[bn]a"), "X" ); // becomes "Xnana" s = "banana"; s.replace( QRegExp("^[bn]a"), "" ); // becomes "nana" \endcode \warning If you want to apply this function repeatedly to the same string it is more efficient to convert the string to a QString and apply the function to that. */ QCString &QCString::replace( const QRegExp &rx, const char *str ) { - QString d = QString::fromLatin1( data() ); - QString r = QString::fromLatin1( str ); + QString d = QString::fromAscii( data() ); + QString r = QString::fromAscii( str ); d.replace( rx, r ); setStr( d.ascii() ); return *this; } #endif //QT_NO_REGEXP /*! Returns the string converted to a \c long value. If \a ok is not 0: \a *ok is set to FALSE if the string is not a number, or if it has trailing garbage; otherwise \a *ok is set to TRUE. */ long QCString::toLong( bool *ok ) const { char *p = data(); long val=0; const long max_mult = 214748364; bool is_ok = FALSE; int neg = 0; if ( !p ) goto bye; while ( isspace((uchar) *p) ) // skip leading space p++; if ( *p == '-' ) { p++; neg = 1; } else if ( *p == '+' ) { p++; } if ( !isdigit((uchar) *p) ) goto bye; while ( isdigit((uchar) *p) ) { if ( val > max_mult || (val == max_mult && (*p-'0') > 7+neg) ) goto bye; val = 10*val + (*p++ - '0'); } if ( neg ) val = -val; while ( isspace((uchar) *p) ) // skip trailing space p++; if ( *p == '\0' ) is_ok = TRUE; bye: if ( ok ) *ok = is_ok; return is_ok ? val : 0; } /*! Returns the string converted to an \c{unsigned long} value. If \a ok is not 0: \a *ok is set to FALSE if the string is not a number, or if it has trailing garbage; otherwise \a *ok is set to TRUE. */ ulong QCString::toULong( bool *ok ) const { char *p = data(); ulong val=0; const ulong max_mult = 429496729; bool is_ok = FALSE; @@ -2138,145 +2175,145 @@ QCString &QCString::setNum( double n, char f, int prec ) if ( prec >= 10 ) { *fs++ = prec / 10 + '0'; *fs++ = prec % 10 + '0'; } else { *fs++ = prec + '0'; } *fs++ = 'l'; *fs++ = f; *fs = '\0'; return sprintf( format, n ); } /*! \overload QCString &QCString::setNum( float n, char f, int prec ) */ /*! Sets the character at position \a index to \a c and expands the string if necessary, padding with spaces. Returns FALSE if \a index was out of range and the string could not be expanded; otherwise returns TRUE. */ bool QCString::setExpand( uint index, char c ) { detach(); uint oldlen = length(); if ( index >= oldlen ) { if ( !QByteArray::resize( index+2 ) ) // no memory return FALSE; if ( index > oldlen ) memset( data() + oldlen, ' ', index - oldlen ); *(data() + index+1) = '\0'; // terminate padded string } *(data() + index) = c; return TRUE; } /*! \fn QCString::operator const char *() const Returns the string data. */ /*! \fn QCString& QCString::append( const char *str ) Appends string \a str to the string and returns a reference to the string. Equivalent to operator+=(). */ /*! Appends string \a str to the string and returns a reference to the string. */ QCString& QCString::operator+=( const char *str ) { if ( !str ) return *this; // nothing to append detach(); uint len1 = length(); uint len2 = qstrlen(str); - if ( !QByteArray::resize( len1 + len2 + 1 ) ) + if ( !QByteArray::resize( len1 + len2 + 1, QByteArray::SpeedOptim ) ) return *this; // no memory memcpy( data() + len1, str, len2 + 1 ); return *this; } /*! \overload Appends character \a c to the string and returns a reference to the string. */ QCString &QCString::operator+=( char c ) { detach(); uint len = length(); - if ( !QByteArray::resize( len + 2 ) ) + if ( !QByteArray::resize( len + 2, QByteArray::SpeedOptim ) ) return *this; // no memory *(data() + len) = c; *(data() + len+1) = '\0'; return *this; } /***************************************************************************** QCString stream functions *****************************************************************************/ #ifndef QT_NO_DATASTREAM /*! \relates QCString Writes string \a str to the stream \a s. \sa \link datastreamformat.html Format of the QDataStream operators \endlink */ QDataStream &operator<<( QDataStream &s, const QCString &str ) { return s.writeBytes( str.data(), str.size() ); } /*! \relates QCString Reads a string into \a str from the stream \a s. \sa \link datastreamformat.html Format of the QDataStream operators \endlink */ QDataStream &operator>>( QDataStream &s, QCString &str ) { str.detach(); 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.QByteArray::resize( (uint)len )) {// resize string #if defined(QT_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 /***************************************************************************** Documentation for related functions *****************************************************************************/ /*! \fn bool operator==( const QCString &s1, const QCString &s2 ) \relates QCString Returns TRUE if \a s1 and \a s2 are equal; otherwise returns FALSE. Equivalent to qstrcmp(\a s1, \a s2) == 0. diff --git a/qmake/tools/qdatastream.cpp b/qmake/tools/qdatastream.cpp index 9c573c7..51a1448 100644 --- a/qmake/tools/qdatastream.cpp +++ b/qmake/tools/qdatastream.cpp @@ -689,130 +689,138 @@ QDataStream &QDataStream::operator>>( double &f ) Reads the '\0'-terminated string \a s from the stream and returns a reference to the stream. Space for the string is allocated using \c new -- the caller must destroy it with delete[]. */ QDataStream &QDataStream::operator>>( char *&s ) { uint len = 0; return readBytes( s, len ); } /*! Reads the buffer \a s from the stream and returns a reference to the stream. The buffer \a s is allocated using \c new. Destroy it with the \c delete[] operator. If the length is zero or \a s cannot be allocated, \a s is set to 0. The \a l parameter will be set to the length of the buffer. The serialization format is a Q_UINT32 length specifier first, then \a l bytes of data. Note that the data is \e not encoded. \sa readRawBytes(), writeBytes() */ QDataStream &QDataStream::readBytes( char *&s, uint &l ) { CHECK_STREAM_PRECOND Q_UINT32 len; *this >> len; // first read length spec l = (uint)len; if ( len == 0 || eof() ) { s = 0; return *this; } else { s = new char[len]; // create char array Q_CHECK_PTR( s ); if ( !s ) // no memory return *this; return readRawBytes( s, (uint)len ); } } /*! Reads \a len bytes from the stream into \a s and returns a reference to the stream. The buffer \a s must be preallocated. The data is \e not encoded. \sa readBytes(), QIODevice::readBlock(), writeRawBytes() */ QDataStream &QDataStream::readRawBytes( char *s, uint len ) { CHECK_STREAM_PRECOND if ( printable ) { // printable data register Q_INT8 *p = (Q_INT8*)s; - while ( len-- ) - *this >> *p++; + if ( version() < 4 ) { + while ( len-- ) { + Q_INT32 tmp; + *this >> tmp; + *p++ = tmp; + } + } else { + while ( len-- ) + *this >> *p++; + } } else { // read data char array dev->readBlock( s, len ); } return *this; } /***************************************************************************** QDataStream write functions *****************************************************************************/ /*! \overload QDataStream &QDataStream::operator<<( Q_UINT8 i ) Writes an unsigned byte, \a i, to the stream and returns a reference to the stream. */ /*! Writes a signed byte, \a i, to the stream and returns a reference to the stream. */ QDataStream &QDataStream::operator<<( Q_INT8 i ) { CHECK_STREAM_PRECOND if ( printable && (i == '\\' || !isprint((uchar) i)) ) { char buf[6]; // write octal code buf[0] = '\\'; buf[1] = '0' + ((i >> 6) & 0x07); buf[2] = '0' + ((i >> 3) & 0x07); buf[3] = '0' + (i & 0x07); buf[4] = '\0'; dev->writeBlock( buf, 4 ); } else { dev->putch( i ); } return *this; } /*! \overload QDataStream &QDataStream::operator<<( Q_UINT16 i ) Writes an unsigned 16-bit integer, \a i, to the stream and returns a reference to the stream. */ /*! \overload Writes a signed 16-bit integer, \a i, to the stream and returns a reference to the stream. */ QDataStream &QDataStream::operator<<( Q_INT16 i ) { CHECK_STREAM_PRECOND if ( printable ) { // printable data char buf[16]; sprintf( buf, "%d\n", i ); dev->writeBlock( buf, strlen(buf) ); } else if ( noswap ) { // no conversion needed @@ -951,74 +959,80 @@ QDataStream &QDataStream::operator<<( double f ) b[5] = *p++; b[4] = *p++; b[3] = *p++; b[2] = *p++; b[1] = *p++; b[0] = *p; dev->writeBlock( b, 8 ); } return *this; } /*! \overload Writes the '\0'-terminated string \a s to the stream and returns a reference to the stream. The string is serialized using writeBytes(). */ QDataStream &QDataStream::operator<<( const char *s ) { if ( !s ) { *this << (Q_UINT32)0; return *this; } uint len = qstrlen( s ) + 1; // also write null terminator *this << (Q_UINT32)len; // write length specifier return writeRawBytes( s, len ); } /*! Writes the length specifier \a len and the buffer \a s to the stream and returns a reference to the stream. The \a len is serialized as a Q_UINT32, followed by \a len bytes from \a s. Note that the data is \e not encoded. \sa writeRawBytes(), readBytes() */ QDataStream &QDataStream::writeBytes(const char *s, uint len) { CHECK_STREAM_PRECOND *this << (Q_UINT32)len; // write length specifier if ( len ) writeRawBytes( s, len ); return *this; } /*! Writes \a len bytes from \a s to the stream and returns a reference to the stream. The data is \e not encoded. \sa writeBytes(), QIODevice::writeBlock(), readRawBytes() */ QDataStream &QDataStream::writeRawBytes( const char *s, uint len ) { CHECK_STREAM_PRECOND if ( printable ) { // write printable - register Q_INT8 *p = (Q_INT8*)s; - while ( len-- ) - *this << *p++; + if ( version() < 4 ) { + register char *p = (char *)s; + while ( len-- ) + *this << *p++; + } else { + register Q_INT8 *p = (Q_INT8*)s; + while ( len-- ) + *this << *p++; + } } else { // write data char array dev->writeBlock( s, len ); } return *this; } #endif // QT_NO_DATASTREAM diff --git a/qmake/tools/qdatetime.cpp b/qmake/tools/qdatetime.cpp index 93e40a8..3137877 100644 --- a/qmake/tools/qdatetime.cpp +++ b/qmake/tools/qdatetime.cpp @@ -1,102 +1,101 @@ /**************************************************************************** ** $Id$ ** ** Implementation of date and time classes ** ** Created : 940124 ** -** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** Copyright (C) 1992-2002 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. ** **********************************************************************/ -// Get the system specific includes and defines #include "qplatformdefs.h" #include "qdatetime.h" #include "qdatastream.h" #include "qregexp.h" #include <stdio.h> #ifndef Q_OS_TEMP #include <time.h> #endif #if defined(Q_OS_WIN32) #include <windows.h> #endif static const uint FIRST_DAY = 2361222; // Julian day for 1752-09-14 static const int FIRST_YEAR = 1752; // ### wrong for many countries static const uint SECS_PER_DAY = 86400; static const uint MSECS_PER_DAY = 86400000; static const uint SECS_PER_HOUR = 3600; static const uint MSECS_PER_HOUR= 3600000; static const uint SECS_PER_MIN = 60; static const uint MSECS_PER_MIN = 60000; static const short monthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static const char * const qt_shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; #ifndef QT_NO_DATESTRING /***************************************************************************** Some static function used by QDate, QTime and QDateTime *****************************************************************************/ // Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens static QString getFmtString( const QString& f, const QTime* dt = 0, const QDate* dd = 0, bool am_pm = FALSE ) { if ( f.isEmpty() ) return QString::null; QString buf = f; if ( dt ) { if ( f == "h" ) { if ( ( am_pm ) && ( dt->hour() > 12 ) ) buf = QString::number( dt->hour() - 12 ); else if ( ( am_pm ) && ( dt->hour() == 0 ) ) buf = "12"; else buf = QString::number( dt->hour() ); } else if ( f == "hh" ) { if ( ( am_pm ) && ( dt->hour() > 12 ) ) buf = QString::number( dt->hour() - 12 ).rightJustify( 2, '0', TRUE ); else if ( ( am_pm ) && ( dt->hour() == 0 ) ) buf = "12"; else buf = QString::number( dt->hour() ).rightJustify( 2, '0', TRUE ); } else if ( f == "m" ) { buf = QString::number( dt->minute() ); } else if ( f == "mm" ) { buf = QString::number( dt->minute() ).rightJustify( 2, '0', TRUE ); } else if ( f == "s" ) { @@ -834,230 +833,248 @@ QDate QDate::addDays( int ndays ) const return d; } /*! Returns a QDate object containing a date \a nmonths later than the date of this object (or earlier if \a nmonths is negative). \sa addDays() addYears() */ QDate QDate::addMonths( int nmonths ) const { int y, m, d; julianToGregorian( jd, y, m, d ); while ( nmonths != 0 ) { if ( nmonths < 0 && nmonths + 12 <= 0 ) { y--; nmonths+=12; } else if ( nmonths < 0 ) { m+= nmonths; nmonths = 0; if ( m <= 0 ) { --y; m+=12; } } else if ( nmonths - 12 >= 0 ) { y++; nmonths-=12; } else if ( m == 12 ) { y++; m = 0; } else { m+= nmonths; nmonths = 0; if ( m > 12 ) { ++y; m -= 12; } } } QDate tmp(y,m,1); if( d > tmp.daysInMonth() ) d = tmp.daysInMonth(); QDate date(y, m, d); return date; } /*! Returns a QDate object containing a date \a nyears later than the date of this object (or earlier if \a nyears is negative). \sa addDays(), addMonths() */ QDate QDate::addYears( int nyears ) const { int y, m, d; julianToGregorian( jd, y, m, d ); y += nyears; + + QDate tmp(y,m,1); + + if( d > tmp.daysInMonth() ) + d = tmp.daysInMonth(); + QDate date(y, m, d); return date; } /*! Returns the number of days from this date to \a d (which is negative if \a d is earlier than this date). Example: \code QDate d1( 1995, 5, 17 ); // May 17th 1995 QDate d2( 1995, 5, 20 ); // May 20th 1995 d1.daysTo( d2 ); // returns 3 d2.daysTo( d1 ); // returns -3 \endcode \sa addDays() */ int QDate::daysTo( const QDate &d ) const { return d.jd - jd; } /*! \fn bool QDate::operator==( const QDate &d ) const Returns TRUE if this date is equal to \a d; otherwise returns FALSE. */ /*! \fn bool QDate::operator!=( const QDate &d ) const Returns TRUE if this date is different from \a d; otherwise returns FALSE. */ /*! \fn bool QDate::operator<( const QDate &d ) const Returns TRUE if this date is earlier than \a d, otherwise returns FALSE. */ /*! \fn bool QDate::operator<=( const QDate &d ) const Returns TRUE if this date is earlier than or equal to \a d, otherwise returns FALSE. */ /*! \fn bool QDate::operator>( const QDate &d ) const Returns TRUE if this date is later than \a d, otherwise returns FALSE. */ /*! \fn bool QDate::operator>=( const QDate &d ) const Returns TRUE if this date is later than or equal to \a d, otherwise returns FALSE. */ /*! \overload Returns the current date, as reported by the system clock. \sa QTime::currentTime(), QDateTime::currentDateTime() */ QDate QDate::currentDate() { return currentDate( Qt::LocalTime ); } /*! Returns the current date, as reported by the system clock, for the TimeSpec \a ts. The default TimeSpec is LocalTime. \sa QTime::currentTime(), QDateTime::currentDateTime(), Qt::TimeSpec */ QDate QDate::currentDate( Qt::TimeSpec ts ) { QDate d; #if defined(Q_OS_WIN32) SYSTEMTIME t; memset( &t, 0, sizeof(SYSTEMTIME) ); if ( ts == Qt::LocalTime ) GetLocalTime( &t ); else GetSystemTime( &t ); d.jd = gregorianToJulian( t.wYear, t.wMonth, t.wDay ); #else + // posix compliant system time_t ltime; time( <ime ); tm *t; + +# if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant versions of localtime() and gmtime() where available + tm res; + if ( ts == Qt::LocalTime ) + t = localtime_r( <ime, &res ); + else + t = gmtime_r( <ime, &res ); +# else if ( ts == Qt::LocalTime ) t = localtime( <ime ); - else + else t = gmtime( <ime ); +# endif // QT_THREAD_SUPPORT && _POSIX_THREAD_SAFE_FUNCTIONS + d.jd = gregorianToJulian( t->tm_year + 1900, t->tm_mon + 1, t->tm_mday ); #endif return d; } #ifndef QT_NO_DATESTRING /*! Returns the QDate represented by the string \a s, using the format \a f, or an invalid date if the string cannot be parsed. Note for \c Qt::TextDate: It is recommended that you use the English short month names (e.g. "Jan"). Although localized month names can also be used, they depend on the user's locale settings. \warning \c Qt::LocalDate cannot be used here. */ QDate QDate::fromString( const QString& s, Qt::DateFormat f ) { if ( ( s.isEmpty() ) || ( f == Qt::LocalDate ) ) { #if defined(QT_CHECK_RANGE) qWarning( "QDate::fromString: Parameter out of range." ); #endif return QDate(); } switch ( f ) { case Qt::ISODate: { int year( s.mid( 0, 4 ).toInt() ); int month( s.mid( 5, 2 ).toInt() ); int day( s.mid( 8, 2 ).toInt() ); if ( year && month && day ) return QDate( year, month, day ); } break; default: #ifndef QT_NO_TEXTDATE case Qt::TextDate: { /* This will fail gracefully if the input string doesn't contain any space. */ int monthPos = s.find( ' ' ) + 1; int dayPos = s.find( ' ', monthPos ) + 1; QString monthName( s.mid(monthPos, dayPos - monthPos - 1) ); int month = -1; // try English names first for ( int i = 0; i < 12; i++ ) { if ( monthName == qt_shortMonthNames[i] ) { month = i + 1; break; } } // try the localized names if ( month == -1 ) { for ( int i = 0; i < 12; i++ ) { if ( monthName == shortMonthName( i + 1 ) ) { month = i + 1; break; } } @@ -1494,282 +1511,293 @@ QTime QTime::addMSecs( int ms ) const t.ds = ((int)ds + ms + negdays*MSECS_PER_DAY) % MSECS_PER_DAY; } else { t.ds = ((int)ds + ms) % MSECS_PER_DAY; } return t; } /*! Returns the number of milliseconds from this time to \a t (which is negative if \a t is earlier than this time). Because QTime measures time within a day and there are 86400 seconds in a day, the result is always between -86400 and 86400s. \sa secsTo() */ int QTime::msecsTo( const QTime &t ) const { return (int)t.ds - (int)ds; } /*! \fn bool QTime::operator==( const QTime &t ) const Returns TRUE if this time is equal to \a t; otherwise returns FALSE. */ /*! \fn bool QTime::operator!=( const QTime &t ) const Returns TRUE if this time is different from \a t; otherwise returns FALSE. */ /*! \fn bool QTime::operator<( const QTime &t ) const Returns TRUE if this time is earlier than \a t; otherwise returns FALSE. */ /*! \fn bool QTime::operator<=( const QTime &t ) const Returns TRUE if this time is earlier than or equal to \a t; otherwise returns FALSE. */ /*! \fn bool QTime::operator>( const QTime &t ) const Returns TRUE if this time is later than \a t; otherwise returns FALSE. */ /*! \fn bool QTime::operator>=( const QTime &t ) const Returns TRUE if this time is later than or equal to \a t; otherwise returns FALSE. */ -/*! +/*! \overload Returns the current time as reported by the system clock. Note that the accuracy depends on the accuracy of the underlying operating system; not all systems provide 1-millisecond accuracy. */ QTime QTime::currentTime() { return currentTime( Qt::LocalTime ); } /*! Returns the current time as reported by the system clock, for the TimeSpec \a ts. The default TimeSpec is LocalTime. Note that the accuracy depends on the accuracy of the underlying operating system; not all systems provide 1-millisecond accuracy. \sa Qt::TimeSpec */ QTime QTime::currentTime( Qt::TimeSpec ts ) { QTime t; currentTime( &t, ts ); return t; } #ifndef QT_NO_DATESTRING /*! Returns the representation \a s as a QTime using the format \a f, or an invalid time if this is not possible. \warning Note that \c Qt::LocalDate cannot be used here. */ QTime QTime::fromString( const QString& s, Qt::DateFormat f ) { if ( ( s.isEmpty() ) || ( f == Qt::LocalDate ) ) { #if defined(QT_CHECK_RANGE) qWarning( "QTime::fromString: Parameter out of range." ); #endif return QTime(); } int hour( s.mid( 0, 2 ).toInt() ); int minute( s.mid( 3, 2 ).toInt() ); int second( s.mid( 6, 2 ).toInt() ); int msec( s.mid( 9, 3 ).toInt() ); return QTime( hour, minute, second, msec ); } #endif /*! \internal \obsolete Fetches the current time and returns TRUE if the time is within one minute after midnight, otherwise FALSE. The return value is used by QDateTime::currentDateTime() to ensure that the date there is correct. */ bool QTime::currentTime( QTime *ct ) { return currentTime( ct, Qt::LocalTime ); } /*! \internal Fetches the current time, for the TimeSpec \a ts, and returns TRUE if the time is within one minute after midnight, otherwise FALSE. The return value is used by QDateTime::currentDateTime() to ensure that the date there is correct. The default TimeSpec is LocalTime. \sa Qt::TimeSpec */ bool QTime::currentTime( QTime *ct, Qt::TimeSpec ts ) { if ( !ct ) { #if defined(QT_CHECK_NULL) qWarning( "QTime::currentTime(QTime *): Null pointer not allowed" ); #endif return FALSE; } #if defined(Q_OS_WIN32) SYSTEMTIME t; if ( ts == Qt::LocalTime ) { GetLocalTime( &t ); } else { GetSystemTime( &t ); } ct->ds = (uint)( MSECS_PER_HOUR*t.wHour + MSECS_PER_MIN*t.wMinute + 1000*t.wSecond + t.wMilliseconds ); #elif defined(Q_OS_UNIX) + // posix compliant system struct timeval tv; gettimeofday( &tv, 0 ); time_t ltime = tv.tv_sec; tm *t; - if ( ts == Qt::LocalTime ) { + +# if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant versions of localtime() and gmtime() where available + tm res; + if ( ts == Qt::LocalTime ) + t = localtime_r( <ime, &res ); + else + t = gmtime_r( <ime, &res ); +# else + if ( ts == Qt::LocalTime ) t = localtime( <ime ); - } else { + else t = gmtime( <ime ); - } +# endif // QT_THREAD_SUPPORT && _POSIX_THREAD_SAFE_FUNCTIONS + ct->ds = (uint)( MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec + tv.tv_usec / 1000 ); #else time_t ltime; // no millisecond resolution ::time( <ime ); tm *t; - if ( ts == Qt::LocalTime ) + if ( ts == Qt::LocalTime ) localtime( <ime ); else gmtime( <ime ); ct->ds = (uint) ( MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec ); #endif // 00:00.00 to 00:00.59.999 is considered as "midnight or right after" return ct->ds < (uint) MSECS_PER_MIN; } /*! \overload Returns TRUE if the specified time is valid; otherwise returns FALSE. The time is valid if \a h is in the range 0..23, \a m and \a s are in the range 0..59, and \a ms is in the range 0..999. Example: \code QTime::isValid(21, 10, 30); // returns TRUE QTime::isValid(22, 5, 62); // returns FALSE \endcode */ bool QTime::isValid( int h, int m, int s, int ms ) { return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000; } /*! Sets this time to the current time. This is practical for timing: \code QTime t; - t.start(); // start clock - ... // some lengthy task - qDebug( "%d\n", t.elapsed() ); // prints the number of msecs elapsed + t.start(); + some_lengthy_task(); + qDebug( "Time elapsed: %d ms", t.elapsed() ); \endcode \sa restart(), elapsed(), currentTime() */ void QTime::start() { *this = currentTime(); } /*! Sets this time to the current time and returns the number of milliseconds that have elapsed since the last time start() or restart() was called. This function is guaranteed to be atomic and is thus very handy for repeated measurements. Call start() to start the first measurement and then restart() for each later measurement. Note that the counter wraps to zero 24 hours after the last call to start() or restart(). \warning If the system's clock setting has been changed since the last time start() or restart() was called, the result is undefined. This can happen when daylight savings time is turned on or off. \sa start(), elapsed(), currentTime() */ int QTime::restart() { QTime t = currentTime(); int n = msecsTo( t ); if ( n < 0 ) // passed midnight n += 86400*1000; *this = t; return n; } /*! Returns the number of milliseconds that have elapsed since the last time start() or restart() was called. Note that the counter wraps to zero 24 hours after the last call to start() or restart. Note that the accuracy depends on the accuracy of the underlying operating system; not all systems provide 1-millisecond accuracy. \warning If the system's clock setting has been changed since the last time start() or restart() was called, the result is undefined. This can happen when daylight savings time is turned on or off. \sa start(), restart() */ int QTime::elapsed() const { int n = msecsTo( currentTime() ); if ( n < 0 ) // passed midnight n += 86400*1000; return n; @@ -1899,138 +1927,156 @@ QDateTime::QDateTime( const QDate &date, const QTime &time ) /*! \fn void QDateTime::setTime( const QTime &time ) Sets the time part of this datetime to \a time. \sa time(), setDate() */ /*! Returns the datetime as the number of seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (UTC). On systems that do not support timezones, this function will behave as if local time were UTC. \sa setTime_t() */ uint QDateTime::toTime_t() const { tm brokenDown; brokenDown.tm_sec = t.second(); brokenDown.tm_min = t.minute(); brokenDown.tm_hour = t.hour(); brokenDown.tm_mday = d.day(); brokenDown.tm_mon = d.month() - 1; brokenDown.tm_year = d.year() - 1900; brokenDown.tm_isdst = -1; int secsSince1Jan1970UTC = (int) mktime( &brokenDown ); if ( secsSince1Jan1970UTC < -1 ) secsSince1Jan1970UTC = -1; return (uint) secsSince1Jan1970UTC; } /*! \overload Convenience function that sets the date and time to local time based on the given UTC time. */ void QDateTime::setTime_t( uint secsSince1Jan1970UTC ) { setTime_t( secsSince1Jan1970UTC, Qt::LocalTime ); } /*! Sets the date and time to \a ts time (\c Qt::LocalTime or \c Qt::UTC) given the number of seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (UTC). On systems that do not support timezones this function will behave as if local time were UTC. On Windows, only a subset of \a secsSince1Jan1970UTC values are supported, as Windows starts counting from 1980. \sa toTime_t() */ void QDateTime::setTime_t( uint secsSince1Jan1970UTC, Qt::TimeSpec ts ) { time_t tmp = (time_t) secsSince1Jan1970UTC; tm *brokenDown = 0; + +#if defined(Q_OS_UNIX) && defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // posix compliant system + // use the reentrant versions of localtime() and gmtime() where available + tm res; + if ( ts == Qt::LocalTime ) + brokenDown = localtime_r( &tmp, &res ); + if ( !brokenDown ) { + brokenDown = gmtime_r( &tmp, &res ); + if ( !brokenDown ) { + d.jd = QDate::gregorianToJulian( 1970, 1, 1 ); + t.ds = 0; + return; + } + } +#else if ( ts == Qt::LocalTime ) brokenDown = localtime( &tmp ); if ( !brokenDown ) { brokenDown = gmtime( &tmp ); if ( !brokenDown ) { d.jd = QDate::gregorianToJulian( 1970, 1, 1 ); t.ds = 0; return; } } +#endif + d.jd = QDate::gregorianToJulian( brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday ); t.ds = MSECS_PER_HOUR * brokenDown->tm_hour + MSECS_PER_MIN * brokenDown->tm_min + 1000 * brokenDown->tm_sec; } #ifndef QT_NO_DATESTRING #ifndef QT_NO_SPRINTF /*! \overload Returns the datetime as a string. The \a f parameter determines the format of the string. If \a f is \c Qt::TextDate, the string format is "Wed May 20 03:40:13 1998" (using QDate::shortDayName(), QDate::shortMonthName(), and QTime::toString() to generate the string, so the day and month names will have localized names). If \a f is \c Qt::ISODate, the string format corresponds to the ISO 8601 extended specification for representations of dates and times, which is YYYY-MM-DDTHH:MM:SS. If \a f is \c Qt::LocalDate, the string format depends on the locale settings of the system. If the format \a f is invalid, toString() returns a null string. \sa QDate::toString() QTime::toString() */ QString QDateTime::toString( Qt::DateFormat f ) const { if ( f == Qt::ISODate ) { return d.toString( Qt::ISODate ) + "T" + t.toString( Qt::ISODate ); } #ifndef QT_NO_TEXTDATE else if ( f == Qt::TextDate ) { #ifndef Q_WS_WIN QString buf = d.shortDayName( d.dayOfWeek() ); buf += ' '; buf += d.shortMonthName( d.month() ); buf += ' '; buf += QString().setNum( d.day() ); buf += ' '; #else QString buf; QString winstr; QT_WA( { TCHAR out[255]; GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255 ); winstr = QString::fromUcs2( (ushort*)out ); } , { char out[255]; GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_ILDATE, (char*)&out, 255 ); winstr = QString::fromLocal8Bit( out ); } ); switch ( winstr.toInt() ) { case 1: buf = d.shortDayName( d.dayOfWeek() ) + " " + QString().setNum( d.day() ) + ". " + d.shortMonthName( d.month() ) + " "; break; default: buf = d.shortDayName( d.dayOfWeek() ) + " " + d.shortMonthName( d.month() ) + " " + QString().setNum( d.day() ) + " "; @@ -2239,129 +2285,129 @@ bool QDateTime::operator==( const QDateTime &dt ) const } /*! Returns TRUE if this datetime is different from \a dt; otherwise returns FALSE. \sa operator==() */ bool QDateTime::operator!=( const QDateTime &dt ) const { return t != dt.t || d != dt.d; } /*! Returns TRUE if this datetime is earlier than \a dt; otherwise returns FALSE. */ bool QDateTime::operator<( const QDateTime &dt ) const { if ( d < dt.d ) return TRUE; return d == dt.d ? t < dt.t : FALSE; } /*! Returns TRUE if this datetime is earlier than or equal to \a dt; otherwise returns FALSE. */ bool QDateTime::operator<=( const QDateTime &dt ) const { if ( d < dt.d ) return TRUE; return d == dt.d ? t <= dt.t : FALSE; } /*! Returns TRUE if this datetime is later than \a dt; otherwise returns FALSE. */ bool QDateTime::operator>( const QDateTime &dt ) const { if ( d > dt.d ) return TRUE; return d == dt.d ? t > dt.t : FALSE; } /*! Returns TRUE if this datetime is later than or equal to \a dt; otherwise returns FALSE. */ bool QDateTime::operator>=( const QDateTime &dt ) const { if ( d > dt.d ) return TRUE; return d == dt.d ? t >= dt.t : FALSE; } /*! \overload - + Returns the current datetime, as reported by the system clock. \sa QDate::currentDate(), QTime::currentTime() */ QDateTime QDateTime::currentDateTime() { return currentDateTime( Qt::LocalTime ); } /*! Returns the current datetime, as reported by the system clock, for the TimeSpec \a ts. The default TimeSpec is LocalTime. \sa QDate::currentDate(), QTime::currentTime(), Qt::TimeSpec */ QDateTime QDateTime::currentDateTime( Qt::TimeSpec ts ) { QDateTime dt; QTime t; dt.setDate( QDate::currentDate(ts) ); if ( QTime::currentTime(&t, ts) ) // midnight or right after? dt.setDate( QDate::currentDate(ts) ); // fetch date again dt.setTime( t ); return dt; } #ifndef QT_NO_DATESTRING /*! Returns the QDateTime represented by the string \a s, using the format \a f, or an invalid datetime if this is not possible. Note for \c Qt::TextDate: It is recommended that you use the English short month names (e.g. "Jan"). Although localized month names can also be used, they depend on the user's locale settings. \warning Note that \c Qt::LocalDate cannot be used here. */ QDateTime QDateTime::fromString( const QString& s, Qt::DateFormat f ) { if ( ( s.isEmpty() ) || ( f == Qt::LocalDate ) ) { #if defined(QT_CHECK_RANGE) qWarning( "QDateTime::fromString: Parameter out of range" ); #endif return QDateTime(); } if ( f == Qt::ISODate ) { return QDateTime( QDate::fromString( s.mid(0,10), Qt::ISODate ), QTime::fromString( s.mid(11), Qt::ISODate ) ); } #if !defined(QT_NO_REGEXP) && !defined(QT_NO_TEXTDATE) else if ( f == Qt::TextDate ) { QString monthName( s.mid( 4, 3 ) ); int month = -1; // Assume that English monthnames are the default for ( int i = 0; i < 12; ++i ) { if ( monthName == qt_shortMonthNames[i] ) { month = i + 1; break; } } // If English names can't be found, search the localized ones if ( month == -1 ) { diff --git a/qmake/tools/qdir.cpp b/qmake/tools/qdir.cpp index 418ea49..5714878 100644 --- a/qmake/tools/qdir.cpp +++ b/qmake/tools/qdir.cpp @@ -1,116 +1,121 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QDir class ** ** Created : 950427 ** -** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** Copyright (C) 1992-2003 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. ** **********************************************************************/ #include "qplatformdefs.h" #include "qdir.h" #ifndef QT_NO_DIR #include <private/qdir_p.h> #include "qfileinfo.h" #include "qregexp.h" #include "qstringlist.h" -#include <stdlib.h> -#include <ctype.h> +#include <limits.h> +#if defined(Q_FS_FAT) && !defined(Q_OS_UNIX) +const bool CaseSensitiveFS = FALSE; +#else +const bool CaseSensitiveFS = TRUE; +#endif /*! \class QDir + \reentrant \brief The QDir class provides access to directory structures and their contents in a platform-independent way. \ingroup io \mainclass A QDir is used to manipulate path names, access information regarding paths and files, and manipulate the underlying file system. A QDir can point to a file using either a relative or an absolute path. Absolute paths begin with the directory separator "/" (optionally preceded by a drive specification under Windows). If you always use "/" as a directory separator, Qt will translate your paths to conform to the underlying operating system. Relative file names begin with a directory name or a file name and specify a path relative to the current directory. The "current" path refers to the application's working directory. A QDir's own path is set and retrieved with setPath() and path(). An example of an absolute path is the string "/tmp/quartz", a relative path might look like "src/fatlib". You can use the function isRelative() to check if a QDir is using a relative or an absolute file path. Call convertToAbs() to convert a relative QDir to an absolute one. For a simplified path use cleanDirPath(). To obtain a path which has no symbolic links or redundant ".." elements use canonicalPath(). The path can be set with setPath(), and changed with cd() and cdUp(). QDir provides several static functions, for example, setCurrent() to set the application's working directory and currentDirPath() to retrieve the application's working directory. Access to some common paths is provided with the static functions, current(), home() and root() which return QDir objects or currentDirPath(), homeDirPath() and rootDirPath() which return the path as a string. The number of entries in a directory is returned by count(). Obtain a string list of the names of all the files and directories in a directory with entryList(). If you prefer a list of QFileInfo pointers use entryInfoList(). Both these functions can apply a name filter, an attributes filter (e.g. read-only, files not directories, etc.), and a sort order. The filters and sort may be set with calls to setNameFilter(), setFilter() and setSorting(). They may also be specified in the entryList() and entryInfoList()'s arguments. Create a new directory with mkdir(), rename a directory with rename() and remove an existing directory with rmdir(). Remove a file with remove(). You can interrogate a directory with exists(), isReadable() and isRoot(). To get a path with a filename use filePath(), and to get a directory name use dirName(); neither of these functions checks for the existence of the file or directory. The list of root directories is provided by drives(); on Unix systems this returns a list containing one root directory, "/"; on Windows the list will usually contain "C:/", and possibly "D:/", etc. If you need the path in a form suitable for the underlying operating system use convertSeparators(). Examples: @@ -169,128 +174,136 @@ QDir::QDir() { dPath = QString::fromLatin1("."); init(); } /*! Constructs a QDir with path \a path, that filters its entries by name using \a nameFilter and by attributes using \a filterSpec. It also sorts the names using \a sortSpec. The default \a nameFilter is an empty string, which excludes nothing; the default \a filterSpec is \c All, which also means exclude nothing. The default \a sortSpec is \c Name|IgnoreCase, i.e. sort by name case-insensitively. Example that lists all the files in "/tmp": \code QDir d( "/tmp" ); for ( int i = 0; i < d.count(); i++ ) printf( "%s\n", d[i] ); \endcode If \a path is "" or QString::null, QDir uses "." (the current directory). If \a nameFilter is "" or QString::null, QDir uses the name filter "*" (all files). Note that \a path need not exist. \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting() */ QDir::QDir( const QString &path, const QString &nameFilter, int sortSpec, int filterSpec ) { init(); dPath = cleanDirPath( path ); if ( dPath.isEmpty() ) dPath = QString::fromLatin1("."); nameFilt = nameFilter; if ( nameFilt.isEmpty() ) nameFilt = QString::fromLatin1("*"); filtS = (FilterSpec)filterSpec; sortS = (SortSpec)sortSpec; } /*! Constructs a QDir that is a copy of the directory \a d. \sa operator=() */ QDir::QDir( const QDir &d ) { dPath = d.dPath; fList = 0; fiList = 0; nameFilt = d.nameFilt; dirty = TRUE; allDirs = d.allDirs; filtS = d.filtS; sortS = d.sortS; } +/*! + Refreshes the directory information. +*/ +void QDir::refresh() const +{ + QDir* that = (QDir*) this; + that->dirty = TRUE; +} void QDir::init() { fList = 0; fiList = 0; nameFilt = QString::fromLatin1("*"); dirty = TRUE; allDirs = FALSE; filtS = All; sortS = SortSpec(Name | IgnoreCase); } /*! Destroys the QDir frees up its resources. */ QDir::~QDir() { delete fList; delete fiList; } /*! Sets the path of the directory to \a path. The path is cleaned of redundant ".", ".." and of multiple separators. No check is made to ensure that a directory with this path exists. The path can be either absolute or relative. Absolute paths begin with the directory separator "/" (optionally preceded by a drive specification under Windows). Relative file names begin with a directory name or a file name and specify a path relative to the current directory. An example of an absolute path is the string "/tmp/quartz", a relative path might look like "src/fatlib". \sa path(), absPath(), exists(), cleanDirPath(), dirName(), absFilePath(), isRelative(), convertToAbs() */ void QDir::setPath( const QString &path ) { dPath = cleanDirPath( path ); if ( dPath.isEmpty() ) dPath = QString::fromLatin1("."); dirty = TRUE; } /*! \fn QString QDir::path() const Returns the path, this may contain symbolic links, but never contains redundant ".", ".." or multiple separators. The returned path can be either absolute or relative (see setPath()). \sa setPath(), absPath(), exists(), cleanDirPath(), dirName(), absFilePath(), convertSeparators() */ /*! Returns the absolute path (a path that starts with "/" or with a drive specification), which may contain symbolic links, but never contains redundant ".", ".." or multiple separators. @@ -321,132 +334,158 @@ QString QDir::absPath() const No check is made to ensure that a directory with this name actually exists. \sa path(), absPath(), absFilePath(), exists(), QString::isNull() */ QString QDir::dirName() const { int pos = dPath.findRev( '/' ); if ( pos == -1 ) return dPath; return dPath.right( dPath.length() - pos - 1 ); } /*! Returns the path name of a file in the directory. Does \e not check if the file actually exists in the directory. If the QDir is relative the returned path name will also be relative. Redundant multiple separators or "." and ".." directories in \a fileName will not be removed (see cleanDirPath()). If \a acceptAbsPath is TRUE a \a fileName starting with a separator "/" will be returned without change. If \a acceptAbsPath is FALSE an absolute path will be prepended to the fileName and the resultant string returned. \sa absFilePath(), isRelative(), canonicalPath() */ QString QDir::filePath( const QString &fileName, bool acceptAbsPath ) const { if ( acceptAbsPath && !isRelativePath(fileName) ) return QString(fileName); QString tmp = dPath; if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && fileName[0] != '/') ) tmp += '/'; tmp += fileName; return tmp; } /*! Returns the absolute path name of a file in the directory. Does \e not check if the file actually exists in the directory. Redundant multiple separators or "." and ".." directories in \a fileName will not be removed (see cleanDirPath()). If \a acceptAbsPath is TRUE a \a fileName starting with a separator "/" will be returned without change. If \a acceptAbsPath is FALSE an absolute path will be prepended to the fileName and the resultant string returned. \sa filePath() */ QString QDir::absFilePath( const QString &fileName, bool acceptAbsPath ) const { if ( acceptAbsPath && !isRelativePath( fileName ) ) return fileName; QString tmp = absPath(); - if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && - fileName[0] != '/') ) - tmp += '/'; - tmp += fileName; +#ifdef Q_OS_WIN32 + if ( fileName[0].isLetter() && fileName[1] == ':' ) { + int drv = fileName.upper()[0].latin1() - 'A' + 1; + if ( _getdrive() != drv ) { + if ( qt_winunicode ) { + TCHAR buf[PATH_MAX]; + ::_tgetdcwd( drv, buf, PATH_MAX ); + tmp.setUnicodeCodes( (ushort*)buf, ::_tcslen(buf) ); + } else { + char buf[PATH_MAX]; + ::_getdcwd( drv, buf, PATH_MAX ); + tmp = buf; + } + if ( !tmp.endsWith("\\") ) + tmp += "\\"; + tmp += fileName.right( fileName.length() - 2 ); + int x; + for ( x = 0; x < (int) tmp.length(); x++ ) { + if ( tmp[x] == '\\' ) + tmp[x] = '/'; + } + } + } else +#endif + { + if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && + fileName[0] != '/') ) + tmp += '/'; + tmp += fileName; + } return tmp; } /*! Returns \a pathName with the '/' separators converted to separators that are appropriate for the underlying operating system. On Windows, convertSeparators("c:/winnt/system32") returns "c:\winnt\system32". The returned string may be the same as the argument on some operating systems, for example on Unix. */ QString QDir::convertSeparators( const QString &pathName ) { QString n( pathName ); #if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) for ( int i=0; i<(int)n.length(); i++ ) { if ( n[i] == '/' ) n[i] = '\\'; } #elif defined(Q_OS_MAC9) while(n.length() && n[0] == '/' ) n = n.right(n.length()-1); for ( int i=0; i<(int)n.length(); i++ ) { if ( n[i] == '/' ) n[i] = ':'; } if(n.contains(':') && n.left(1) != ':') n.prepend(':'); #endif return n; } /*! Changes the QDir's directory to \a dirName. If \a acceptAbsPath is TRUE a path starting with separator "/" will cause the function to change to the absolute directory. If \a acceptAbsPath is FALSE any number of separators at the beginning of \a dirName will be removed and the function will descend into \a dirName. Returns TRUE if the new directory exists and is readable; otherwise returns FALSE. Note that the logical cd() operation is not performed if the new directory does not exist. Calling cd( ".." ) is equivalent to calling cdUp(). \sa cdUp(), isReadable(), exists(), path() */ bool QDir::cd( const QString &dirName, bool acceptAbsPath ) { if ( dirName.isEmpty() || dirName==QString::fromLatin1(".") ) return TRUE; QString old = dPath; if ( acceptAbsPath && !isRelativePath(dirName) ) { dPath = cleanDirPath( dirName ); } else { if ( !isRoot() ) { @@ -873,144 +912,146 @@ bool QDir::exists() const */ bool QDir::isRelative() const { return isRelativePath( dPath ); } /*! Converts the directory path to an absolute path. If it is already absolute nothing is done. \sa isRelative() */ void QDir::convertToAbs() { dPath = absPath(); } /*! Makes a copy of QDir \a d and assigns it to this QDir. */ QDir &QDir::operator=( const QDir &d ) { dPath = d.dPath; delete fList; fList = 0; delete fiList; fiList = 0; nameFilt = d.nameFilt; dirty = TRUE; allDirs = d.allDirs; filtS = d.filtS; sortS = d.sortS; return *this; } /*! \overload Sets the directory path to be the given \a path. */ QDir &QDir::operator=( const QString &path ) { dPath = cleanDirPath( path ); dirty = TRUE; return *this; } /*! \fn bool QDir::operator!=( const QDir &d ) const Returns TRUE if directory \a d and this directory have different paths or different sort or filter settings; otherwise returns FALSE. Example: \code // The current directory is "/usr/local" QDir d1( "/usr/local/bin" ); QDir d2( "bin" ); - if ( d1 != d2 ) qDebug( "They differ\n" ); // This is printed + if ( d1 != d2 ) + qDebug( "They differ" ); \endcode */ /*! Returns TRUE if directory \a d and this directory have the same path and their sort and filter settings are the same; otherwise returns FALSE. Example: \code // The current directory is "/usr/local" QDir d1( "/usr/local/bin" ); QDir d2( "bin" ); d2.convertToAbs(); - if ( d1 == d2 ) qDebug( "They're the same\n" ); // This is printed + if ( d1 == d2 ) + qDebug( "They're the same" ); \endcode */ bool QDir::operator==( const QDir &d ) const { return dPath == d.dPath && nameFilt == d.nameFilt && allDirs == d.allDirs && filtS == d.filtS && sortS == d.sortS; } /*! Removes the file, \a fileName. If \a acceptAbsPath is TRUE a path starting with separator "/" will remove the file with the absolute path. If \a acceptAbsPath is FALSE any number of separators at the beginning of \a fileName will be removed and the resultant file name will be removed. Returns TRUE if the file is removed successfully; otherwise returns FALSE. */ bool QDir::remove( const QString &fileName, bool acceptAbsPath ) { if ( fileName.isEmpty() ) { #if defined(QT_CHECK_NULL) qWarning( "QDir::remove: Empty or null file name" ); #endif return FALSE; } QString p = filePath( fileName, acceptAbsPath ); return QFile::remove( p ); } /*! Checks for the existence of the file \a name. If \a acceptAbsPath is TRUE a path starting with separator "/" will check the file with the absolute path. If \a acceptAbsPath is FALSE any number of separators at the beginning of \a name will be removed and the resultant file name will be checked. Returns TRUE if the file exists; otherwise returns FALSE. \sa QFileInfo::exists(), QFile::exists() */ bool QDir::exists( const QString &name, bool acceptAbsPath ) //### const in 4.0 { if ( name.isEmpty() ) { #if defined(QT_CHECK_NULL) qWarning( "QDir::exists: Empty or null file name" ); #endif return FALSE; } QString tmp = filePath( name, acceptAbsPath ); return QFile::exists( tmp ); } /*! Returns the native directory separator; "/" under UNIX (including @@ -1026,190 +1067,197 @@ char QDir::separator() #if defined(Q_OS_UNIX) return '/'; #elif defined (Q_FS_FAT) || defined(Q_WS_WIN) return '\\'; #elif defined (Q_OS_MAC) return ':'; #else return '/'; #endif } /*! Returns the application's current directory. Use path() to access a QDir object's path. \sa currentDirPath(), QDir::QDir() */ QDir QDir::current() { return QDir( currentDirPath() ); } /*! Returns the home directory. Under Windows the \c HOME environment variable is used. If this does not exist the \c USERPROFILE environment variable is used. If that does not exist the path is formed by concatenating the \c HOMEDRIVE and \c HOMEPATH environment variables. If they don't exist the rootDirPath() is used (this uses the \c SystemDrive environment variable). If none of these exist "C:\" is used. Under non-Windows operating systems the \c HOME environment variable is used if it exists, otherwise rootDirPath() is used. \sa homeDirPath() */ QDir QDir::home() { return QDir( homeDirPath() ); } /*! Returns the root directory. \sa rootDirPath() drives() */ QDir QDir::root() { return QDir( rootDirPath() ); } /*! \fn QString QDir::homeDirPath() Returns the absolute path of the user's home directory. \sa home() */ -QStringList qt_makeFilterList( const QString &filter ) +QValueList<QRegExp> qt_makeFilterList( const QString &filter ) { + QValueList<QRegExp> regExps; if ( filter.isEmpty() ) - return QStringList(); + return regExps; QChar sep( ';' ); int i = filter.find( sep, 0 ); if ( i == -1 && filter.find( ' ', 0 ) != -1 ) sep = QChar( ' ' ); QStringList list = QStringList::split( sep, filter ); QStringList::Iterator it = list.begin(); - QStringList list2; + while ( it != list.end() ) { + regExps << QRegExp( (*it).stripWhiteSpace(), CaseSensitiveFS, TRUE ); + ++it; + } + return regExps; +} - for ( ; it != list.end(); ++it ) { - QString s = *it; - list2 << s.stripWhiteSpace(); +bool qt_matchFilterList( const QValueList<QRegExp>& filters, + const QString &fileName ) +{ + QValueList<QRegExp>::ConstIterator rit = filters.begin(); + while ( rit != filters.end() ) { + if ( (*rit).exactMatch(fileName) ) + return TRUE; + ++rit; } - return list2; + return FALSE; } + /*! \overload Returns TRUE if the \a fileName matches any of the wildcard (glob) patterns in the list of \a filters; otherwise returns FALSE. (See \link qregexp.html#wildcard-matching QRegExp wildcard matching.\endlink) \sa QRegExp::match() */ bool QDir::match( const QStringList &filters, const QString &fileName ) { QStringList::ConstIterator sit = filters.begin(); while ( sit != filters.end() ) { -#if defined(Q_FS_FAT) && !defined(Q_OS_UNIX) - QRegExp rx( *sit, FALSE, TRUE ); // The FAT FS is not case sensitive.. -#else - QRegExp rx( *sit, TRUE, TRUE ); // ..while others are. -#endif + QRegExp rx( *sit, CaseSensitiveFS, TRUE ); if ( rx.exactMatch(fileName) ) return TRUE; ++sit; } return FALSE; } /*! Returns TRUE if the \a fileName matches the wildcard (glob) pattern \a filter; otherwise returns FALSE. The \a filter may contain multiple patterns separated by spaces or semicolons. (See \link qregexp.html#wildcard-matching QRegExp wildcard matching.\endlink) \sa QRegExp::match() */ bool QDir::match( const QString &filter, const QString &fileName ) { - QStringList lst = qt_makeFilterList( filter ); - return match( lst, fileName ); + return qt_matchFilterList( qt_makeFilterList(filter), fileName ); } /*! Removes all multiple directory separators "/" and resolves any "."s or ".."s found in the path, \a filePath. Symbolic links are kept. This function does not return the canonical path, but rather the simplest version of the input. For example, "./local" becomes "local", "local/../bin" becomes "bin" and "/local/usr/../bin" becomes "/local/bin". \sa absPath() canonicalPath() */ QString QDir::cleanDirPath( const QString &filePath ) { QString name = filePath; QString newPath; if ( name.isEmpty() ) return name; slashify( name ); bool addedSeparator; if ( isRelativePath(name) ) { addedSeparator = TRUE; name.insert( 0, '/' ); } else { addedSeparator = FALSE; } int ePos, pos, upLevel; pos = ePos = name.length(); upLevel = 0; int len; while ( pos && (pos = name.findRev('/',--pos)) != -1 ) { len = ePos - pos - 1; if ( len == 2 && name.at(pos + 1) == '.' && name.at(pos + 2) == '.' ) { upLevel++; } else { if ( len != 0 && (len != 1 || name.at(pos + 1) != '.') ) { if ( !upLevel ) newPath = QString::fromLatin1("/") + name.mid(pos + 1, len) + newPath; else upLevel--; } } ePos = pos; } if ( addedSeparator ) { while ( upLevel-- ) newPath.insert( 0, QString::fromLatin1("/..") ); if ( !newPath.isEmpty() ) newPath.remove( 0, 1 ); else newPath = QString::fromLatin1("."); } else { if ( newPath.isEmpty() ) diff --git a/qmake/tools/qdir_unix.cpp b/qmake/tools/qdir_unix.cpp index 57fe3c5..6a7adda 100644 --- a/qmake/tools/qdir_unix.cpp +++ b/qmake/tools/qdir_unix.cpp @@ -1,291 +1,297 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QDir class ** ** Created : 950628 ** -** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** Copyright (C) 1992-2003 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 for Unix/X11 or for Qt/Embedded 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. ** **********************************************************************/ #include "qplatformdefs.h" #include "qdir.h" #ifndef QT_NO_DIR #include "qdir_p.h" #include "qfileinfo.h" #include "qregexp.h" #include "qstringlist.h" #ifdef QT_THREAD_SUPPORT # include <private/qmutexpool_p.h> #endif // QT_THREAD_SUPPORT #include <stdlib.h> #include <limits.h> +#include <errno.h> void QDir::slashify( QString& ) { } QString QDir::homeDirPath() { QString d; d = QFile::decodeName(getenv("HOME")); slashify( d ); if ( d.isNull() ) d = rootDirPath(); return d; } QString QDir::canonicalPath() const { QString r; - char cur[PATH_MAX+1]; - if ( ::getcwd( cur, PATH_MAX ) ) - if ( ::chdir(QFile::encodeName(dPath)) >= 0 ) { - char tmp[PATH_MAX+1]; - if ( ::getcwd( tmp, PATH_MAX ) ) - r = QFile::decodeName(tmp); - ::chdir( cur ); - } - - slashify( r ); + if ( ::getcwd( cur, PATH_MAX ) ) { + char tmp[PATH_MAX+1]; + if( ::realpath( QFile::encodeName( dPath ), tmp ) ) + r = QFile::decodeName( tmp ); + slashify( r ); + + // always make sure we go back to the current dir + ::chdir( cur ); + } return r; } bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const { #if defined(Q_OS_MACX) // Mac X doesn't support trailing /'s QString name = dirName; if (dirName[dirName.length() - 1] == "/") name = dirName.left( dirName.length() - 1 ); - return ::mkdir( QFile::encodeName(filePath(name,acceptAbsPath)), 0777 ) - == 0; + int status = + ::mkdir( QFile::encodeName(filePath(name,acceptAbsPath)), 0777 ); #else - return ::mkdir( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) - == 0; + int status = + ::mkdir( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ); #endif + return status == 0; } bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const { return ::rmdir( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; } bool QDir::isReadable() const { return ::access( QFile::encodeName(dPath), R_OK | X_OK ) == 0; } bool QDir::isRoot() const { return dPath == QString::fromLatin1("/"); } bool QDir::rename( const QString &name, const QString &newName, bool acceptAbsPaths ) { if ( name.isEmpty() || newName.isEmpty() ) { #if defined(QT_CHECK_NULL) qWarning( "QDir::rename: Empty or null file name(s)" ); #endif return FALSE; } QString fn1 = filePath( name, acceptAbsPaths ); QString fn2 = filePath( newName, acceptAbsPaths ); return ::rename( QFile::encodeName(fn1), QFile::encodeName(fn2) ) == 0; } bool QDir::setCurrent( const QString &path ) { int r; r = ::chdir( QFile::encodeName(path) ); return r >= 0; } QString QDir::currentDirPath() { QString result; struct stat st; if ( ::stat( ".", &st ) == 0 ) { char currentName[PATH_MAX+1]; if ( ::getcwd( currentName, PATH_MAX ) ) result = QFile::decodeName(currentName); #if defined(QT_DEBUG) if ( result.isNull() ) qWarning( "QDir::currentDirPath: getcwd() failed" ); #endif } else { #if defined(QT_DEBUG) qWarning( "QDir::currentDirPath: stat(\".\") failed" ); #endif } slashify( result ); return result; } QString QDir::rootDirPath() { QString d = QString::fromLatin1( "/" ); return d; } bool QDir::isRelativePath( const QString &path ) { int len = path.length(); if ( len == 0 ) return TRUE; return path[0] != '/'; } bool QDir::readDirEntries( const QString &nameFilter, int filterSpec, int sortSpec ) { int i; if ( !fList ) { fList = new QStringList; Q_CHECK_PTR( fList ); fiList = new QFileInfoList; Q_CHECK_PTR( fiList ); fiList->setAutoDelete( TRUE ); } else { fList->clear(); fiList->clear(); } - QStringList filters = qt_makeFilterList( nameFilter ); + QValueList<QRegExp> filters = qt_makeFilterList( nameFilter ); bool doDirs = (filterSpec & Dirs) != 0; bool doFiles = (filterSpec & Files) != 0; bool noSymLinks = (filterSpec & NoSymLinks) != 0; bool doReadable = (filterSpec & Readable) != 0; bool doWritable = (filterSpec & Writable) != 0; bool doExecable = (filterSpec & Executable) != 0; bool doHidden = (filterSpec & Hidden) != 0; bool doSystem = (filterSpec & System) != 0; -#if defined(Q_OS_OS2EMX) - //QRegExp wc( nameFilter, FALSE, TRUE ); // wild card, case insensitive -#else - //QRegExp wc( nameFilter, TRUE, TRUE ); // wild card, case sensitive -#endif QFileInfo fi; DIR *dir; dirent *file; dir = opendir( QFile::encodeName(dPath) ); if ( !dir ) return FALSE; // cannot read the directory - while ( (file = readdir(dir)) ) { +#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) + union { + struct dirent mt_file; + char b[sizeof(struct dirent) + MAXNAMLEN + 1]; + } u; + while ( readdir_r(dir, &u.mt_file, &file ) == 0 && file ) +#else + while ( (file = readdir(dir)) ) +#endif // QT_THREAD_SUPPORT && _POSIX_THREAD_SAFE_FUNCTIONS + { QString fn = QFile::decodeName(file->d_name); fi.setFile( *this, fn ); - if ( !match( filters, fn ) && !(allDirs && fi.isDir()) ) + if ( !qt_matchFilterList(filters, fn) && !(allDirs && fi.isDir()) ) continue; if ( (doDirs && fi.isDir()) || (doFiles && fi.isFile()) || (doSystem && (!fi.isFile() && !fi.isDir())) ) { if ( noSymLinks && fi.isSymLink() ) continue; if ( (filterSpec & RWEMask) != 0 ) if ( (doReadable && !fi.isReadable()) || (doWritable && !fi.isWritable()) || (doExecable && !fi.isExecutable()) ) continue; if ( !doHidden && fn[0] == '.' && fn != QString::fromLatin1(".") && fn != QString::fromLatin1("..") ) continue; fiList->append( new QFileInfo( fi ) ); } } if ( closedir(dir) != 0 ) { #if defined(QT_CHECK_NULL) qWarning( "QDir::readDirEntries: Cannot close the directory: %s", dPath.local8Bit().data() ); #endif } // Sort... if(fiList->count()) { QDirSortItem* si= new QDirSortItem[fiList->count()]; QFileInfo* itm; i=0; for (itm = fiList->first(); itm; itm = fiList->next()) si[i++].item = itm; qt_cmp_si_sortSpec = sortSpec; qsort( si, i, sizeof(si[0]), qt_cmp_si ); // put them back in the list fiList->setAutoDelete( FALSE ); fiList->clear(); int j; for ( j=0; j<i; j++ ) { fiList->append( si[j].item ); fList->append( si[j].item->fileName() ); } delete [] si; fiList->setAutoDelete( TRUE ); } if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && nameFilter == nameFilt ) dirty = FALSE; else dirty = TRUE; return TRUE; } const QFileInfoList * QDir::drives() { // at most one instance of QFileInfoList is leaked, and this variable // points to that list static QFileInfoList * knownMemoryLeak = 0; if ( !knownMemoryLeak ) { #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &knownMemoryLeak ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &knownMemoryLeak ) : 0 ); #endif // QT_THREAD_SUPPORT if ( !knownMemoryLeak ) { knownMemoryLeak = new QFileInfoList; // non-win32 versions both use just one root directory knownMemoryLeak->append( new QFileInfo( rootDirPath() ) ); } } return knownMemoryLeak; } #endif //QT_NO_DIR diff --git a/qmake/tools/qfile.cpp b/qmake/tools/qfile.cpp index a578b49..c088b55 100644 --- a/qmake/tools/qfile.cpp +++ b/qmake/tools/qfile.cpp @@ -27,129 +27,129 @@ ** ** 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. ** **********************************************************************/ #include "qplatformdefs.h" // POSIX Large File Support redefines open -> open64 #if defined(open) # undef open #endif // POSIX Large File Support redefines truncate -> truncate64 #if defined(truncate) # undef truncate #endif #include "qfile.h" extern bool qt_file_access( const QString& fn, int t ); /*! \class QFile qfile.h \reentrant \brief The QFile class is an I/O device that operates on files. \ingroup io \mainclass QFile is an I/O device for reading and writing binary and text files. A QFile may be used by itself or more conveniently with a QDataStream or QTextStream. The file name is usually passed in the constructor but can be changed with setName(). You can check for a file's existence with exists() and remove a file with remove(). The file is opened with open(), closed with close() and flushed with flush(). Data is usually read and written using QDataStream or QTextStream, but you can read with readBlock() and readLine() and write with writeBlock(). QFile also supports getch(), ungetch() and putch(). The size of the file is returned by size(). You can get the current file position or move to a new file position using the at() functions. If you've reached the end of the file, atEnd() returns TRUE. The file handle is returned by handle(). Here is a code fragment that uses QTextStream to read a text file line by line. It prints each line with a line number. \code QStringList lines; QFile file( "file.txt" ); if ( file.open( IO_ReadOnly ) ) { QTextStream stream( &file ); QString line; int i = 1; - while ( !stream.eof() ) { + while ( !stream.atEnd() ) { line = stream.readLine(); // line of text excluding '\n' printf( "%3d: %s\n", i++, line.latin1() ); lines += line; } file.close(); } \endcode Writing text is just as easy. The following example shows how to write the data we read into the string list from the previous example: \code QFile file( "file.txt" ); if ( file.open( IO_WriteOnly ) ) { QTextStream stream( &file ); for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) stream << *it << "\n"; file.close(); } \endcode The QFileInfo class holds detailed information about a file, such as access permissions, file dates and file types. The QDir class manages directories and lists of file names. Qt uses Unicode file names. If you want to do your own I/O on Unix systems you may want to use encodeName() (and decodeName()) to convert the file name into the local encoding. \important readAll() \sa QDataStream, QTextStream */ /*! \fn Q_LONG QFile::writeBlock( const QByteArray& data ) \overload */ /*! Constructs a QFile with no name. */ QFile::QFile() { init(); } /*! Constructs a QFile with a file name \a name. \sa setName() */ QFile::QFile( const QString &name ) : fn(name) { init(); } @@ -229,128 +229,129 @@ void QFile::setName( const QString &name ) Returns TRUE if this file exists; otherwise returns FALSE. \sa name() */ bool QFile::exists() const { return qt_file_access( fn, F_OK ); } /*! Returns TRUE if the file given by \a fileName exists; otherwise returns FALSE. */ bool QFile::exists( const QString &fileName ) { return qt_file_access( fileName, F_OK ); } /*! Removes the file specified by the file name currently set. Returns TRUE if successful; otherwise returns FALSE. The file is closed before it is removed. */ bool QFile::remove() { close(); return remove( fn ); } #if defined(Q_OS_MAC) || defined(Q_OS_MSDOS) || defined(Q_OS_WIN32) || defined(Q_OS_OS2) # define HAS_TEXT_FILEMODE // has translate/text filemode #endif #if defined(O_NONBLOCK) # define HAS_ASYNC_FILEMODE # define OPEN_ASYNC O_NONBLOCK #elif defined(O_NDELAY) # define HAS_ASYNC_FILEMODE # define OPEN_ASYNC O_NDELAY #endif /*! Flushes the file buffer to the disk. close() also flushes the file buffer. */ void QFile::flush() { if ( isOpen() && fh ) // can only flush open/buffered fflush( fh ); // file } /*! \reimp \fn QIODevice::Offset QFile::at() const */ /*! Returns TRUE if the end of file has been reached; otherwise returns FALSE. + If QFile has not been open()'d, then the behavior is undefined. \sa size() */ bool QFile::atEnd() const { if ( !isOpen() ) { #if defined(QT_CHECK_STATE) qWarning( "QFile::atEnd: File is not open" ); #endif return FALSE; } if ( isDirectAccess() && !isTranslated() ) { if ( at() < length ) return FALSE; } return QIODevice::atEnd(); } /*! Reads a line of text. Reads bytes from the file into the char* \a p, until end-of-line or \a maxlen bytes have been read, whichever occurs first. Returns the number of bytes read, or -1 if there was an error. Any terminating newline is not stripped. This function is only efficient for buffered files. Avoid readLine() for files that have been opened with the \c IO_Raw flag. \sa readBlock(), QTextStream::readLine() */ Q_LONG QFile::readLine( char *p, Q_ULONG maxlen ) { if ( maxlen == 0 ) // application bug? return 0; #if defined(QT_CHECK_STATE) Q_CHECK_PTR( p ); if ( !isOpen() ) { // file not open qWarning( "QFile::readLine: File not open" ); return -1; } if ( !isReadable() ) { // reading not permitted qWarning( "QFile::readLine: Read operation not permitted" ); return -1; } #endif Q_LONG nread; // number of bytes read if ( isRaw() ) { // raw file nread = QIODevice::readLine( p, maxlen ); } else { // buffered file p = fgets( p, maxlen, fh ); if ( p ) { nread = qstrlen( p ); if ( !isSequentialAccess() ) ioIndex += nread; } else { nread = -1; setStatus(IO_ReadError); } } return nread; diff --git a/qmake/tools/qfile_unix.cpp b/qmake/tools/qfile_unix.cpp index 2d5a856..460bf06 100644 --- a/qmake/tools/qfile_unix.cpp +++ b/qmake/tools/qfile_unix.cpp @@ -374,314 +374,319 @@ bool QFile::open( int m, FILE *f ) Returns TRUE if successful, otherwise FALSE. When a QFile is opened using this function, close() does not actually close the file. The QFile that is opened using this function, is automatically set to be in raw mode; this means that the file input/output functions are slow. If you run into performance issues, you should try to use one of the other open functions. \warning If \a f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not be able to seek. size() is set to \c INT_MAX (in limits.h). \sa close() */ bool QFile::open( int m, int f ) { if ( isOpen() ) { #if defined(QT_CHECK_RANGE) qWarning( "QFile::open: File already open" ); #endif return FALSE; } init(); setMode( m |IO_Raw ); setState( IO_Open ); fd = f; ext_f = TRUE; struct stat st; ::fstat( fd, &st ); ioIndex = (Offset)::lseek(fd, 0, SEEK_CUR); if ( (st.st_mode & S_IFMT) != S_IFREG || f == 0 ) { // stdin is not seekable... // non-seekable setType( IO_Sequential ); length = INT_MAX; ioIndex = 0; } else { length = (Offset)st.st_size; if ( length == 0 && isReadable() ) { // try if you can read from it (if you can, it's a sequential // device; e.g. a file in the /proc filesystem) int c = getch(); if ( c != -1 ) { ungetch(c); setType( IO_Sequential ); length = INT_MAX; ioIndex = 0; } resetStatus(); } } return TRUE; } /*! Returns the file size. \sa at() */ QIODevice::Offset QFile::size() const { struct stat st; + int ret = 0; if ( isOpen() ) { - ::fstat( fh ? fileno(fh) : fd, &st ); + ret = ::fstat( fh ? fileno(fh) : fd, &st ); } else { - ::stat( QFile::encodeName(fn), &st ); + ret = ::stat( QFile::encodeName(fn), &st ); } + if ( ret == -1 ) + return 0; #if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_64BITOFFSET) return (uint)st.st_size > UINT_MAX ? UINT_MAX : (QIODevice::Offset)st.st_size; #else return st.st_size; #endif } /*! \overload Sets the file index to \a pos. Returns TRUE if successful; otherwise returns FALSE. Example: \code QFile f( "data.bin" ); f.open( IO_ReadOnly ); // index set to 0 f.at( 100 ); // set index to 100 f.at( f.at()+50 ); // set index to 150 f.at( f.size()-80 ); // set index to 80 before EOF f.close(); \endcode Use \c at() without arguments to retrieve the file offset. \warning The result is undefined if the file was open()'ed using the \c IO_Append specifier. \sa size(), open() */ bool QFile::at( Offset pos ) { if ( !isOpen() ) { #if defined(QT_CHECK_STATE) qWarning( "QFile::at: File is not open" ); #endif return FALSE; } if ( isSequentialAccess() ) return FALSE; bool ok; if ( isRaw() ) { off_t l = ::lseek( fd, pos, SEEK_SET ); ok = ( l != -1 ); pos = (Offset)l; } else { // buffered file #if defined(QT_LARGEFILE_SUPPORT) ok = ( ::fseeko(fh, pos, SEEK_SET) == 0 ); #else ok = ( ::fseek(fh, pos, SEEK_SET) == 0 ); #endif } if ( ok ) ioIndex = pos; #if defined(QT_CHECK_RANGE) else #if defined(QT_LARGEFILE_SUPPORT) && defined(QT_ABI_64BITOFFSET) qWarning( "QFile::at: Cannot set file position %llu", pos ); #else qWarning( "QFile::at: Cannot set file position %lu", pos ); #endif #endif return ok; } /*! \reimp \warning We have experienced problems with some C libraries when a buffered file is opened for both reading and writing. If a read operation takes place immediately after a write operation, the read buffer contains garbage data. Worse, the same garbage is written to the file. Calling flush() before readBlock() solved this problem. */ Q_LONG QFile::readBlock( char *p, Q_ULONG len ) { #if defined(QT_CHECK_NULL) if ( !p ) qWarning( "QFile::readBlock: Null pointer error" ); #endif #if defined(QT_CHECK_STATE) if ( !isOpen() ) { qWarning( "QFile::readBlock: File not open" ); return -1; } if ( !isReadable() ) { qWarning( "QFile::readBlock: Read operation not permitted" ); return -1; } #endif Q_ULONG nread = 0; // number of bytes read if ( !ungetchBuffer.isEmpty() ) { // need to add these to the returned string. uint l = ungetchBuffer.length(); while( nread < l ) { - *p = ungetchBuffer[ l - nread - 1 ]; + *p = ungetchBuffer.at( l - nread - 1 ); p++; nread++; } ungetchBuffer.truncate( l - nread ); } if ( nread < len ) { if ( isRaw() ) { // raw file nread += ::read( fd, p, len-nread ); if ( len && nread <= 0 ) { nread = 0; setStatus(IO_ReadError); } } else { // buffered file nread += fread( p, 1, len-nread, fh ); if ( (uint)nread != len ) { if ( ferror( fh ) || nread==0 ) setStatus(IO_ReadError); } } } if ( !isSequentialAccess() ) ioIndex += nread; return nread; } /*! \reimp Writes \a len bytes from \a p to the file and returns the number of bytes actually written. Returns -1 if a serious error occurred. \warning When working with buffered files, data may not be written to the file at once. Call flush() to make sure the data is really written. \sa readBlock() */ Q_LONG QFile::writeBlock( const char *p, Q_ULONG len ) { #if defined(QT_CHECK_NULL) if ( p == 0 && len != 0 ) qWarning( "QFile::writeBlock: Null pointer error" ); #endif #if defined(QT_CHECK_STATE) if ( !isOpen() ) { // file not open qWarning( "QFile::writeBlock: File not open" ); return -1; } if ( !isWritable() ) { // writing not permitted qWarning( "QFile::writeBlock: Write operation not permitted" ); return -1; } #endif Q_ULONG nwritten; // number of bytes written if ( isRaw() ) // raw file nwritten = ::write( fd, (void *)p, len ); else // buffered file nwritten = fwrite( p, 1, len, fh ); if ( nwritten != len ) { // write error if ( errno == ENOSPC ) // disk is full setStatus( IO_ResourceError ); else setStatus( IO_WriteError ); if ( !isSequentialAccess() ) { if ( isRaw() ) // recalc file position ioIndex = (Offset)::lseek( fd, 0, SEEK_CUR ); else #if defined(QT_LARGEFILE_SUPPORT) ioIndex = (Offset)::fseeko( fh, 0, SEEK_CUR ); #else ioIndex = (Offset)::fseek( fh, 0, SEEK_CUR ); #endif } } else { if ( !isSequentialAccess() ) ioIndex += nwritten; } if ( ioIndex > length ) // update file length length = ioIndex; return nwritten; } /*! Returns the file handle of the file. This is a small positive integer, suitable for use with C library - functions such as fdopen() and fcntl(), as well as with QSocketNotifier. + functions such as fdopen() and fcntl(). On systems that use file + descriptors for sockets (ie. Unix systems, but not Windows) the handle + can be used with QSocketNotifier as well. If the file is not open or there is an error, handle() returns -1. \sa QSocketNotifier */ int QFile::handle() const { if ( !isOpen() ) return -1; else if ( fh ) return fileno( fh ); else return fd; } /*! Closes an open file. The file is not closed if it was opened with an existing file handle. If the existing file handle is a \c FILE*, the file is flushed. If the existing file handle is an \c int file descriptor, nothing is done to the file. Some "write-behind" filesystems may report an unspecified error on closing the file. These errors only indicate that something may have gone wrong since the previous open(). In such a case status() reports IO_UnspecifiedError after close(), otherwise IO_Ok. \sa open(), flush() */ void QFile::close() { bool ok = FALSE; if ( isOpen() ) { // file is not open if ( fh ) { // buffered file if ( ext_f ) ok = fflush( fh ) != -1; // flush instead of closing else ok = fclose( fh ) != -1; } else { // raw file if ( ext_f ) ok = TRUE; // cannot close else ok = ::close( fd ) != -1; } init(); // restore internal state } if (!ok) setStatus( IO_UnspecifiedError ); return; } diff --git a/qmake/tools/qfileinfo.cpp b/qmake/tools/qfileinfo.cpp index 3af7932..a78f4fa 100644 --- a/qmake/tools/qfileinfo.cpp +++ b/qmake/tools/qfileinfo.cpp @@ -574,86 +574,88 @@ QDateTime QFileInfo::created() const { QDateTime dt; if ( !fic || !cache ) doStat(); if ( fic && fic->st.st_ctime != 0 ) { dt.setTime_t( fic->st.st_ctime ); return dt; } else { return lastModified(); } } /*! Returns the date and time when the file was last modified. \sa created() lastModified() lastRead() */ QDateTime QFileInfo::lastModified() const { QDateTime dt; if ( !fic || !cache ) doStat(); if ( fic ) dt.setTime_t( fic->st.st_mtime ); return dt; } /*! Returns the date and time when the file was last read (accessed). On platforms where this information is not available, returns the same as lastModified(). \sa created() lastModified() lastRead() */ QDateTime QFileInfo::lastRead() const { QDateTime dt; if ( !fic || !cache ) doStat(); if ( fic && fic->st.st_atime != 0 ) { dt.setTime_t( fic->st.st_atime ); return dt; } else { return lastModified(); } } #ifndef QT_NO_DIR /*! Returns the absolute path including the file name. The absolute path name consists of the full path and the file name. On Unix this will always begin with the root, '/', directory. On Windows this will always begin 'D:/' where D is a drive letter, except for network shares that are not mapped to a drive letter, in which case the path will begin '//sharename/'. This function returns the same as filePath(), unless isRelative() is TRUE. + If the QFileInfo is empty it returns QDir::currentDirPath(). + This function can be time consuming under Unix (in the order of milliseconds). \sa isRelative(), filePath() */ QString QFileInfo::absFilePath() const { QString tmp; if ( QDir::isRelativePath(fn) -#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) +#if defined(Q_OS_WIN32) && fn[1] != ':' #endif ) { tmp = QDir::currentDirPath(); tmp += '/'; } tmp += fn; makeAbs( tmp ); return QDir::cleanDirPath( tmp ); } #endif diff --git a/qmake/tools/qfileinfo_unix.cpp b/qmake/tools/qfileinfo_unix.cpp index f7c3a97..364f219 100644 --- a/qmake/tools/qfileinfo_unix.cpp +++ b/qmake/tools/qfileinfo_unix.cpp @@ -153,131 +153,131 @@ QString QFileInfo::owner() const function returns ((uint) -2). \sa owner(), group(), groupId() */ uint QFileInfo::ownerId() const { if ( !fic || !cache ) doStat(); if ( fic ) return fic->st.st_uid; return nobodyID; } /*! Returns the group of the file. On Windows, on systems where files do not have groups, or if an error occurs, QString::null is returned. This function can be time consuming under Unix (in the order of milliseconds). \sa groupId(), owner(), ownerId() */ QString QFileInfo::group() const { struct group *gr = getgrgid( groupId() ); if ( gr ) return QFile::decodeName( gr->gr_name ); return QString::null; } /*! Returns the id of the group the file belongs to. On Windows and on systems where files do not have groups this function always returns (uint) -2. \sa group(), owner(), ownerId() */ uint QFileInfo::groupId() const { if ( !fic || !cache ) doStat(); if ( fic ) return fic->st.st_gid; return nobodyID; } /*! Tests for file permissions. The \a permissionSpec argument can be several flags of type \c PermissionSpec OR-ed together to check for permission combinations. On systems where files do not have permissions this function always returns TRUE. Example: \code QFileInfo fi( "/tmp/archive.tar.gz" ); if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) - qWarning( "I can change the file; my group can read the file."); + qWarning( "I can change the file; my group can read the file" ); if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) - qWarning( "The group or others can change the file!" ); + qWarning( "The group or others can change the file" ); \endcode \sa isReadable(), isWritable(), isExecutable() */ bool QFileInfo::permission( int permissionSpec ) const { if ( !fic || !cache ) doStat(); if ( fic ) { uint mask = 0; if ( permissionSpec & ReadUser ) mask |= S_IRUSR; if ( permissionSpec & WriteUser ) mask |= S_IWUSR; if ( permissionSpec & ExeUser ) mask |= S_IXUSR; if ( permissionSpec & ReadGroup ) mask |= S_IRGRP; if ( permissionSpec & WriteGroup ) mask |= S_IWGRP; if ( permissionSpec & ExeGroup ) mask |= S_IXGRP; if ( permissionSpec & ReadOther ) mask |= S_IROTH; if ( permissionSpec & WriteOther ) mask |= S_IWOTH; if ( permissionSpec & ExeOther ) mask |= S_IXOTH; if ( mask ) { return (fic->st.st_mode & mask) == mask; } else { #if defined(QT_CHECK_NULL) qWarning( "QFileInfo::permission: permissionSpec is 0" ); #endif return TRUE; } } else { return FALSE; } } void QFileInfo::doStat() const { QFileInfo *that = ((QFileInfo*)this); // mutable function if ( !that->fic ) that->fic = new QFileInfoCache; that->symLink = FALSE; struct stat *b = &that->fic->st; #if defined(Q_OS_UNIX) && defined(S_IFLNK) if ( ::lstat( QFile::encodeName(fn), b ) == 0 ) { if ( S_ISLNK( b->st_mode ) ) that->symLink = TRUE; else return; } #endif int r = ::stat( QFile::encodeName(fn), b ); if ( r != 0 && !that->symLink ) { delete that->fic; that->fic = 0; } } diff --git a/qmake/tools/qgarray.cpp b/qmake/tools/qgarray.cpp index 45c45ce..0a522e4 100644 --- a/qmake/tools/qgarray.cpp +++ b/qmake/tools/qgarray.cpp @@ -1,469 +1,530 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QGArray class ** ** Created : 930906 ** ** 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. ** **********************************************************************/ -#include "qglobal.h" // needed to define Q_WS_WIN -#ifdef Q_WS_WIN -#include "qt_windows.h" // needed for bsearch on some platforms +#include "qglobal.h" +#if defined(Q_CC_BOR) + // needed for qsort() because of a std namespace problem on Borland +# include "qplatformdefs.h" +#elif defined(Q_WS_WIN) + // needed for bsearch on some platforms +# include "qt_windows.h" #endif #define QGARRAY_CPP #include "qgarray.h" #include <stdlib.h> #include <string.h> #ifdef QT_THREAD_SUPPORT # include <private/qmutexpool_p.h> #endif // QT_THREAD_SUPPORT -#define USE_MALLOC // comment to use new/delete +/* + If USE_MALLOC isn't defined, we use new[] and delete[] to allocate + memory. The documentation for QMemArray<T>::assign() explicitly + mentions that the array is freed using free(), so don't mess around + with USE_MALLOC unless you know what you're doing. +*/ +#define USE_MALLOC #undef NEW #undef DELETE #if defined(USE_MALLOC) #define NEW(type,size) ((type*)malloc(size*sizeof(type))) #define DELETE(array) (free((char*)array)) #else #define NEW(type,size) (new type[size]) #define DELETE(array) (delete[] array) #define DONT_USE_REALLOC // comment to use realloc() #endif /*! \class QShared qshared.h \reentrant \ingroup shared \brief The QShared class is used internally for implementing shared classes. \internal It only contains a reference count and member functions to increment and decrement it. Shared classes normally have internal classes that inherit QShared and add the shared data. \sa \link shclass.html Shared Classes\endlink */ /*! \class QGArray qgarray.h \reentrant \ingroup shared \ingroup collection \brief The QGArray class is an internal class for implementing the QMemArray class. \internal QGArray is a strictly internal class that acts as base class for the QMemArray template array. It contains an array of bytes and has no notion of an array element. */ /*! Constructs a null array. */ QGArray::QGArray() { shd = newData(); Q_CHECK_PTR( shd ); } /*! Dummy constructor; does not allocate any data. This constructor does not initialize any array data so subclasses must do it. The intention is to make the code more efficient. */ QGArray::QGArray( int, int ) { } /*! Constructs an array with room for \a size bytes. */ QGArray::QGArray( int size ) { if ( size < 0 ) { #if defined(QT_CHECK_RANGE) qWarning( "QGArray: Cannot allocate array with negative length" ); #endif size = 0; } shd = newData(); Q_CHECK_PTR( shd ); if ( size == 0 ) // zero length return; shd->data = NEW(char,size); Q_CHECK_PTR( shd->data ); - shd->len = size; + shd->len = +#ifdef QT_QGARRAY_SPEED_OPTIM + shd->maxl = +#endif + size; } /*! Constructs a shallow copy of \a a. */ QGArray::QGArray( const QGArray &a ) { shd = a.shd; shd->ref(); } /*! Dereferences the array data and deletes it if this was the last reference. */ QGArray::~QGArray() { if ( shd && shd->deref() ) { // delete when last reference if ( shd->data ) // is lost DELETE(shd->data); deleteData( shd ); shd = 0; } } /*! \fn QGArray &QGArray::operator=( const QGArray &a ) Assigns a shallow copy of \a a to this array and returns a reference to this array. Equivalent to assign(). */ /*! \fn void QGArray::detach() Detaches this array from shared array data. */ /*! \fn char *QGArray::data() const Returns a pointer to the actual array data. */ /*! \fn uint QGArray::nrefs() const Returns the reference count. */ /*! \fn uint QGArray::size() const Returns the size of the array, in bytes. */ /*! Returns TRUE if this array is equal to \a a, otherwise FALSE. The comparison is bitwise, of course. */ bool QGArray::isEqual( const QGArray &a ) const { if ( size() != a.size() ) // different size return FALSE; if ( data() == a.data() ) // has same data return TRUE; return (size() ? memcmp( data(), a.data(), size() ) : 0) == 0; } /*! - Resizes the array to \a newsize bytes. + Resizes the array to \a newsize bytes. \a optim is either + MemOptim (the default) or SpeedOptim. */ - -bool QGArray::resize( uint newsize ) +bool QGArray::resize( uint newsize, Optimization optim ) { - if ( newsize == shd->len ) // nothing to do +#ifndef QT_QGARRAY_SPEED_OPTIM + Q_UNUSED(optim); +#endif + + if ( newsize == shd->len +#ifdef QT_QGARRAY_SPEED_OPTIM + && newsize == shd->maxl +#endif + ) // nothing to do return TRUE; if ( newsize == 0 ) { // remove array duplicate( 0, 0 ); return TRUE; } + + uint newmaxl = newsize; +#ifdef QT_QGARRAY_SPEED_OPTIM + if ( optim == SpeedOptim ) { + if ( newsize <= shd->maxl && + ( newsize * 4 > shd->maxl || shd->maxl <= 4 ) ) { + shd->len = newsize; + return TRUE; + } + newmaxl = 4; + while ( newmaxl < newsize ) + newmaxl *= 2; + // try to spare some memory + if ( newmaxl >= 1024 * 1024 && newsize <= newmaxl - (newmaxl >> 2) ) + newmaxl -= newmaxl >> 2; + } + shd->maxl = newmaxl; +#endif + if ( shd->data ) { // existing data #if defined(DONT_USE_REALLOC) char *newdata = NEW(char,newsize); // manual realloc - memcpy( newdata, shd->data, QMIN(shd->len,newsize) ); + memcpy( newdata, shd->data, QMIN(shd->len,newmaxl) ); DELETE(shd->data); shd->data = newdata; #else - shd->data = (char *)realloc( shd->data, newsize ); + shd->data = (char *)realloc( shd->data, newmaxl ); #endif } else { - shd->data = NEW(char,newsize); + shd->data = NEW(char,newmaxl); } if ( !shd->data ) // no memory return FALSE; shd->len = newsize; return TRUE; } +/*!\overload +*/ +bool QGArray::resize( uint newsize ) +{ + return resize( newsize, MemOptim ); +} + + /*! Fills the array with the repeated occurrences of \a d, which is \a sz bytes long. If \a len is specified as different from -1, then the array will be resized to \a len*sz before it is filled. Returns TRUE if successful, or FALSE if the memory cannot be allocated (only when \a len != -1). \sa resize() */ bool QGArray::fill( const char *d, int len, uint sz ) { if ( len < 0 ) len = shd->len/sz; // default: use array length else if ( !resize( len*sz ) ) return FALSE; if ( sz == 1 ) // 8 bit elements memset( data(), *d, len ); else if ( sz == 4 ) { // 32 bit elements register Q_INT32 *x = (Q_INT32*)data(); Q_INT32 v = *((Q_INT32*)d); while ( len-- ) *x++ = v; } else if ( sz == 2 ) { // 16 bit elements register Q_INT16 *x = (Q_INT16*)data(); Q_INT16 v = *((Q_INT16*)d); while ( len-- ) *x++ = v; } else { // any other size elements register char *x = data(); while ( len-- ) { // more complicated memcpy( x, d, sz ); x += sz; } } return TRUE; } /*! \overload Shallow copy. Dereference the current array and references the data contained in \a a instead. Returns a reference to this array. \sa operator=() */ QGArray &QGArray::assign( const QGArray &a ) { a.shd->ref(); // avoid 'a = a' if ( shd->deref() ) { // delete when last reference if ( shd->data ) // is lost DELETE(shd->data); deleteData( shd ); } shd = a.shd; return *this; } /*! Shallow copy. Dereference the current array and references the array data \a d, which contains \a len bytes. Returns a reference to this array. Do not delete \a d later, because QGArray takes care of that. */ QGArray &QGArray::assign( const char *d, uint len ) { if ( shd->count > 1 ) { // disconnect this shd->count--; shd = newData(); Q_CHECK_PTR( shd ); } else { if ( shd->data ) DELETE(shd->data); } shd->data = (char *)d; - shd->len = len; + shd->len = +#ifdef QT_QGARRAY_SPEED_OPTIM + shd->maxl = +#endif + len; return *this; } /*! Deep copy. Dereference the current array and obtains a copy of the data contained in \a a instead. Returns a reference to this array. \sa assign(), operator=() */ QGArray &QGArray::duplicate( const QGArray &a ) { if ( a.shd == shd ) { // a.duplicate(a) ! if ( shd->count > 1 ) { shd->count--; register array_data *n = newData(); Q_CHECK_PTR( n ); if ( (n->len=shd->len) ) { n->data = NEW(char,n->len); Q_CHECK_PTR( n->data ); if ( n->data ) memcpy( n->data, shd->data, n->len ); } else { n->data = 0; } shd = n; } return *this; } char *oldptr = 0; if ( shd->count > 1 ) { // disconnect this shd->count--; shd = newData(); Q_CHECK_PTR( shd ); } else { // delete after copy was made oldptr = shd->data; } if ( a.shd->len ) { // duplicate data shd->data = NEW(char,a.shd->len); Q_CHECK_PTR( shd->data ); if ( shd->data ) memcpy( shd->data, a.shd->data, a.shd->len ); } else { shd->data = 0; } - shd->len = a.shd->len; + shd->len = +#ifdef QT_QGARRAY_SPEED_OPTIM + shd->maxl = +#endif + a.shd->len; if ( oldptr ) DELETE(oldptr); return *this; } /*! \overload Deep copy. Dereferences the current array and obtains a copy of \a len characters from array data \a d instead. Returns a reference to this array. \sa assign(), operator=() */ QGArray &QGArray::duplicate( const char *d, uint len ) { char *data; if ( d == 0 || len == 0 ) { data = 0; len = 0; } else { if ( shd->count == 1 && shd->len == len ) { memcpy( shd->data, d, len ); // use same buffer return *this; } data = NEW(char,len); Q_CHECK_PTR( data ); memcpy( data, d, len ); } if ( shd->count > 1 ) { // detach shd->count--; shd = newData(); Q_CHECK_PTR( shd ); } else { // just a single reference if ( shd->data ) DELETE(shd->data); } shd->data = data; - shd->len = len; + shd->len = +#ifdef QT_QGARRAY_SPEED_OPTIM + shd->maxl = +#endif + len; return *this; } /*! Resizes this array to \a len bytes and copies the \a len bytes at address \a d into it. \warning This function disregards the reference count mechanism. If other QGArrays reference the same data as this, all will be updated. */ void QGArray::store( const char *d, uint len ) { // store, but not deref resize( len ); memcpy( shd->data, d, len ); } /*! \fn array_data *QGArray::sharedBlock() const Returns a pointer to the shared array block. \warning Do not use this function. Using it is begging for trouble. We dare not remove it, for fear of breaking code, but we \e strongly discourage new use of it. */ /*! \fn void QGArray::setSharedBlock( array_data *p ) Sets the shared array block to \a p. \warning Do not use this function. Using it is begging for trouble. We dare not remove it, for fear of breaking code, but we \e strongly discourage new use of it. */ /*! Sets raw data and returns a reference to the array. Dereferences the current array and sets the new array data to \a d and the new array size to \a len. Do not attempt to resize or re-assign the array data when raw data has been set. Call resetRawData(d,len) to reset the array. Setting raw data is useful because it sets QMemArray data without allocating memory or copying data. Example of intended use: \code static uchar bindata[] = { 231, 1, 44, ... }; QByteArray a; a.setRawData( bindata, sizeof(bindata) ); // a points to bindata QDataStream s( a, IO_ReadOnly ); // open on a's data s >> <something>; // read raw bindata s.close(); a.resetRawData( bindata, sizeof(bindata) ); // finished \endcode @@ -598,147 +659,149 @@ int QGArray::contains( const char *d, uint sz ) const break; case 2: { // 16 bit elements register Q_INT16 *x = (Q_INT16*)data(); Q_INT16 v = *((Q_INT16*)d); i /= 2; while ( i-- ) { if ( *x++ == v ) count++; } } break; case 4: { // 32 bit elements register Q_INT32 *x = (Q_INT32*)data(); Q_INT32 v = *((Q_INT32*)d); i /= 4; while ( i-- ) { if ( *x++ == v ) count++; } } break; default: { // any size elements for ( i=0; i<shd->len; i+=sz ) { if ( memcmp(d, &shd->data[i], sz) == 0 ) count++; } } break; } return count; } static int cmp_item_size = 0; #if defined(Q_C_CALLBACKS) extern "C" { #endif #ifdef Q_OS_TEMP static int __cdecl cmp_arr( const void *n1, const void *n2 ) #else static int cmp_arr( const void *n1, const void *n2 ) #endif { return ( n1 && n2 ) ? memcmp( n1, n2, cmp_item_size ) : ( n1 ? 1 : ( n2 ? -1 : 0 ) ); // ### Qt 3.0: Add a virtual compareItems() method and call that instead } #if defined(Q_C_CALLBACKS) } #endif /*! Sorts the first \a sz items of the array. */ void QGArray::sort( uint sz ) { int numItems = size() / sz; if ( numItems < 2 ) return; #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &cmp_item_size ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &cmp_item_size ) : 0 ); #endif // QT_THREAD_SUPPORT cmp_item_size = sz; qsort( shd->data, numItems, sz, cmp_arr ); } /*! Binary search; assumes that \a d is a sorted array of size \a sz. */ int QGArray::bsearch( const char *d, uint sz ) const { int numItems = size() / sz; if ( !numItems ) return -1; #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &cmp_item_size ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &cmp_item_size ) : 0 ); #endif // QT_THREAD_SUPPORT cmp_item_size = sz; char* r = (char*)::bsearch( d, shd->data, numItems, sz, cmp_arr ); if ( !r ) return -1; while( (r >= shd->data + sz) && (cmp_arr( r - sz, d ) == 0) ) r -= sz; // search to first of equal elements; bsearch is undef return (int)(( r - shd->data ) / sz); } /*! \fn char *QGArray::at( uint index ) const Returns a pointer to the byte at offset \a index in the array. */ /*! Expand the array if necessary, and copies (the first part of) its contents from the \a index * \a sz bytes at \a d. Returns TRUE if the operation succeeds, FALSE if it runs out of memory. \warning This function disregards the reference count mechanism. If other QGArrays reference the same data as this, all will be changed. */ bool QGArray::setExpand( uint index, const char *d, uint sz ) { index *= sz; if ( index >= shd->len ) { if ( !resize( index+sz ) ) // no memory return FALSE; } memcpy( data() + index, d, sz ); return TRUE; } /*! Prints a warning message if at() or [] is given a bad index. */ void QGArray::msg_index( uint index ) { #if defined(QT_CHECK_RANGE) qWarning( "QGArray::at: Absolute index %d out of range", index ); #else Q_UNUSED( index ) #endif } /*! Returns a new shared array block. */ QGArray::array_data * QGArray::newData() { return new array_data; } diff --git a/qmake/tools/qgdict.cpp b/qmake/tools/qgdict.cpp index c431ff8..3d49fc7 100644 --- a/qmake/tools/qgdict.cpp +++ b/qmake/tools/qgdict.cpp @@ -143,129 +143,132 @@ int QGDict::hashKeyAscii( const char *key ) h ^= g >> 24; h &= ~g; k++; } } int index = h; if ( index < 0 ) // adjust index to table size index = -index; return index; } #ifndef QT_NO_DATASTREAM /*! \overload Reads a collection/dictionary item from the stream \a s and returns a reference to the stream. The default implementation sets \a item to 0. \sa write() */ QDataStream& QGDict::read( QDataStream &s, QPtrCollection::Item &item ) { item = 0; return s; } /*! \overload Writes a collection/dictionary item to the stream \a s and returns a reference to the stream. \sa read() */ QDataStream& QGDict::write( QDataStream &s, QPtrCollection::Item ) const { return s; } #endif //QT_NO_DATASTREAM /***************************************************************************** QGDict member functions *****************************************************************************/ /*! Constructs a dictionary. \a len is the initial size of the dictionary. The key type is \a kt which may be \c StringKey, \c AsciiKey, \c IntKey or \c PtrKey. The case-sensitivity of lookups is set with \a caseSensitive. Keys are copied if \a copyKeys is TRUE. */ QGDict::QGDict( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) { init( len, kt, caseSensitive, copyKeys ); } void QGDict::init( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) { - vec = new QBaseBucket *[vlen = len]; // allocate hash table + vlen = len; + if ( vlen == 0 ) + vlen = 17; + vec = new QBaseBucket *[vlen]; Q_CHECK_PTR( vec ); memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); numItems = 0; iterators = 0; // The caseSensitive and copyKey options don't make sense for // all dict types. switch ( (keytype = (uint)kt) ) { case StringKey: cases = caseSensitive; copyk = FALSE; break; case AsciiKey: cases = caseSensitive; copyk = copyKeys; break; default: cases = FALSE; copyk = FALSE; break; } } /*! Constructs a copy of \a dict. */ QGDict::QGDict( const QGDict & dict ) : QPtrCollection( dict ) { init( dict.vlen, (KeyType)dict.keytype, dict.cases, dict.copyk ); QGDictIterator it( dict ); while ( it.get() ) { // copy from other dict switch ( keytype ) { case StringKey: look_string( it.getKeyString(), it.get(), op_insert ); break; case AsciiKey: look_ascii( it.getKeyAscii(), it.get(), op_insert ); break; case IntKey: look_int( it.getKeyInt(), it.get(), op_insert ); break; case PtrKey: look_ptr( it.getKeyPtr(), it.get(), op_insert ); break; } ++it; } } /*! Removes all items from the dictionary and destroys it. */ QGDict::~QGDict() { clear(); // delete everything delete [] vec; if ( !iterators ) // no iterators for this dict return; QGDictIterator *i = iterators->first(); while ( i ) { // notify all iterators that diff --git a/qmake/tools/qglist.cpp b/qmake/tools/qglist.cpp index 155d585..bd27f8a 100644 --- a/qmake/tools/qglist.cpp +++ b/qmake/tools/qglist.cpp @@ -268,134 +268,130 @@ QGList& QGList::operator=( const QGList &list ) return *this; clear(); if ( list.count() > 0 ) { QLNode *n = list.firstNode; while ( n ) { // copy all items from list append( n->data ); n = n->next; } curNode = firstNode; curIndex = 0; } return *this; } /*! Compares this list with \a list. Returns TRUE if the lists contain the same data, otherwise FALSE. */ bool QGList::operator==( const QGList &list ) const { if ( count() != list.count() ) return FALSE; if ( count() == 0 ) return TRUE; QLNode *n1 = firstNode; QLNode *n2 = list.firstNode; while ( n1 && n2 ) { // should be mutable if ( ( (QGList*)this )->compareItems( n1->data, n2->data ) != 0 ) return FALSE; n1 = n1->next; n2 = n2->next; } return TRUE; } /*! \fn uint QGList::count() const Returns the number of items in the list. */ /*! Returns the node at position \a index. Sets this node to current. */ QLNode *QGList::locate( uint index ) { if ( index == (uint)curIndex ) // current node ? return curNode; if ( !curNode && firstNode ) { // set current node curNode = firstNode; curIndex = 0; } register QLNode *node; int distance = index - curIndex; // node distance to cur node bool forward; // direction to traverse - if ( index >= numNodes ) { -#if defined(QT_CHECK_RANGE) - qWarning( "QGList::locate: Index %d out of range", index ); -#endif + if ( index >= numNodes ) return 0; - } if ( distance < 0 ) distance = -distance; if ( (uint)distance < index && (uint)distance < numNodes - index ) { node = curNode; // start from current node forward = index > (uint)curIndex; } else if ( index < numNodes - index ) { // start from first node node = firstNode; distance = index; forward = TRUE; } else { // start from last node node = lastNode; distance = numNodes - index - 1; if ( distance < 0 ) distance = 0; forward = FALSE; } if ( forward ) { // now run through nodes while ( distance-- ) node = node->next; } else { while ( distance-- ) node = node->prev; } curIndex = index; // must update index return curNode = node; } /*! Inserts item \a d at its sorted position in the list. */ void QGList::inSort( QPtrCollection::Item d ) { int index = 0; register QLNode *n = firstNode; while ( n && compareItems(n->data,d) < 0 ){ // find position in list n = n->next; index++; } insertAt( index, d ); } /*! Inserts item \a d at the start of the list. */ void QGList::prepend( QPtrCollection::Item d ) { register QLNode *n = new QLNode( newItem(d) ); Q_CHECK_PTR( n ); n->prev = 0; if ( (n->next = firstNode) ) // list is not empty firstNode->prev = n; else // initialize list lastNode = n; firstNode = curNode = n; // curNode affected numNodes++; curIndex = 0; } diff --git a/qmake/tools/qglobal.cpp b/qmake/tools/qglobal.cpp index 47cd6bd..342005d 100644 --- a/qmake/tools/qglobal.cpp +++ b/qmake/tools/qglobal.cpp @@ -88,129 +88,150 @@ bool qSysInfo( int *wordSize, bool *bigEndian ) { #if defined(QT_CHECK_NULL) Q_ASSERT( wordSize != 0 ); Q_ASSERT( bigEndian != 0 ); #endif if ( si_alreadyDone ) { // run it only once *wordSize = si_wordSize; *bigEndian = si_bigEndian; return TRUE; } si_wordSize = 0; Q_ULONG n = (Q_ULONG)(~0); while ( n ) { // detect word size si_wordSize++; n /= 2; } *wordSize = si_wordSize; if ( *wordSize != 64 && *wordSize != 32 && *wordSize != 16 ) { // word size: 16, 32 or 64 #if defined(QT_CHECK_RANGE) qFatal( "qSysInfo: Unsupported system word size %d", *wordSize ); #endif return FALSE; } if ( sizeof(Q_INT8) != 1 || sizeof(Q_INT16) != 2 || sizeof(Q_INT32) != 4 || sizeof(Q_ULONG)*8 != si_wordSize || sizeof(float) != 4 || sizeof(double) != 8 ) { #if defined(QT_CHECK_RANGE) qFatal( "qSysInfo: Unsupported system data type size" ); #endif return FALSE; } bool be16, be32; // determine byte ordering short ns = 0x1234; int nl = 0x12345678; unsigned char *p = (unsigned char *)(&ns); // 16-bit integer be16 = *p == 0x12; p = (unsigned char *)(&nl); // 32-bit integer if ( p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78 ) be32 = TRUE; else if ( p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && p[3] == 0x12 ) be32 = FALSE; else be32 = !be16; if ( be16 != be32 ) { // strange machine! #if defined(QT_CHECK_RANGE) qFatal( "qSysInfo: Inconsistent system byte order" ); #endif return FALSE; } *bigEndian = si_bigEndian = be32; si_alreadyDone = TRUE; return TRUE; } -#if defined(Q_OS_WIN32) || defined(Q_OS_CYGWIN) +#if !defined(QWS) && defined(Q_OS_MAC) + +#include "qt_mac.h" + +int qMacVersion() +{ + static int macver = Qt::MV_Unknown; + static bool first = TRUE; + if(first) { + first = FALSE; + long gestalt_version; + if(Gestalt(gestaltSystemVersion, &gestalt_version) == noErr) { + if(gestalt_version >= 0x1020 && gestalt_version < 0x1030) + macver = Qt::MV_10_DOT_2; + else if(gestalt_version >= 0x1010 && gestalt_version < 0x1020) + macver = Qt::MV_10_DOT_1; + } + } + return macver; +} +Qt::MacintoshVersion qt_macver = (Qt::MacintoshVersion)qMacVersion(); +#elif defined(Q_OS_WIN32) || defined(Q_OS_CYGWIN) bool qt_winunicode; #include "qt_windows.h" int qWinVersion() { #ifndef VER_PLATFORM_WIN32s #define VER_PLATFORM_WIN32s 0 #endif #ifndef VER_PLATFORM_WIN32_WINDOWS #define VER_PLATFORM_WIN32_WINDOWS 1 #endif #ifndef VER_PLATFORM_WIN32_NT #define VER_PLATFORM_WIN32_NT 2 #endif static int winver = Qt::WV_NT; static int t=0; if ( !t ) { t=1; #ifdef Q_OS_TEMP OSVERSIONINFOW osver; osver.dwOSVersionInfoSize = sizeof(osver); GetVersionEx( &osver ); #else OSVERSIONINFOA osver; osver.dwOSVersionInfoSize = sizeof(osver); GetVersionExA( &osver ); #endif switch ( osver.dwPlatformId ) { case VER_PLATFORM_WIN32s: winver = Qt::WV_32s; break; case VER_PLATFORM_WIN32_WINDOWS: // We treat Windows Me (minor 90) the same as Windows 98 if ( ( osver.dwMinorVersion == 10 ) || ( osver.dwMinorVersion == 90 ) ) winver = Qt::WV_98; else winver = Qt::WV_95; break; default: // VER_PLATFORM_WIN32_NT if ( osver.dwMajorVersion < 5 ) { winver = Qt::WV_NT; } else if ( osver.dwMinorVersion == 0 ) { winver = Qt::WV_2000; } else { winver = Qt::WV_XP; } } } #if defined(UNICODE) if ( winver & Qt::WV_NT_based ) qt_winunicode = TRUE; else #endif qt_winunicode = FALSE; return winver; } Qt::WindowsVersion qt_winver = (Qt::WindowsVersion)qWinVersion(); #endif @@ -260,145 +281,157 @@ Qt::WindowsVersion qt_winver = (Qt::WindowsVersion)qWinVersion(); similar to the C printf() function. Example: \code void f( int c ) { if ( c > 200 ) qWarning( "f: bad argument, c == %d", c ); } \endcode Under X11, the text is printed to stderr. Under Windows, the text is sent to the debugger. \warning The internal buffer is limited to 8196 bytes (including the '\0'-terminator). \warning Passing (const char *)0 as argument to qWarning might lead to crashes on certain platforms due to the platforms printf implementation. \sa qDebug(), qFatal(), qInstallMsgHandler(), \link debug.html Debugging\endlink */ /*! \fn void qFatal( const char *msg, ... ) \relates QApplication Prints a fatal error message \a msg and exits, or calls the message handler (if it has been installed). This function takes a format string and a list of arguments, similar to the C printf() function. Example: \code int divide( int a, int b ) { if ( b == 0 ) // program error qFatal( "divide: cannot divide by zero" ); return a/b; } \endcode Under X11, the text is printed to stderr. Under Windows, the text is sent to the debugger. \warning The internal buffer is limited to 8196 bytes (including the '\0'-terminator). \warning Passing (const char *)0 as argument to qFatal might lead to crashes on certain platforms due to the platforms printf implementation. \sa qDebug(), qWarning(), qInstallMsgHandler(), \link debug.html Debugging\endlink */ static QtMsgHandler handler = 0; // pointer to debug handler static const int QT_BUFFER_LENGTH = 8196; // internal buffer length #ifdef Q_OS_MAC -const unsigned char * p_str(const char * c, int len=-1) +QString cfstring2qstring(CFStringRef str) +{ + CFIndex length = CFStringGetLength(str); + if(const UniChar *chars = CFStringGetCharactersPtr(str)) + return QString((QChar *)chars, length); + UniChar *buffer = (UniChar*)malloc(length * sizeof(UniChar)); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer); + QString ret((QChar *)buffer, length); + free(buffer); + return ret; +} + +unsigned char * p_str(const char * c, int len=-1) { const int maxlen = 255; if(len == -1) len = qstrlen(c); if(len > maxlen) { qWarning( "p_str len must never exceed %d", maxlen ); len = maxlen; } unsigned char *ret = (unsigned char*)malloc(len+2); *ret=len; memcpy(((char *)ret)+1,c,len); *(ret+len+1) = '\0'; return ret; } -const unsigned char * p_str(const QString &s) +unsigned char * p_str(const QString &s) { return p_str(s, s.length()); } QCString p2qstring(const unsigned char *c) { char *arr = (char *)malloc(c[0] + 1); memcpy(arr, c+1, c[0]); arr[c[0]] = '\0'; QCString ret = arr; delete arr; return ret; } #endif #ifdef Q_CC_MWERKS #include "qt_mac.h" extern bool qt_is_gui_used; static void mac_default_handler( const char *msg ) { if ( qt_is_gui_used ) { const char *p = p_str(msg); DebugStr(p); free(p); } else { fprintf( stderr, msg ); } } #endif void qDebug( const char *msg, ... ) { char buf[QT_BUFFER_LENGTH]; va_list ap; va_start( ap, msg ); // use variable arg list if ( handler ) { #if defined(QT_VSNPRINTF) QT_VSNPRINTF( buf, QT_BUFFER_LENGTH, msg, ap ); #else vsprintf( buf, msg, ap ); #endif va_end( ap ); (*handler)( QtDebugMsg, buf ); } else { #if defined(Q_CC_MWERKS) vsprintf( buf, msg, ap ); // ### is there no vsnprintf()? va_end( ap ); mac_default_handler(buf); #else vfprintf( stderr, msg, ap ); va_end( ap ); fprintf( stderr, "\n" ); // add newline #endif } } // copied... this looks really bad. void debug( const char *msg, ... ) { char buf[QT_BUFFER_LENGTH]; @@ -580,140 +613,140 @@ void qSystemWarning( const char* msg, int code ) FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&string, 0, NULL ); qWarning( "%s\n\tError code %d - %s", msg, code, (const char*)string ); #endif LocalFree( (HLOCAL)string ); #else if ( code != -1 ) qWarning( "%s\n\tError code %d - %s", msg, code, strerror( code ) ); else qWarning( msg ); #endif #endif } /*! \fn void Q_ASSERT( bool test ) \relates QApplication Prints a warning message containing the source code file name and line number if \a test is FALSE. This is really a macro defined in \c qglobal.h. Q_ASSERT is useful for testing pre- and post-conditions. Example: \code // // File: div.cpp // #include <qglobal.h> int divide( int a, int b ) { Q_ASSERT( b != 0 ); // this is line 9 return a/b; } \endcode If \c b is zero, the Q_ASSERT statement will output the following message using the qWarning() function: \code ASSERT: "b == 0" in div.cpp (9) \endcode \sa qWarning(), \link debug.html Debugging\endlink */ /*! \fn void Q_CHECK_PTR( void *p ) \relates QApplication - If \a p is null, a fatal messages says that the program ran out of - memory and exits. If \e p is not null, nothing happens. + If \a p is 0, a fatal messages says that the program ran out of + memory and exits. If \e p is not 0, nothing happens. This is really a macro defined in \c qglobal.h. Example: \code int *a; Q_CHECK_PTR( a = new int[80] ); // WRONG! - a = new int[80]; // Right + a = new (nothrow) int[80]; // Right Q_CHECK_PTR( a ); \endcode \sa qFatal(), \link debug.html Debugging\endlink */ // // The Q_CHECK_PTR macro calls this function to check if an allocation went ok. // #if (QT_VERSION-0 >= 0x040000) #if defined(Q_CC_GNU) #warning "Change Q_CHECK_PTR to '{if ((p)==0) qt_check_pointer(__FILE__,__LINE__);}'" #warning "No need for qt_check_pointer() to return a value - make it void!" #endif #endif bool qt_check_pointer( bool c, const char *n, int l ) { if ( c ) qWarning( "In file %s, line %d: Out of memory", n, l ); return TRUE; } static bool firstObsoleteWarning(const char *obj, const char *oldfunc ) { static QAsciiDict<int> *obsoleteDict = 0; if ( !obsoleteDict ) { // first time func is called obsoleteDict = new QAsciiDict<int>; #if defined(QT_DEBUG) qDebug( "You are using obsolete functions in the Qt library. Call the function\n" "qSuppressObsoleteWarnings() to suppress obsolete warnings.\n" ); #endif } QCString s( obj ); s += "::"; s += oldfunc; if ( obsoleteDict->find(s.data()) == 0 ) { obsoleteDict->insert( s.data(), (int*)1 ); // anything different from 0 return TRUE; } return FALSE; } static bool suppressObsolete = FALSE; void qSuppressObsoleteWarnings( bool suppress ) { suppressObsolete = suppress; } void qObsolete( const char *obj, const char *oldfunc, const char *newfunc ) { if ( suppressObsolete ) return; if ( !firstObsoleteWarning(obj, oldfunc) ) return; if ( obj ) qDebug( "%s::%s: This function is obsolete, use %s instead.", obj, oldfunc, newfunc ); else qDebug( "%s: This function is obsolete, use %s instead.", diff --git a/qmake/tools/qgpluginmanager.cpp b/qmake/tools/qgpluginmanager.cpp index 46c85f5..72246ac 100644 --- a/qmake/tools/qgpluginmanager.cpp +++ b/qmake/tools/qgpluginmanager.cpp @@ -1,70 +1,70 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QGPluginManager class ** -** Copyright (C) 2000-2001 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2003 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. ** **********************************************************************/ #include "qgpluginmanager_p.h" #ifndef QT_NO_COMPONENT #include "qcomlibrary_p.h" #include "qmap.h" #include "qdir.h" /* The following co-occurrence code is borrowed from Qt Linguist. How similar are two texts? The approach used here relies on co-occurrence matrices and is very efficient. Let's see with an example: how similar are "here" and "hither"? The co-occurrence matrix M for "here" is M[h,e] = 1, M[e,r] = 1, M[r,e] = 1 and 0 elsewhere; the matrix N for "hither" is N[h,i] = 1, N[i,t] = 1, ..., N[h,e] = 1, N[e,r] = 1 and 0 elsewhere. The union U of both matrices is the matrix U[i,j] = max { M[i,j], N[i,j] }, and the intersection V is V[i,j] = min { M[i,j], N[i,j] }. The score for a pair of texts is score = (sum of V[i,j] over all i, j) / (sum of U[i,j] over all i, j), a formula suggested by Arnt Gulbrandsen. Here we have score = 2 / 6, or one third. The implementation differs from this in a few details. Most importantly, repetitions are ignored; for input "xxx", M[x,x] equals 1, not 2. */ /* Every character is assigned to one of 20 buckets so that the @@ -414,129 +414,129 @@ QStringList QGPluginManager::featureList() const if ( !enabled() ) return features; QGPluginManager *that = (QGPluginManager*)this; QStringList theLibs = libList; QStringList phase2Libs; QStringList phase2Deny; /* In order to get the feature list we need to add all interesting libraries. If there are libraries with the same base name, we prioritze the one that fits our Qt version number and ignore the others */ QStringList::Iterator it; for ( it = theLibs.begin(); it != theLibs.end(); ++it ) { if ( (*it).isEmpty() || libDict[*it] ) continue; QComLibrary* library = new QComLibrary( *it ); if ( library->qtVersion() == QT_VERSION ) { that->addLibrary( library ); phase2Deny << QFileInfo( *it ).baseName(); } else { delete library; phase2Libs << *it; } } for ( it = phase2Libs.begin(); it != phase2Libs.end(); ++it ) if ( !phase2Deny.contains( QFileInfo( *it ).baseName() ) ) that->addLibrary( new QComLibrary( *it ) ); for ( QDictIterator<QLibrary> pit( plugDict ); pit.current(); ++pit ) features << pit.currentKey(); return features; } bool QGPluginManager::addLibrary( QLibrary* lib ) { if ( !enabled() || !lib ) return FALSE; QComLibrary* plugin = (QComLibrary*)lib; bool useful = FALSE; QUnknownInterface* iFace = 0; plugin->queryInterface( interfaceId, &iFace ); if ( iFace ) { QFeatureListInterface *fliFace = 0; QComponentInformationInterface *cpiFace = 0; iFace->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace ); if ( !fliFace ) plugin->queryInterface( IID_QFeatureList, (QUnknownInterface**)&fliFace ); if ( !fliFace ) { iFace->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace ); if ( !cpiFace ) plugin->queryInterface( IID_QComponentInformation, (QUnknownInterface**)&cpiFace ); } QStringList fl; if ( fliFace ) // Map all found features to the library fl = fliFace->featureList(); else if ( cpiFace ) fl << cpiFace->name(); - for ( QStringList::Iterator f = fl.begin(); f != fl.end(); f++ ) { + for ( QStringList::Iterator f = fl.begin(); f != fl.end(); ++f ) { QLibrary *old = plugDict[*f]; if ( !old ) { useful = TRUE; plugDict.replace( *f, plugin ); } else { // we have old *and* plugin, which one to pick? QComLibrary* first = (QComLibrary*)old; QComLibrary* second = (QComLibrary*)plugin; bool takeFirst = TRUE; if ( first->qtVersion() != QT_VERSION ) { if ( second->qtVersion() == QT_VERSION ) takeFirst = FALSE; else if ( second->qtVersion() < QT_VERSION && first->qtVersion() > QT_VERSION ) takeFirst = FALSE; } if ( !takeFirst ) { useful = TRUE; plugDict.replace( *f, plugin ); qWarning("%s: Discarding feature %s in %s!", (const char*) QFile::encodeName( plugin->library()), (*f).latin1(), (const char*) QFile::encodeName( old->library() ) ); } else { qWarning("%s: Feature %s already defined in %s!", (const char*) QFile::encodeName( old->library() ), (*f).latin1(), (const char*) QFile::encodeName( plugin->library() ) ); } } } if ( fliFace ) fliFace->release(); if ( cpiFace ) cpiFace->release(); iFace->release(); } if ( useful ) { libDict.replace( plugin->library(), plugin ); if ( !libList.contains( plugin->library() ) ) libList.append( plugin->library() ); return TRUE; } delete plugin; return FALSE; } bool QGPluginManager::enabled() const { #ifdef QT_SHARED return TRUE; #else return FALSE; #endif } QRESULT QGPluginManager::queryUnknownInterface(const QString& feature, QUnknownInterface** iface) const { QComLibrary* plugin = 0; plugin = (QComLibrary*)library( feature ); return plugin ? plugin->queryInterface( interfaceId, (QUnknownInterface**)iface ) : QE_NOINTERFACE; } diff --git a/qmake/tools/qgvector.cpp b/qmake/tools/qgvector.cpp index 1985f03..3c903ed 100644 --- a/qmake/tools/qgvector.cpp +++ b/qmake/tools/qgvector.cpp @@ -1,101 +1,107 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QGVector class ** ** Created : 930907 ** ** 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. ** **********************************************************************/ +#include "qglobal.h" +#if defined(Q_CC_BOR) +// needed for qsort() because of a std namespace problem on Borland +#include "qplatformdefs.h" +#endif + #define QGVECTOR_CPP #include "qgvector.h" #include "qglist.h" #include "qstring.h" #include "qdatastream.h" #include <stdlib.h> #ifdef QT_THREAD_SUPPORT # include <private/qmutexpool_p.h> #endif // QT_THREAD_SUPPORT #define USE_MALLOC // comment to use new/delete #undef NEW #undef DELETE #if defined(USE_MALLOC) #define NEW(type,size) ((type*)malloc(size*sizeof(type))) #define DELETE(array) (free((char*)array)) #else #define NEW(type,size) (new type[size]) #define DELETE(array) (delete[] array) #define DONT_USE_REALLOC // comment to use realloc() #endif /*! \class QGVector \reentrant \ingroup collection \brief The QGVector class is an internal class for implementing Qt collection classes. \internal QGVector is an internal class that acts as a base class for the QPtrVector collection class. QGVector has some virtual functions that may be reimplemented in subclasses to customize behavior. \list \i compareItems() compares two collection/vector items. \i read() reads a collection/vector item from a QDataStream. \i write() writes a collection/vector item to a QDataStream. \endlist */ /***************************************************************************** Default implementation of virtual functions *****************************************************************************/ /*! This virtual function compares two list items. Returns: <ul> <li> 0 if \a d1 == \a d2 <li> non-zero if \a d1 != \a d2 </ul> This function returns \e int rather than \e bool so that reimplementations can return one of three values and use it to sort by: @@ -332,129 +338,130 @@ bool QGVector::resize( uint newsize ) // resize array if ( !vec ) // no memory return FALSE; if ( newsize > len ) // init extra space added memset( (void*)&vec[len], 0, (newsize-len)*sizeof(Item) ); len = newsize; return TRUE; } bool QGVector::fill( Item d, int flen ) // resize and fill vector { if ( flen < 0 ) flen = len; // default: use vector length else if ( !resize( flen ) ) return FALSE; for ( uint i=0; i<(uint)flen; i++ ) // insert d at every index insert( i, d ); return TRUE; } static QGVector *sort_vec=0; // current sort vector #if defined(Q_C_CALLBACKS) extern "C" { #endif #ifdef Q_OS_TEMP static int _cdecl cmp_vec( const void *n1, const void *n2 ) #else static int cmp_vec( const void *n1, const void *n2 ) #endif { return sort_vec->compareItems( *((QPtrCollection::Item*)n1), *((QPtrCollection::Item*)n2) ); } #if defined(Q_C_CALLBACKS) } #endif void QGVector::sort() // sort vector { if ( count() == 0 ) // no elements return; register Item *start = &vec[0]; register Item *end = &vec[len-1]; Item tmp; for (;;) { // put all zero elements behind while ( start < end && *start != 0 ) start++; while ( end > start && *end == 0 ) end--; if ( start < end ) { tmp = *start; *start = *end; *end = tmp; } else { break; } } #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &sort_vec ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &sort_vec ) : 0 ); #endif // QT_THREAD_SUPPORT sort_vec = (QGVector*)this; qsort( vec, count(), sizeof(Item), cmp_vec ); sort_vec = 0; } int QGVector::bsearch( Item d ) const // binary search; when sorted { if ( !len ) return -1; if ( !d ) { #if defined(QT_CHECK_NULL) qWarning( "QGVector::bsearch: Cannot search for null object" ); #endif return -1; } int n1 = 0; int n2 = len - 1; int mid = 0; bool found = FALSE; while ( n1 <= n2 ) { int res; mid = (n1 + n2)/2; if ( vec[mid] == 0 ) // null item greater res = -1; else res = ((QGVector*)this)->compareItems( d, vec[mid] ); if ( res < 0 ) n2 = mid - 1; else if ( res > 0 ) n1 = mid + 1; else { // found it found = TRUE; break; } } if ( !found ) return -1; // search to first of equal items while ( (mid - 1 >= 0) && !((QGVector*)this)->compareItems(d, vec[mid-1]) ) mid--; return mid; } int QGVector::findRef( Item d, uint index) const // find exact item in vector { #if defined(QT_CHECK_RANGE) if ( index > len ) { // range error qWarning( "QGVector::findRef: Index %d out of range", index ); return -1; } #endif for ( uint i=index; i<len; i++ ) { if ( vec[i] == d ) return i; } return -1; } int QGVector::find( Item d, uint index ) const // find equal item in vector { #if defined(QT_CHECK_RANGE) if ( index >= len ) { // range error diff --git a/qmake/tools/qlibrary.cpp b/qmake/tools/qlibrary.cpp index 564db30..be1d54b 100644 --- a/qmake/tools/qlibrary.cpp +++ b/qmake/tools/qlibrary.cpp @@ -1,138 +1,138 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QLibrary class ** -** Created : 2000-01-01 +** Created : 000101 ** -** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2003 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. ** **********************************************************************/ #include "qplatformdefs.h" #include <private/qlibrary_p.h> #ifndef QT_NO_LIBRARY // uncomment this to get error messages //#define QT_DEBUG_COMPONENT 1 // uncomment this to get error and success messages //#define QT_DEBUG_COMPONENT 2 #ifndef QT_DEBUG_COMPONENT # if defined(QT_DEBUG) # define QT_DEBUG_COMPONENT 1 # endif #endif #if defined(QT_DEBUG_COMPONENT) #include <qfile.h> #endif #if defined(Q_WS_WIN) && !defined(QT_MAKEDLL) #define QT_NO_LIBRARY_UNLOAD #endif QLibraryPrivate::QLibraryPrivate( QLibrary *lib ) : pHnd( 0 ), library( lib ) { } /*! \class QLibrary qlibrary.h \reentrant \brief The QLibrary class provides a wrapper for handling shared libraries. \mainclass - \group plugins + \ingroup plugins An instance of a QLibrary object can handle a single shared library and provide access to the functionality in the library in a platform independent way. If the library is a component server, QLibrary provides access to the exported component and can directly query this component for interfaces. QLibrary ensures that the shared library is loaded and stays in memory whilst it is in use. QLibrary can also unload the library on destruction and release unused resources. A typical use of QLibrary is to resolve an exported symbol in a shared object, and to call the function that this symbol represents. This is called "explicit linking" in contrast to "implicit linking", which is done by the link step in the build process when linking an executable against a library. The following code snippet loads a library, resolves the symbol "mysymbol", and calls the function if everything succeeded. If something went wrong, e.g. the library file does not exist or the symbol is not defined, the function pointer will be 0 and won't be called. When the QLibrary object is destroyed the library will be unloaded, making all references to memory allocated in the library invalid. \code typedef void (*MyPrototype)(); MyPrototype myFunction; QLibrary myLib( "mylib" ); myFunction = (MyProtoype) myLib.resolve( "mysymbol" ); if ( myFunction ) { myFunction(); } \endcode */ /*! Creates a QLibrary object for the shared library \a filename. The library will be unloaded in the destructor. Note that \a filename does not need to include the (platform specific) file extension, so calling \code QLibrary lib( "mylib" ); \endcode is equivalent to calling \code QLibrary lib( "mylib.dll" ); \endcode on Windows, and \code QLibrary lib( "libmylib.so" ); \endcode on Unix. Specifying the extension is not recommended, since doing so introduces a platform dependency. If \a filename does not include a path, the library loader will look for the file in the platform specific search paths. \sa load() unload(), setAutoUnload() */ QLibrary::QLibrary( const QString& filename ) : libfile( filename ), aunload( TRUE ) @@ -265,79 +265,80 @@ bool QLibrary::unload() # if defined(QT_DEBUG_COMPONENT) qWarning( "%s could not be unloaded", (const char*) QFile::encodeName(library()) ); # endif return FALSE; } # if defined(QT_DEBUG_COMPONENT) && QT_DEBUG_COMPONENT == 2 qWarning( "%s has been unloaded", (const char*) QFile::encodeName(library()) ); # endif d->pHnd = 0; #endif return TRUE; } /*! Returns TRUE if the library will be automatically unloaded when this wrapper object is destructed; otherwise returns FALSE. The default is TRUE. \sa setAutoUnload() */ bool QLibrary::autoUnload() const { return (bool)aunload; } /*! If \a enabled is TRUE (the default), the wrapper object is set to automatically unload the library upon destruction. If \a enabled is FALSE, the wrapper object is not unloaded unless you explicitly call unload(). \sa autoUnload() */ void QLibrary::setAutoUnload( bool enabled ) { aunload = enabled; } /*! Returns the filename of the shared library this QLibrary object handles, including the platform specific file extension. For example: \code QLibrary lib( "mylib" ); QString str = lib.library(); \endcode will set \e str to "mylib.dll" on Windows, and "libmylib.so" on Linux. */ QString QLibrary::library() const { if ( libfile.isEmpty() ) return libfile; QString filename = libfile; #if defined(Q_WS_WIN) if ( filename.findRev( '.' ) <= filename.findRev( '/' ) ) filename += ".dll"; #elif defined(Q_OS_MACX) if ( filename.find( ".dylib" ) == -1 ) filename += ".dylib"; #else - if ( filename.find( ".so" ) == -1 ) { + QString filter = ".so"; + if ( filename.find(filter) == -1 ) { const int x = filename.findRev( "/" ); if ( x != -1 ) { QString path = filename.left( x + 1 ); QString file = filename.right( filename.length() - x - 1 ); - filename = QString( "%1lib%2.so" ).arg( path ).arg( file ); + filename = QString( "%1lib%2.%3" ).arg( path ).arg( file ).arg( filter ); } else { - filename = QString( "lib%1.so" ).arg( filename ); + filename = QString( "lib%1.%2" ).arg( filename ).arg( filter ); } } #endif return filename; } #endif //QT_NO_LIBRARY diff --git a/qmake/tools/qlibrary_unix.cpp b/qmake/tools/qlibrary_unix.cpp index f0fbdf6..12b9310 100644 --- a/qmake/tools/qlibrary_unix.cpp +++ b/qmake/tools/qlibrary_unix.cpp @@ -1,120 +1,137 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QLibraryPrivate class ** -** Created : 2000-01-01 +** Created : 000101 ** ** Copyright (C) 2000-2002 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. ** **********************************************************************/ #include "qplatformdefs.h" #include "private/qlibrary_p.h" #ifndef QT_NO_LIBRARY #if defined(QT_AOUT_UNDERSCORE) #include <string.h> #endif /* The platform dependent implementations of - loadLibrary - freeLibrary - resolveSymbol It's not too hard to guess what the functions do. */ -#if defined(QT_HPUX_LD) // for HP-UX < 11.x and 32 bit +#if defined(Q_OS_MAC) + +bool QLibraryPrivate::loadLibrary() +{ + return FALSE; +} + +bool QLibraryPrivate::freeLibrary() +{ + return FALSE; +} + +void* QLibraryPrivate::resolveSymbol( const char* ) +{ + return 0; +} + +#elif defined(QT_HPUX_LD) // for HP-UX < 11.x and 32 bit bool QLibraryPrivate::loadLibrary() { if ( pHnd ) return TRUE; QString filename = library->library(); pHnd = (void*)shl_load( filename.latin1(), BIND_DEFERRED | BIND_NONFATAL | DYNAMIC_PATH, 0 ); #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) if ( !pHnd ) qWarning( "%s: failed to load library!", filename.latin1() ); #endif return pHnd != 0; } bool QLibraryPrivate::freeLibrary() { if ( !pHnd ) return TRUE; if ( shl_unload( (shl_t)pHnd ) ) { #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) QString filename = library->library(); qWarning( "%s: Failed to unload library!", filename.latin1() ); #endif return FALSE; } pHnd = 0; return TRUE; } void* QLibraryPrivate::resolveSymbol( const char* symbol ) { if ( !pHnd ) return 0; void* address = 0; if ( shl_findsym( (shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address ) < 0 ) { #if defined(QT_DEBUG_COMPONENT) QString filename = library->library(); qWarning( "%s: couldn't resolve symbol \"%s\"", filename.latin1(), symbol ); #endif } return address; } #else // POSIX #include <dlfcn.h> bool QLibraryPrivate::loadLibrary() { if ( pHnd ) return TRUE; QString filename = library->library(); pHnd = dlopen( filename.latin1(), RTLD_LAZY ); #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) if ( !pHnd ) qWarning( "%s", dlerror() ); #endif return pHnd != 0; } diff --git a/qmake/tools/qmutex_unix.cpp b/qmake/tools/qmutex_unix.cpp index c861b2d..3eb59cf 100644 --- a/qmake/tools/qmutex_unix.cpp +++ b/qmake/tools/qmutex_unix.cpp @@ -1,111 +1,112 @@ /**************************************************************************** ** $Id$ ** ** QMutex class for Unix ** ** Created : 20010725 ** ** Copyright (C) 1992-2002 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. ** **********************************************************************/ #if defined(QT_THREAD_SUPPORT) #include "qplatformdefs.h" typedef pthread_mutex_t Q_MUTEX_T; // POSIX threads mutex types #if ((defined(PTHREAD_MUTEX_RECURSIVE) && defined(PTHREAD_MUTEX_DEFAULT)) || \ - defined(Q_OS_FREEBSD)) && !defined(Q_OS_UNIXWARE) && !defined(Q_OS_SOLARIS) - // POSIX 1003.1c-1995 - We love this OS + defined(Q_OS_FREEBSD)) && !defined(Q_OS_UNIXWARE) && !defined(Q_OS_SOLARIS) && \ + !defined(Q_OS_MAC) +// POSIX 1003.1c-1995 - We love this OS # define Q_MUTEX_SET_TYPE(a, b) pthread_mutexattr_settype((a), (b)) # if defined(QT_CHECK_RANGE) # define Q_NORMAL_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK # else # define Q_NORMAL_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT # endif # define Q_RECURSIVE_MUTEX_TYPE PTHREAD_MUTEX_RECURSIVE #elif defined(MUTEX_NONRECURSIVE_NP) && defined(MUTEX_RECURSIVE_NP) // POSIX 1003.4a pthreads draft extensions # define Q_MUTEX_SET_TYPE(a, b) pthread_mutexattr_setkind_np((a), (b)); # define Q_NORMAL_MUTEX_TYPE MUTEX_NONRECURSIVE_NP # define Q_RECURSIVE_MUTEX_TYPE MUTEX_RECURSIVE_NP #else // Unknown mutex types - skip them # define Q_MUTEX_SET_TYPE(a, b) # undef Q_NORMAL_MUTEX_TYPE # undef Q_RECURSIVE_MUTEX_TYPE #endif #include "qmutex.h" #include "qmutex_p.h" #include <errno.h> #include <string.h> // Private class declarations class QRealMutexPrivate : public QMutexPrivate { public: QRealMutexPrivate(bool = FALSE); void lock(); void unlock(); bool locked(); bool trylock(); int type() const; bool recursive; }; #ifndef Q_RECURSIVE_MUTEX_TYPE class QRecursiveMutexPrivate : public QMutexPrivate { public: QRecursiveMutexPrivate(); ~QRecursiveMutexPrivate(); void lock(); void unlock(); bool locked(); bool trylock(); int type() const; int count; unsigned long owner; pthread_mutex_t handle2; }; #endif // !Q_RECURSIVE_MUTEX_TYPE // Private class implementation // base destructor @@ -600,88 +601,89 @@ bool QMutex::tryLock() break; } default: { if ( flag > 10 ) return -1; break; } } return return_value; } \endcode Now, the mutex will always be unlocked when the QMutexLocker object is destroyed (when the function returns since \c locker is an auto variable). The same principle applies to code that throws and catches exceptions. An exception that is not caught in the function that has locked the mutex has no way of unlocking the mutex before the exception is passed up the stack to the calling function. QMutexLocker also provides a mutex() member function that returns the mutex on which the QMutexLocker is operating. This is useful for code that needs access to the mutex, such as QWaitCondition::wait(). For example: \code class SignalWaiter { private: QMutexLocker locker; public: SignalWaiter( QMutex *mutex ) : locker( mutex ) { } void waitForSignal() { ... ... ... while ( ! signalled ) waitcondition.wait( locker.mutex() ); ... ... ... } }; \endcode \sa QMutex, QWaitCondition */ /*! \fn QMutexLocker::QMutexLocker( QMutex *mutex ) Constructs a QMutexLocker and locks \a mutex. The mutex will be - unlocked when the QMutexLocker is destroyed. + unlocked when the QMutexLocker is destroyed. If \a mutex is zero, + QMutexLocker does nothing. \sa QMutex::lock() */ /*! \fn QMutexLocker::~QMutexLocker() Destroys the QMutexLocker and unlocks the mutex which was locked in the constructor. \sa QMutexLocker::QMutexLocker(), QMutex::unlock() */ /*! \fn QMutex *QMutexLocker::mutex() const Returns a pointer to the mutex which was locked in the constructor. \sa QMutexLocker::QMutexLocker() */ #endif // QT_THREAD_SUPPORT diff --git a/qmake/tools/qmutexpool.cpp b/qmake/tools/qmutexpool.cpp index 9ed2829..a8e7402 100644 --- a/qmake/tools/qmutexpool.cpp +++ b/qmake/tools/qmutexpool.cpp @@ -1,130 +1,152 @@ +/**************************************************************************** +** $Id$ +** +** ... +** +** Copyright (C) 2002 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. +** +**********************************************************************/ + #include "qmutexpool_p.h" #ifdef QT_THREAD_SUPPORT #include <qthread.h> -#include <stdio.h> QMutexPool *qt_global_mutexpool = 0; -// this is an internal class used only for inititalizing the global mutexpool -class QGlobalMutexPoolInitializer -{ -public: - inline QGlobalMutexPoolInitializer() - { - /* - Purify will report a leak here. However, this mutex pool must be alive - until *everything* in Qt has been destructed. Unfortunately there is - no way to guarantee this, so we never destroy this mutex pool. - */ - qt_global_mutexpool = new QMutexPool( TRUE ); - } -}; -QGlobalMutexPoolInitializer qt_global_mutexpool_initializer; /*! \class QMutexPool qmutexpool_p.h \brief The QMutexPool class provides a pool of QMutex objects. \internal \ingroup thread QMutexPool is a convenience class that provides access to a fixed number of QMutex objects. Typical use of a QMutexPool is in situations where it is not possible or feasible to use one QMutex for every protected object. The mutex pool will return a mutex based on the address of the object that needs protection. For example, consider this simple class: \code class Number { public: Number( double n ) : num ( n ) { } void setNumber( double n ) { num = n; } double number() const { return num; } private: double num; }; \endcode Adding a QMutex member to the Number class does not make sense, because it is so small. However, in order to ensure that access to each Number is protected, you need to use a mutex. In this case, a QMutexPool would be ideal. Code to calculate the square of a number would then look something like this: \code void calcSquare( Number *num ) { QMutexLocker locker( mutexpool.get( num ) ); num.setNumber( num.number() * num.number() ); } \endcode This function will safely calculate the square of a number, since it uses a mutex from a QMutexPool. The mutex is locked and unlocked automatically by the QMutexLocker class. See the QMutexLocker documentation for more details. */ /*! Constructs a QMutexPool, reserving space for \a size QMutexes. If \a recursive is TRUE, all QMutexes in the pool will be recursive mutexes; otherwise they will all be non-recursive (the default). The QMutexes are created when needed, and deleted when the QMutexPool is destructed. */ QMutexPool::QMutexPool( bool recursive, int size ) - : mutex( FALSE ), mutexes( size ), recurs( recursive ) + : mutex( FALSE ), count( size ), recurs( recursive ) { - mutexes.fill( 0 ); + mutexes = new QMutex*[count]; + for ( int index = 0; index < count; ++index ) { + mutexes[index] = 0; + } } /*! Destructs a QMutexPool. All QMutexes that were created by the pool are deleted. */ QMutexPool::~QMutexPool() { QMutexLocker locker( &mutex ); - QMutex **d = mutexes.data(); - for ( int index = 0; (uint) index < mutexes.size(); index++ ) { - delete d[index]; - d[index] = 0; + for ( int index = 0; index < count; ++index ) { + delete mutexes[index]; + mutexes[index] = 0; } + delete [] mutexes; + mutexes = 0; } /*! Returns a QMutex from the pool. QMutexPool uses the value \a address to determine which mutex is retured from the pool. */ QMutex *QMutexPool::get( void *address ) { - QMutex **d = mutexes.data(); - int index = (int)( (ulong) address % mutexes.size() ); + int index = (int) ( (unsigned long) address % count ); - if ( ! d[index] ) { + if ( ! mutexes[index] ) { // mutex not created, create one QMutexLocker locker( &mutex ); // we need to check once again that the mutex hasn't been created, since // 2 threads could be trying to create a mutex as the same index... - if ( ! d[index] ) { - d[index] = new QMutex( recurs ); + if ( ! mutexes[index] ) { + mutexes[index] = new QMutex( recurs ); } } - return d[index]; + return mutexes[index]; } #endif diff --git a/qmake/tools/qregexp.cpp b/qmake/tools/qregexp.cpp index 500efed..0c1f060 100644 --- a/qmake/tools/qregexp.cpp +++ b/qmake/tools/qregexp.cpp @@ -202,137 +202,137 @@ another assertion, this time <b>\b</b> "word boundary": <b>\b(mail|letter|correspondence)\b</b>. This regexp means "match a word boundary followed by the expression in parentheses followed by another word boundary". The <b>\b</b> assertion matches at a \e position in the regexp not a \e character in the regexp. A word boundary is any non-word character such as a space a newline or the beginning or end of the string. For our third example we want to replace ampersands with the HTML entity '\&'. The regexp to match is simple: <b>\&</b>, i.e. match one ampersand. Unfortunately this will mess up our text if some of the ampersands have already been turned into HTML entities. So what we really want to say is replace an ampersand providing it is not followed by 'amp;'. For this we need the negative lookahead assertion and our regexp becomes: <b>\&(?!amp;)</b>. The negative lookahead assertion is introduced with '(?!' and finishes at the ')'. It means that the text it contains, 'amp;' in our example, must \e not follow the expression that preceeds it. Regexps provide a rich language that can be used in a variety of ways. For example suppose we want to count all the occurrences of 'Eric' and 'Eirik' in a string. Two valid regexps to match these are <b>\\b(Eric|Eirik)\\b</b> and <b>\\bEi?ri[ck]\\b</b>. We need the word boundary '\b' so we don't get 'Ericsson' etc. The second regexp actually matches more than we want, 'Eric', 'Erik', 'Eiric' and 'Eirik'. We will implement some the examples above in the \link #code-examples code examples \endlink section. \target characters-and-abbreviations-for-sets-of-characters \section1 Characters and Abbreviations for Sets of Characters \table \header \i Element \i Meaning \row \i <b>c</b> \i Any character represents itself unless it has a special regexp meaning. Thus <b>c</b> matches the character \e c. \row \i <b>\\c</b> \i A character that follows a backslash matches the character itself except where mentioned below. For example if you wished to match a literal caret at the beginning of a string you would write <b>\^</b>. \row \i <b>\\a</b> \i This matches the ASCII bell character (BEL, 0x07). \row \i <b>\\f</b> \i This matches the ASCII form feed character (FF, 0x0C). \row \i <b>\\n</b> \i This matches the ASCII line feed character (LF, 0x0A, Unix newline). \row \i <b>\\r</b> \i This matches the ASCII carriage return character (CR, 0x0D). \row \i <b>\\t</b> \i This matches the ASCII horizontal tab character (HT, 0x09). \row \i <b>\\v</b> \i This matches the ASCII vertical tab character (VT, 0x0B). \row \i <b>\\xhhhh</b> \i This matches the Unicode character corresponding to the hexadecimal number hhhh (between 0x0000 and 0xFFFF). \0ooo (i.e., \zero ooo) matches the ASCII/Latin-1 character corresponding to the octal number ooo (between 0 and 0377). \row \i <b>. (dot)</b> \i This matches any character (including newline). \row \i <b>\\d</b> - \i This matches a digit (see QChar::isDigit()). + \i This matches a digit (QChar::isDigit()). \row \i <b>\\D</b> \i This matches a non-digit. \row \i <b>\\s</b> - \i This matches a whitespace (see QChar::isSpace()). + \i This matches a whitespace (QChar::isSpace()). \row \i <b>\\S</b> \i This matches a non-whitespace. \row \i <b>\\w</b> - \i This matches a word character (see QChar::isLetterOrNumber()). + \i This matches a word character (QChar::isLetterOrNumber() or '_'). \row \i <b>\\W</b> \i This matches a non-word character. \row \i <b>\\n</b> \i The n-th \link #capturing-text backreference \endlink, e.g. \1, \2, etc. \endtable \e {Note that the C++ compiler transforms backslashes in strings so to include a <b>\\</b> in a regexp you will need to enter it twice, i.e. <b>\\\\</b>.} \target sets-of-characters \section1 Sets of Characters Square brackets are used to match any character in the set of characters contained within the square brackets. All the character set abbreviations described above can be used within square brackets. Apart from the character set abbreviations and the following two exceptions no characters have special meanings in square brackets. \table \row \i <b>^</b> \i The caret negates the character set if it occurs as the first character, i.e. immediately after the opening square bracket. For example, <b>[abc]</b> matches 'a' or 'b' or 'c', but <b>[^abc]</b> matches anything \e except 'a' or 'b' or 'c'. \row \i <b>-</b> \i The dash is used to indicate a range of characters, for example <b>[W-Z]</b> matches 'W' or 'X' or 'Y' or 'Z'. \endtable Using the predefined character set abbreviations is more portable than using character ranges across platforms and languages. For example, <b>[0-9]</b> matches a digit in Western alphabets but <b>\d</b> matches a digit in \e any alphabet. Note that in most regexp literature sets of characters are called "character classes". \target quantifiers \section1 Quantifiers By default an expression is automatically quantified by <b>{1,1}</b>, i.e. it should occur exactly once. In the following list <b>\e {E}</b> stands for any expression. An expression is a character or an abbreviation for a set of characters or a set of characters in square brackets or any parenthesised expression. \table \row \i <b>\e {E}?</b> \i Matches zero or one occurrence of \e E. This quantifier means "the previous expression is optional" since it will match whether or not the expression occurs in the string. It is the same as <b>\e {E}{0,1}</b>. For example <b>dents?</b> will match 'dent' and 'dents'. \row \i <b>\e {E}+</b> \i Matches one or more occurrences of \e E. This is the same as <b>\e {E}{1,MAXINT}</b>. For example, <b>0+</b> will match '0', '00', '000', etc. \row \i <b>\e {E}*</b> @@ -486,129 +486,136 @@ \i This matches any single character. It is the same as <b>.</b> in full regexps. \row \i <b>*</b> \i This matches zero or more of any characters. It is the same as <b>.*</b> in full regexps. \row \i <b>[...]</b> \i Sets of characters can be represented in square brackets, similar to full regexps. Within the character class, like outside, backslash has no special meaning. \endtable For example if we are in wildcard mode and have strings which contain filenames we could identify HTML files with <b>*.html</b>. This will match zero or more characters followed by a dot followed by 'h', 't', 'm' and 'l'. \target perl-users \section1 Notes for Perl Users Most of the character class abbreviations supported by Perl are supported by QRegExp, see \link #characters-and-abbreviations-for-sets-of-characters characters and abbreviations for sets of characters \endlink. In QRegExp, apart from within character classes, \c{^} always signifies the start of the string, so carets must always be escaped unless used for that purpose. In Perl the meaning of caret varies automagically depending on where it occurs so escaping it is rarely necessary. The same applies to \c{$} which in QRegExp always signifies the end of the string. QRegExp's quantifiers are the same as Perl's greedy quantifiers. Non-greedy matching cannot be applied to individual quantifiers, but can be applied to all the quantifiers in the pattern. For example, to match the Perl regexp <b>ro+?m</b> requires: \code QRegExp rx( "ro+m" ); rx.setMinimal( TRUE ); \endcode The equivalent of Perl's \c{/i} option is setCaseSensitive(FALSE). Perl's \c{/g} option can be emulated using a \link #cap_in_a_loop loop \endlink. In QRegExp <b>.</b> matches any character, therefore all QRegExp regexps have the equivalent of Perl's \c{/s} option. QRegExp does not have an equivalent to Perl's \c{/m} option, but this can be emulated in various ways for example by splitting the input into lines or by looping with a regexp that searches for newlines. Because QRegExp is string oriented there are no \A, \Z or \z assertions. The \G assertion is not supported but can be emulated in a loop. Perl's $& is cap(0) or capturedTexts()[0]. There are no QRegExp equivalents for $`, $' or $+. Perl's capturing variables, $1, $2, ... correspond to cap(1) or capturedTexts()[1], cap(2) or capturedTexts()[2], etc. To substitute a pattern use QString::replace(). Perl's extended \c{/x} syntax is not supported, nor are - regexp comments (?#comment) or directives, e.g. (?i). + directives, e.g. (?i), or regexp comments, e.g. (?#comment). On + the other hand, C++'s rules for literal strings can be used to + achieve the same: + \code + QRegExp mark( "\\b" // word boundary + "[Mm]ark" // the word we want to match + ); + \endcode Both zero-width positive and zero-width negative lookahead assertions (?=pattern) and (?!pattern) are supported with the same syntax as Perl. Perl's lookbehind assertions, "independent" subexpressions and conditional expressions are not supported. Non-capturing parentheses are also supported, with the same (?:pattern) syntax. See QStringList::split() and QStringList::join() for equivalents to Perl's split and join functions. Note: because C++ transforms \\'s they must be written \e twice in code, e.g. <b>\\b</b> must be written <b>\\\\b</b>. \target code-examples \section1 Code Examples \code QRegExp rx( "^\\d\\d?$" ); // match integers 0 to 99 rx.search( "123" ); // returns -1 (no match) rx.search( "-6" ); // returns -1 (no match) rx.search( "6" ); // returns 0 (matched as position 0) \endcode The third string matches '<u>6</u>'. This is a simple validation regexp for integers in the range 0 to 99. \code QRegExp rx( "^\\S+$" ); // match strings without whitespace rx.search( "Hello world" ); // returns -1 (no match) rx.search( "This_is-OK" ); // returns 0 (matched at position 0) \endcode The second string matches '<u>This_is-OK</u>'. We've used the character set abbreviation '\S' (non-whitespace) and the anchors to match strings which contain no whitespace. In the following example we match strings containing 'mail' or 'letter' or 'correspondence' but only match whole words i.e. not 'email' \code QRegExp rx( "\\b(mail|letter|correspondence)\\b" ); rx.search( "I sent you an email" ); // returns -1 (no match) rx.search( "Please write the letter" ); // returns 17 \endcode The second string matches "Please write the <u>letter</u>". The word 'letter' is also captured (because of the parentheses). We can see what text we've captured like this: \code QString captured = rx.cap( 1 ); // captured == "letter" \endcode This will capture the text from the first set of capturing parentheses (counting capturing left parentheses from left to right). The parentheses are counted from 1 since cap( 0 ) is the whole matched regexp (equivalent to '&' in most regexp engines). \code QRegExp rx( "&(?!amp;)" ); // match ampersands but not & QString line1 = "This & that"; @@ -616,166 +623,171 @@ // line1 == "This & that" QString line2 = "His & hers & theirs"; line2.replace( rx, "&" ); // line2 == "His & hers & theirs" \endcode Here we've passed the QRegExp to QString's replace() function to replace the matched text with new text. \code QString str = "One Eric another Eirik, and an Ericsson." " How many Eiriks, Eric?"; QRegExp rx( "\\b(Eric|Eirik)\\b" ); // match Eric or Eirik int pos = 0; // where we are in the string int count = 0; // how many Eric and Eirik's we've counted while ( pos >= 0 ) { pos = rx.search( str, pos ); if ( pos >= 0 ) { pos++; // move along in str count++; // count our Eric or Eirik } } \endcode We've used the search() function to repeatedly match the regexp in the string. Note that instead of moving forward by one character at a time \c pos++ we could have written \c {pos += rx.matchedLength()} to skip over the already matched string. The count will equal 3, matching 'One <u>Eric</u> another <u>Eirik</u>, and an Ericsson. How many Eiriks, <u>Eric</u>?'; it doesn't match 'Ericsson' or 'Eiriks' because they are not bounded by non-word boundaries. One common use of regexps is to split lines of delimited data into their component fields. \code str = "Trolltech AS\twww.trolltech.com\tNorway"; QString company, web, country; rx.setPattern( "^([^\t]+)\t([^\t]+)\t([^\t]+)$" ); if ( rx.search( str ) != -1 ) { company = rx.cap( 1 ); web = rx.cap( 2 ); country = rx.cap( 3 ); } \endcode In this example our input lines have the format company name, web address and country. Unfortunately the regexp is rather long and not very versatile -- the code will break if we add any more fields. A simpler and better solution is to look for the separator, '\t' in this case, and take the surrounding text. The QStringList split() function can take a separator string or regexp as an argument and split a string accordingly. \code QStringList field = QStringList::split( "\t", str ); \endcode Here field[0] is the company, field[1] the web address and so on. To imitate the matching of a shell we can use wildcard mode. \code - QRegExp rx( "*.html" ); // invalid regexp: * doesn't quantify anything - rx.setWildcard( TRUE ); // now it's a valid wildcard regexp - rx.search( "index.html" ); // returns 0 (matched at position 0) - rx.search( "default.htm" ); // returns -1 (no match) - rx.search( "readme.txt" ); // returns -1 (no match) + QRegExp rx( "*.html" ); // invalid regexp: * doesn't quantify anything + rx.setWildcard( TRUE ); // now it's a valid wildcard regexp + rx.exactMatch( "index.html" ); // returns TRUE + rx.exactMatch( "default.htm" ); // returns FALSE + rx.exactMatch( "readme.txt" ); // returns FALSE \endcode Wildcard matching can be convenient because of its simplicity, but any wildcard regexp can be defined using full regexps, e.g. <b>.*\.html$</b>. Notice that we can't match both \c .html and \c .htm files with a wildcard unless we use <b>*.htm*</b> which will also match 'test.html.bak'. A full regexp gives us the precision we need, <b>.*\\.html?$</b>. QRegExp can match case insensitively using setCaseSensitive(), and can use non-greedy matching, see setMinimal(). By default QRegExp uses full regexps but this can be changed with setWildcard(). Searching can be forward with search() or backward with searchRev(). Captured text can be accessed using capturedTexts() which returns a string list of all captured strings, or using cap() which returns the captured string for the given index. The pos() function takes a match index and returns the position in the string where the match was made (or -1 if there was no match). \sa QRegExpValidator QString QStringList \target member-function-documentation */ const int NumBadChars = 64; #define BadChar( ch ) ( (ch).unicode() % NumBadChars ) const int NoOccurrence = INT_MAX; const int EmptyCapture = INT_MAX; const int InftyLen = INT_MAX; const int InftyRep = 1025; const int EOS = -1; +static bool isWord( QChar ch ) +{ + return ch.isLetterOrNumber() || ch == QChar( '_' ); +} + /* Merges two QMemArrays of ints and puts the result into the first one. */ static void mergeInto( QMemArray<int> *a, const QMemArray<int>& b ) { int asize = a->size(); int bsize = b.size(); if ( asize == 0 ) { *a = b.copy(); #ifndef QT_NO_REGEXP_OPTIM } else if ( bsize == 1 && (*a)[asize - 1] < b[0] ) { a->resize( asize + 1 ); (*a)[asize] = b[0]; #endif } else if ( bsize >= 1 ) { int csize = asize + bsize; QMemArray<int> c( csize ); int i = 0, j = 0, k = 0; while ( i < asize ) { if ( j < bsize ) { if ( (*a)[i] == b[j] ) { i++; csize--; } else if ( (*a)[i] < b[j] ) { c[k++] = (*a)[i++]; } else { c[k++] = b[j++]; } } else { memcpy( c.data() + k, (*a).data() + i, (asize - i) * sizeof(int) ); break; } } c.resize( csize ); if ( j < bsize ) memcpy( c.data() + k, b.data() + j, (bsize - j) * sizeof(int) ); *a = c; } } /* Merges two disjoint QMaps of (int, int) pairs and puts the result into the first one. */ static void mergeInto( QMap<int, int> *a, const QMap<int, int>& b ) { QMap<int, int>::ConstIterator it; for ( it = b.begin(); it != b.end(); ++it ) a->insert( it.key(), *it ); } /* Returns the value associated to key k in QMap m of (int, int) pairs, or 0 if no such value is explicitly present. */ static int at( const QMap<int, int>& m, int k ) { QMap<int, int>::ConstIterator it = m.find( k ); if ( it == m.end() ) return 0; else return *it; } @@ -1619,131 +1631,131 @@ int QRegExpEngine::startAtom( bool capture ) #ifndef QT_NO_REGEXP_LOOKAHEAD /* Creates a lookahead anchor. */ int QRegExpEngine::addLookahead( QRegExpEngine *eng, bool negative ) { int n = ahead.size(); if ( n == MaxLookaheads ) { error( RXERR_LIMIT ); return 0; } ahead.resize( n + 1 ); ahead.insert( n, new Lookahead(eng, negative) ); return Anchor_FirstLookahead << n; } #endif #ifndef QT_NO_REGEXP_CAPTURE /* We want the longest leftmost captures. */ bool QRegExpEngine::isBetterCapture( const int *begin1, const int *end1, const int *begin2, const int *end2 ) { for ( int i = 0; i < ncap; i++ ) { int delta = begin2[i] - begin1[i]; // it has to start early... if ( delta == 0 ) delta = end1[i] - end2[i]; // ...and end late (like a party) if ( delta != 0 ) return delta > 0; } return FALSE; } #endif /* Returns TRUE if anchor a matches at position mmPos + i in the input string, otherwise FALSE. */ bool QRegExpEngine::testAnchor( int i, int a, const int *capBegin ) { int j; #ifndef QT_NO_REGEXP_ANCHOR_ALT if ( (a & Anchor_Alternation) != 0 ) { return testAnchor( i, aa[a ^ Anchor_Alternation].a, capBegin ) || testAnchor( i, aa[a ^ Anchor_Alternation].b, capBegin ); } #endif if ( (a & Anchor_Caret) != 0 ) { if ( mmPos + i != mmCaretPos ) return FALSE; } if ( (a & Anchor_Dollar) != 0 ) { if ( mmPos + i != mmLen ) return FALSE; } #ifndef QT_NO_REGEXP_ESCAPE if ( (a & (Anchor_Word | Anchor_NonWord)) != 0 ) { bool before = FALSE; bool after = FALSE; if ( mmPos + i != 0 ) - before = mmIn[mmPos + i - 1].isLetterOrNumber(); + before = isWord( mmIn[mmPos + i - 1] ); if ( mmPos + i != mmLen ) - after = mmIn[mmPos + i].isLetterOrNumber(); + after = isWord( mmIn[mmPos + i] ); if ( (a & Anchor_Word) != 0 && (before == after) ) return FALSE; if ( (a & Anchor_NonWord) != 0 && (before != after) ) return FALSE; } #endif #ifndef QT_NO_REGEXP_LOOKAHEAD bool catchx = TRUE; if ( (a & Anchor_LookaheadMask) != 0 ) { QConstString cstr = QConstString( (QChar *) mmIn + mmPos + i, mmLen - mmPos - i ); for ( j = 0; j < (int) ahead.size(); j++ ) { if ( (a & (Anchor_FirstLookahead << j)) != 0 ) { catchx = ahead[j]->eng->match( cstr.string(), 0, TRUE, TRUE, mmCaretPos - mmPos - i )[0] == 0; if ( catchx == ahead[j]->neg ) return FALSE; } } } #endif #ifndef QT_NO_REGEXP_CAPTURE #ifndef QT_NO_REGEXP_BACKREF for ( j = 0; j < nbrefs; j++ ) { if ( (a & (Anchor_BackRef1Empty << j)) != 0 ) { if ( capBegin[j] != EmptyCapture ) return FALSE; } } #endif #endif return TRUE; } #ifndef QT_NO_REGEXP_OPTIM /* The three following functions are what Jeffrey Friedl would call transmissions (or bump-alongs). Using one or the other should make no difference except in performance. */ bool QRegExpEngine::goodStringMatch() { int k = mmPos + goodEarlyStart; while ( (k = mmStr->find(goodStr, k, cs)) != -1 ) { int from = k - goodLateStart; int to = k - goodEarlyStart; if ( from > mmPos ) mmPos = from; while ( mmPos <= to ) { if ( matchHere() ) return TRUE; mmPos++; } k++; } return FALSE; } bool QRegExpEngine::badCharMatch() { @@ -2571,148 +2583,156 @@ void QRegExpEngine::Box::addAnchorsToEngine( const Box& to ) const } int QRegExpEngine::getChar() { return ( yyPos == yyLen ) ? EOS : yyIn[yyPos++].unicode(); } int QRegExpEngine::getEscape() { #ifndef QT_NO_REGEXP_ESCAPE const char tab[] = "afnrtv"; // no b, as \b means word boundary const char backTab[] = "\a\f\n\r\t\v"; ushort low; int i; #endif ushort val; int prevCh = yyCh; if ( prevCh == EOS ) { error( RXERR_END ); return Tok_Char | '\\'; } yyCh = getChar(); #ifndef QT_NO_REGEXP_ESCAPE if ( (prevCh & ~0xff) == 0 ) { const char *p = strchr( tab, prevCh ); if ( p != 0 ) return Tok_Char | backTab[p - tab]; } #endif switch ( prevCh ) { #ifndef QT_NO_REGEXP_ESCAPE case '0': val = 0; for ( i = 0; i < 3; i++ ) { if ( yyCh >= '0' && yyCh <= '7' ) val = ( val << 3 ) | ( yyCh - '0' ); else break; yyCh = getChar(); } if ( (val & ~0377) != 0 ) error( RXERR_OCTAL ); return Tok_Char | val; #endif #ifndef QT_NO_REGEXP_ESCAPE case 'B': return Tok_NonWord; #endif #ifndef QT_NO_REGEXP_CCLASS case 'D': // see QChar::isDigit() yyCharClass->addCategories( 0x7fffffef ); return Tok_CharClass; case 'S': // see QChar::isSpace() yyCharClass->addCategories( 0x7ffff87f ); yyCharClass->addRange( 0x0000, 0x0008 ); yyCharClass->addRange( 0x000e, 0x001f ); yyCharClass->addRange( 0x007f, 0x009f ); return Tok_CharClass; case 'W': // see QChar::isLetterOrNumber() - yyCharClass->addCategories( 0x7ff07f8f ); + yyCharClass->addCategories( 0x7fe07f8f ); + yyCharClass->addRange( 0x203f, 0x2040 ); + yyCharClass->addSingleton( 0x2040 ); + yyCharClass->addSingleton( 0x30fb ); + yyCharClass->addRange( 0xfe33, 0xfe34 ); + yyCharClass->addRange( 0xfe4d, 0xfe4f ); + yyCharClass->addSingleton( 0xff3f ); + yyCharClass->addSingleton( 0xff65 ); return Tok_CharClass; #endif #ifndef QT_NO_REGEXP_ESCAPE case 'b': return Tok_Word; #endif #ifndef QT_NO_REGEXP_CCLASS case 'd': // see QChar::isDigit() yyCharClass->addCategories( 0x00000010 ); return Tok_CharClass; case 's': // see QChar::isSpace() yyCharClass->addCategories( 0x00000380 ); yyCharClass->addRange( 0x0009, 0x000d ); return Tok_CharClass; case 'w': // see QChar::isLetterOrNumber() yyCharClass->addCategories( 0x000f8070 ); + yyCharClass->addSingleton( 0x005f ); // '_' return Tok_CharClass; #endif #ifndef QT_NO_REGEXP_ESCAPE case 'x': val = 0; for ( i = 0; i < 4; i++ ) { low = QChar( yyCh ).lower(); if ( low >= '0' && low <= '9' ) val = ( val << 4 ) | ( low - '0' ); else if ( low >= 'a' && low <= 'f' ) val = ( val << 4 ) | ( low - 'a' + 10 ); else break; yyCh = getChar(); } return Tok_Char | val; #endif default: if ( prevCh >= '1' && prevCh <= '9' ) { #ifndef QT_NO_REGEXP_BACKREF val = prevCh - '0'; while ( yyCh >= '0' && yyCh <= '9' ) { val = ( val *= 10 ) | ( yyCh - '0' ); yyCh = getChar(); } return Tok_BackRef | val; #else error( RXERR_DISABLED ); #endif } return Tok_Char | prevCh; } } #ifndef QT_NO_REGEXP_INTERVAL int QRegExpEngine::getRep( int def ) { if ( yyCh >= '0' && yyCh <= '9' ) { int rep = 0; do { rep = 10 * rep + yyCh - '0'; if ( rep >= InftyRep ) { error( RXERR_REPETITION ); rep = def; } yyCh = getChar(); } while ( yyCh >= '0' && yyCh <= '9' ); return rep; } else { return def; } } #endif #ifndef QT_NO_REGEXP_LOOKAHEAD void QRegExpEngine::skipChars( int n ) { if ( n > 0 ) { yyPos += n - 1; yyCh = getChar(); } } #endif @@ -3122,149 +3142,151 @@ void QRegExpEngine::parseFactor( Box *box ) #ifndef QT_NO_REGEXP_INTERVAL yyMayCapture = mayCapture; #endif } #undef YYREDO } void QRegExpEngine::parseTerm( Box *box ) { #ifndef QT_NO_REGEXP_OPTIM if ( yyTok != Tok_Eos && yyTok != Tok_RightParen && yyTok != Tok_Bar ) parseFactor( box ); #endif while ( yyTok != Tok_Eos && yyTok != Tok_RightParen && yyTok != Tok_Bar ) { Box rightBox( this ); parseFactor( &rightBox ); box->cat( rightBox ); } } void QRegExpEngine::parseExpression( Box *box ) { parseTerm( box ); while ( yyTok == Tok_Bar ) { Box rightBox( this ); yyTok = getToken(); parseTerm( &rightBox ); box->orx( rightBox ); } } /* The struct QRegExpPrivate contains the private data of a regular expression other than the automaton. It makes it possible for many QRegExp objects to use the same QRegExpEngine object with different QRegExpPrivate objects. */ struct QRegExpPrivate { QString pattern; // regular-expression or wildcard pattern QString rxpattern; // regular-expression pattern #ifndef QT_NO_REGEXP_WILDCARD bool wc; // wildcard mode? #endif bool min; // minimal matching? (instead of maximal) #ifndef QT_NO_REGEXP_CAPTURE QString t; // last string passed to QRegExp::search() or searchRev() QStringList capturedCache; // what QRegExp::capturedTexts() returned last #endif QMemArray<int> captured; // what QRegExpEngine::search() returned last QRegExpPrivate() { captured.fill( -1, 2 ); } }; #ifndef QT_NO_REGEXP_OPTIM static QCache<QRegExpEngine> *engineCache = 0; static QSingleCleanupHandler<QCache<QRegExpEngine> > cleanup_cache; #endif static QRegExpEngine *newEngine( const QString& pattern, bool caseSensitive ) { #ifndef QT_NO_REGEXP_OPTIM if ( engineCache != 0 ) { #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &engineCache ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &engineCache ) : 0 ); #endif QRegExpEngine *eng = engineCache->take( pattern ); if ( eng == 0 || eng->caseSensitive() != caseSensitive ) { delete eng; } else { eng->ref(); return eng; } } #endif return new QRegExpEngine( pattern, caseSensitive ); } static void derefEngine( QRegExpEngine *eng, const QString& pattern ) { - if ( eng != 0 && eng->deref() ) { -#ifndef QT_NO_REGEXP_OPTIM #ifdef QT_THREAD_SUPPORT - QMutexLocker locker( qt_global_mutexpool->get( &engineCache ) ); + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &engineCache ) : 0 ); #endif + if ( eng != 0 && eng->deref() ) { +#ifndef QT_NO_REGEXP_OPTIM if ( engineCache == 0 ) { engineCache = new QCache<QRegExpEngine>; engineCache->setAutoDelete( TRUE ); cleanup_cache.set( &engineCache ); } if ( !pattern.isNull() && engineCache->insert(pattern, eng, 4 + pattern.length() / 4) ) return; #else Q_UNUSED( pattern ); #endif delete eng; } } /*! \enum QRegExp::CaretMode The CaretMode enum defines the different meanings of the caret (<b>^</b>) in a regular expression. The possible values are: \value CaretAtZero The caret corresponds to index 0 in the searched string. \value CaretAtOffset The caret corresponds to the start offset of the search. \value CaretWontMatch The caret never matches. */ /*! Constructs an empty regexp. \sa isValid() errorString() */ QRegExp::QRegExp() { eng = new QRegExpEngine( TRUE ); priv = new QRegExpPrivate; #ifndef QT_NO_REGEXP_WILDCARD priv->wc = FALSE; #endif priv->min = FALSE; compile( TRUE ); } /*! Constructs a regular expression object for the given \a pattern string. The pattern must be given using wildcard notation if \a wildcard is TRUE (default is FALSE). The pattern is case sensitive, unless \a caseSensitive is FALSE. Matching is greedy (maximal), but can be changed by calling setMinimal(). \sa setPattern() setCaseSensitive() setWildcard() setMinimal() */ QRegExp::QRegExp( const QString& pattern, bool caseSensitive, bool wildcard ) { eng = 0; priv = new QRegExpPrivate; priv->pattern = pattern; #ifndef QT_NO_REGEXP_WILDCARD priv->wc = wildcard; #endif @@ -3504,258 +3526,244 @@ void QRegExp::setMinimal( bool minimal ) Returns TRUE if \a str is matched exactly by this regular expression; otherwise returns FALSE. You can determine how much of the string was matched by calling matchedLength(). For a given regexp string, R, exactMatch("R") is the equivalent of search("^R$") since exactMatch() effectively encloses the regexp in the start of string and end of string anchors, except that it sets matchedLength() differently. For example, if the regular expression is <b>blue</b>, then exactMatch() returns TRUE only for input \c blue. For inputs \c bluebell, \c blutak and \c lightblue, exactMatch() returns FALSE and matchedLength() will return 4, 3 and 0 respectively. Although const, this function sets matchedLength(), capturedTexts() and pos(). \sa search() searchRev() QRegExpValidator */ bool QRegExp::exactMatch( const QString& str ) const { #ifndef QT_NO_REGEXP_CAPTURE priv->t = str; priv->capturedCache.clear(); #endif priv->captured = eng->match( str, 0, priv->min, TRUE, 0 ); if ( priv->captured[1] == (int) str.length() ) { return TRUE; } else { priv->captured.detach(); priv->captured[0] = 0; priv->captured[1] = eng->matchedLength(); return FALSE; } } #ifndef QT_NO_COMPAT /*! \obsolete Attempts to match in \a str, starting from position \a index. Returns the position of the match, or -1 if there was no match. The length of the match is stored in \a *len, unless \a len is a null pointer. If \a indexIsStart is TRUE (the default), the position \a index in the string will match the start of string anchor, <b>^</b>, in the regexp, if present. Otherwise, position 0 in \a str will match. Use search() and matchedLength() instead of this function. \sa QString::mid() QConstString */ int QRegExp::match( const QString& str, int index, int *len, bool indexIsStart ) const { int pos = search( str, index, indexIsStart ? CaretAtOffset : CaretAtZero ); if ( len != 0 ) *len = matchedLength(); return pos; } #endif // QT_NO_COMPAT -/*! - \overload - - This convenience function searches with a \c CaretMode of \c - CaretAtZero which is the most common usage. -*/ - int QRegExp::search( const QString& str, int offset ) const { return search( str, offset, CaretAtZero ); } /*! Attempts to find a match in \a str from position \a offset (0 by default). If \a offset is -1, the search starts at the last character; if -2, at the next to last character; etc. Returns the position of the first match, or -1 if there was no match. The \a caretMode parameter can be used to instruct whether <b>^</b> should match at index 0 or at \a offset. You might prefer to use QString::find(), QString::contains() or even QStringList::grep(). To replace matches use QString::replace(). Example: \code QString str = "offsets: 1.23 .50 71.00 6.00"; QRegExp rx( "\\d*\\.\\d+" ); // primitive floating point matching int count = 0; int pos = 0; while ( (pos = rx.search(str, pos)) != -1 ) { count++; pos += rx.matchedLength(); } // pos will be 9, 14, 18 and finally 24; count will end up as 4 \endcode Although const, this function sets matchedLength(), capturedTexts() and pos(). \sa searchRev() exactMatch() */ int QRegExp::search( const QString& str, int offset, CaretMode caretMode ) const { if ( offset < 0 ) offset += str.length(); #ifndef QT_NO_REGEXP_CAPTURE priv->t = str; priv->capturedCache.clear(); #endif priv->captured = eng->match( str, offset, priv->min, FALSE, caretIndex(offset, caretMode) ); return priv->captured[0]; } -/*! - \overload - - This convenience function searches with a \c CaretMode of \c - CaretAtZero which is the most common usage. -*/ - int QRegExp::searchRev( const QString& str, int offset ) const { return searchRev( str, offset, CaretAtZero ); } /*! Attempts to find a match backwards in \a str from position \a offset. If \a offset is -1 (the default), the search starts at the last character; if -2, at the next to last character; etc. Returns the position of the first match, or -1 if there was no match. The \a caretMode parameter can be used to instruct whether <b>^</b> should match at index 0 or at \a offset. Although const, this function sets matchedLength(), capturedTexts() and pos(). \warning Searching backwards is much slower than searching forwards. \sa search() exactMatch() */ int QRegExp::searchRev( const QString& str, int offset, CaretMode caretMode ) const { if ( offset < 0 ) offset += str.length(); #ifndef QT_NO_REGEXP_CAPTURE priv->t = str; priv->capturedCache.clear(); #endif if ( offset < 0 || offset > (int) str.length() ) { priv->captured.detach(); priv->captured.fill( -1 ); return -1; } while ( offset >= 0 ) { priv->captured = eng->match( str, offset, priv->min, TRUE, caretIndex(offset, caretMode) ); if ( priv->captured[0] == offset ) return offset; offset--; } return -1; } /*! Returns the length of the last matched string, or -1 if there was no match. \sa exactMatch() search() searchRev() */ int QRegExp::matchedLength() const { return priv->captured[1]; } #ifndef QT_NO_REGEXP_CAPTURE -/*! +/*! Returns the number of captures contained in the regular expression. */ int QRegExp::numCaptures() const { return eng->numCaptures(); } /*! Returns a list of the captured text strings. The first string in the list is the entire matched string. Each subsequent list element contains a string that matched a (capturing) subexpression of the regexp. For example: \code QRegExp rx( "(\\d+)(\\s*)(cm|inch(es)?)" ); int pos = rx.search( "Length: 36 inches" ); QStringList list = rx.capturedTexts(); // list is now ( "36 inches", "36", " ", "inches", "es" ) \endcode The above example also captures elements that may be present but which we have no interest in. This problem can be solved by using non-capturing parentheses: \code QRegExp rx( "(\\d+)(?:\\s*)(cm|inch(?:es)?)" ); int pos = rx.search( "Length: 36 inches" ); QStringList list = rx.capturedTexts(); // list is now ( "36 inches", "36", "inches" ) \endcode Note that if you want to iterate over the list, you should iterate over a copy, e.g. \code QStringList list = rx.capturedTexts(); QStringList::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode Some regexps can match an indeterminate number of times. For example if the input string is "Offsets: 12 14 99 231 7" and the regexp, \c{rx}, is <b>(\\d+)+</b>, we would hope to get a list of all the numbers matched. However, after calling \c{rx.search(str)}, capturedTexts() will return the list ( "12", "12" ), i.e. the entire match was "12" and the first subexpression matched was "12". The correct approach is to use cap() in a \link #cap_in_a_loop loop \endlink. The order of elements in the string list is as follows. The first element is the entire matching string. Each subsequent element corresponds to the next capturing open left parentheses. Thus capturedTexts()[1] is the text of the first capturing parentheses, capturedTexts()[2] is the text of the second and so on (corresponding to $1, $2, etc., in some other regexp languages). \sa cap() pos() exactMatch() search() searchRev() */ diff --git a/qmake/tools/qsemaphore_unix.cpp b/qmake/tools/qsemaphore_unix.cpp index fcf28da..4516049 100644 --- a/qmake/tools/qsemaphore_unix.cpp +++ b/qmake/tools/qsemaphore_unix.cpp @@ -122,166 +122,164 @@ QSemaphore::~QSemaphore() delete d; } /*! Postfix ++ operator. Try to get access to the semaphore. If \l available() == 0, this call will block until it can get access, i.e. until available() \> 0. */ int QSemaphore::operator++(int) { int ret; d->mutex.lock(); while (d->value >= d->max) d->cond.wait(&(d->mutex)); ++(d->value); if (d->value > d->max) d->value = d->max; ret = d->value; d->mutex.unlock(); return ret; } /*! Postfix -- operator. Release access of the semaphore. This wakes all threads waiting for access to the semaphore. */ int QSemaphore::operator--(int) { int ret; d->mutex.lock(); --(d->value); if (d->value < 0) d->value = 0; ret = d->value; d->cond.wakeAll(); d->mutex.unlock(); return ret; } /*! Try to get access to the semaphore. If \l available() \< \a n, this call will block until it can get all the accesses it wants, i.e. until available() \>= \a n. */ int QSemaphore::operator+=(int n) { int ret; d->mutex.lock(); + if ( n < 0 || n > d->max ) { +#ifdef QT_CHECK_RANGE + qWarning( "QSemaphore::operator+=: paramter %d out of range", n ); +#endif // QT_CHECK_RANGE + n = n < 0 ? 0 : d->max; + } + while (d->value + n > d->max) d->cond.wait(&(d->mutex)); d->value += n; - -#ifdef QT_CHECK_RANGE - if (d->value > d->max) { - qWarning("QSemaphore::operator+=: attempt to allocate more resources than available"); - d->value = d->max; - } -#endif - ret = d->value; d->mutex.unlock(); return ret; } /*! Release \a n accesses to the semaphore. */ int QSemaphore::operator-=(int n) { int ret; d->mutex.lock(); - d->value -= n; - + if ( n < 0 || n > d->value ) { #ifdef QT_CHECK_RANGE - if (d->value < 0) { - qWarning("QSemaphore::operator-=: attempt to deallocate more resources than taken"); - d->value = 0; + qWarning( "QSemaphore::operator-=: paramter %d out of range", n ); +#endif // QT_CHECK_RANGE + n = n < 0 ? 0 : d->value; } -#endif + d->value -= n; ret = d->value; d->cond.wakeOne(); d->mutex.unlock(); return ret; } /*! Returns the number of accesses currently available to the semaphore. */ int QSemaphore::available() const { int ret; d->mutex.lock(); ret = d->max - d->value; d->mutex.unlock(); return ret; } /*! Returns the total number of accesses to the semaphore. */ int QSemaphore::total() const { int ret; d->mutex.lock(); ret = d->max; d->mutex.unlock(); return ret; } /*! Try to get access to the semaphore. If \l available() \< \a n, this function will return FALSE immediately. If \l available() \>= \a n, this function will take \a n accesses and return TRUE. This function does \e not block. */ bool QSemaphore::tryAccess(int n) { if (! d->mutex.tryLock()) return FALSE; if (d->value + n > d->max) { d->mutex.unlock(); return FALSE; } d->value += n; #ifdef QT_CHECK_RANGE if (d->value > d->max) { qWarning("QSemaphore::operator+=: attempt to allocate more resources than available"); d->value = d->max; } #endif d->mutex.unlock(); diff --git a/qmake/tools/qsettings.cpp b/qmake/tools/qsettings.cpp index 5de105c..35fc039 100644 --- a/qmake/tools/qsettings.cpp +++ b/qmake/tools/qsettings.cpp @@ -1,219 +1,248 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QSettings class ** -** Created: 2000.06.26 +** Created : 000626 ** ** Copyright (C) 2000-2002 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. ** **********************************************************************/ #include "qplatformdefs.h" // POSIX Large File Support redefines open -> open64 static inline int qt_open( const char *pathname, int flags, mode_t mode ) { return ::open( pathname, flags, mode ); } #if defined(open) # undef open #endif // POSIX Large File Support redefines truncate -> truncate64 #if defined(truncate) # undef truncate #endif #include "qsettings.h" #ifndef QT_NO_SETTINGS #include "qdir.h" #include "qfile.h" #include "qfileinfo.h" #include "qmap.h" #include "qtextstream.h" #include "qregexp.h" #include <private/qsettings_p.h> #include <errno.h> /*! - \class QSettings - \brief The QSettings class provides persistent platform-independent application settings. - - \ingroup io - \ingroup misc - \mainclass - - On Unix systems, QSettings uses text files to store settings. On Windows - systems, QSettings uses the system registry. On Mac OS X, QSettings will - behave as on Unix, and store to text files. - - Each setting comprises an identifying key and the data associated with - the key. A key is a unicode string which consists of \e two or more - subkeys. A subkey is a slash, '/', followed by one or more unicode - characters (excluding slashes, newlines, carriage returns and equals, - '=', signs). The associated data, called the entry or value, may be a - boolean, an integer, a double, a string or a list of strings. Entry - strings may contain any unicode characters. - - If you want to save and restore the entire desktop's settings, i.e. - which applications are running, use QSettings to save the settings - for each individual application and QSessionManager to save the - desktop's session. + \class QSettings + \brief The QSettings class provides persistent platform-independent application settings. + + \ingroup io + \ingroup misc + \mainclass + + On Unix systems, QSettings uses text files to store settings. On Windows + systems, QSettings uses the system registry. On Mac OS X, QSettings uses + the Carbon preferences API. + + Each setting comprises an identifying key and the data associated with + the key. A key is a unicode string which consists of \e two or more + subkeys. A subkey is a slash, '/', followed by one or more unicode + characters (excluding slashes, newlines, carriage returns and equals, + '=', signs). The associated data, called the entry or value, may be a + boolean, an integer, a double, a string or a list of strings. Entry + strings may contain any unicode characters. + + If you want to save and restore the entire desktop's settings, i.e. + which applications are running, use QSettings to save the settings + for each individual application and QSessionManager to save the + desktop's session. Example settings: \code /MyCompany/MyApplication/background color /MyCompany/MyApplication/foreground color /MyCompany/MyApplication/geometry/x /MyCompany/MyApplication/geometry/y /MyCompany/MyApplication/geometry/width /MyCompany/MyApplication/geometry/height /MyCompany/MyApplication/recent files/1 /MyCompany/MyApplication/recent files/2 /MyCompany/MyApplication/recent files/3 \endcode Each line above is a complete key, made up of subkeys. - A typical usage pattern for application startup: + A typical usage pattern for reading application startup: \code QSettings settings; - settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); - // No search path needed for Unix; see notes further on. - // Use default values if the keys don't exist - QString bgColor = settings.readEntry( "/MyApplication/background color", "white" ); - int width = settings.readNumEntry( "/MyApplication/geometry/width", 640 ); + settings.setPath( "MyCompany.com", "MyApplication" ); + + QString bgColor = settings.readEntry( "/colors/background", "white" ); + int width = settings.readNumEntry( "/geometry/width", 640 ); // ... \endcode A typical usage pattern for application exit or 'save preferences': \code QSettings settings; - settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); - // No search path needed for Unix; see notes further on. - settings.writeEntry( "/MyApplication/background color", bgColor ); - settings.writeEntry( "/MyApplication/geometry/width", width ); + settings.setPath( "MyCompany.com", "MyApplication" ); + + settings.writeEntry( "/colors/background", bgColor ); + settings.writeEntry( "/geometry/width", width ); // ... \endcode + QSettings can build a key prefix that is prepended to all keys. To + build the key prefix, use beginGroup() and endGroup(). + \code + QSettings settings; + + settings.beginGroup( "/MainWindow" ); + settings.beginGroup( "/Geometry" ); + int x = settings.readEntry( "/x" ); + // ... + settings.endGroup(); + settings.beginGroup( "/Toolbars" ); + // ... + settings.endGroup(); + settings.endGroup(); + \endcode + You can get a list of entry-holding keys by calling entryList(), and a list of key-holding keys using subkeyList(). \code QStringList keys = entryList( "/MyApplication" ); // keys contains 'background color' and 'foreground color'. QStringList keys = entryList( "/MyApplication/recent files" ); // keys contains '1', '2' and '3'. QStringList subkeys = subkeyList( "/MyApplication" ); // subkeys contains 'geometry' and 'recent files' QStringList subkeys = subkeyList( "/MyApplication/recent files" ); // subkeys is empty. \endcode - If you wish to use a different search path call insertSearchPath() - as often as necessary to add your preferred paths. Call - removeSearchPath() to remove any unwanted paths. - Since settings for Windows are stored in the registry there are size limits as follows: \list \i A subkey may not exceed 255 characters. \i An entry's value may not exceed 16,300 characters. \i All the values of a key (for example, all the 'recent files' subkeys values), may not exceed 65,535 characters. \endlist - These limitations are not enforced on Unix. + These limitations are not enforced on Unix or Mac OS X. + + If you wish to use a different search path call insertSearchPath() + as often as necessary to add your preferred paths. Call + removeSearchPath() to remove any unwanted paths. + + \section1 Notes for Mac OS X Applications + + Internal to the CFPreferences API it is not defined (for Mac OS 9 + support) where the settings will ultimitely be stored. However, at the + time of this writing the settings will be stored (either on a global or + user basis, preferring locally) into a plist file in + $ROOT/System/Library/Preferences (in XML format). QSettings will create + an appropriate plist file (com.<first group name>.plist) out of the + full path to a key. + + For further information on CFPreferences see also + \link http://developer.apple.com/techpubs/macosx/CoreFoundation/PreferenceServices/preferenceservices_carbon.html + Apple's Specifications\endlink \section1 Notes for Unix Applications There is no universally accepted place for storing application settings under Unix. In the examples the settings file will be searched for in the following directories: \list 1 \i INSTALL/etc/settings \i /opt/MyCompany/share/etc \i /opt/MyCompany/share/MyApplication/etc \i $HOME/.qt \endlist When reading settings the files are searched in the order shown above, with later settings overriding earlier settings. Files for which the user doesn't have read permission are ignored. When saving settings QSettings works in the order shown above, writing to the first settings file for which the user has write permission. (\c INSTALL is the directory where Qt was installed. This can be modified by using the configure script's -prefix argument ) If you want to put the settings in a particular place in the filesystem you could do this: \code settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share" ); \endcode But in practice you may prefer not to use a search path for Unix. For example the following code: \code settings.writeEntry( "/MyApplication/geometry/width", width ); \endcode will end up writing the "geometry/width" setting to the file \c{$HOME/.qt/myapplicationrc} (assuming that the application is being run by an ordinary user, i.e. not by root). For cross-platform applications you should ensure that the Windows size limitations are not exceeded. */ /*! \enum QSettings::System \value Mac Macintosh execution environments \value Unix Mac OS X, Unix, Linux and Unix-like execution environments \value Windows Windows execution environments */ /*! \enum QSettings::Format \value Native Store the settings in a platform dependent location \value Ini Store the settings in a text file */ /*! \enum QSettings::Scope \value Global Save settings as global as possible \value User Save settings in user space */ #if defined(Q_OS_UNIX) typedef int HANDLE; #define Q_LOCKREAD F_RDLCK @@ -239,142 +268,142 @@ static HANDLE openlock( const QString &name, int type ) HANDLE fd = qt_open( QFile::encodeName( lockfile ), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ); if ( fd < 0 ) { // failed to open the lock file, most likely because of permissions return fd; } struct flock fl; fl.l_type = type; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; if ( fcntl( fd, F_SETLKW, &fl ) == -1 ) { // the lock failed, so we should fail silently, so that people // using filesystems that do not support locking don't see // numerous warnings about a failed lock close( fd ); fd = -1; } return fd; } /* Closes the lock file specified by fd. fd is the file descriptor returned by the openlock() function. */ static void closelock( HANDLE fd ) { if ( fd < 0 ) { // the lock file is not open return; } struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; // ignore the return value, so that the unlock fails silently (void) fcntl( fd, F_SETLKW, &fl ); close( fd ); } #elif defined(Q_WS_WIN) #define Q_LOCKREAD 1 #define Q_LOCKWRITE 2 static HANDLE openlock( const QString &name, int /*type*/ ) { if ( !QFile::exists( name ) ) return 0; return 0; HANDLE fd = 0; QT_WA( { fd = CreateFileW( (TCHAR*)name.ucs2(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } , { fd = CreateFileA( name.local8Bit(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); } ); - if ( !LockFile( fd, 0, 0, -1, -1 ) ) { + if ( !LockFile( fd, 0, 0, (DWORD)-1, (DWORD)-1 ) ) { // ### (DWORD)-1 ??? #ifdef QT_CHECK_STATE qWarning( "QSettings: openlock failed!" ); #endif } return fd; } -void closelock( HANDLE fd ) +static void closelock( HANDLE fd ) { if ( !fd ) return; - if ( !UnlockFile( fd, 0, 0, -1, -1 ) ) { + if ( !UnlockFile( fd, 0, 0, (DWORD)-1, (DWORD)-1 ) ) { // ### (DWORD)-1 ??? #ifdef QT_CHECK_STATE qWarning( "QSettings: closelock failed!"); #endif } CloseHandle( fd ); } #endif QSettingsGroup::QSettingsGroup() : modified(FALSE) { } void QSettingsHeading::read(const QString &filename) { if (! QFileInfo(filename).exists()) return; HANDLE lockfd = openlock( filename, Q_LOCKREAD ); QFile file(filename); if (! file.open(IO_ReadOnly)) { #if defined(QT_CHECK_STATE) qWarning("QSettings: failed to open file '%s'", filename.latin1()); #endif return; } git = end(); QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); while (! stream.atEnd()) parseLine(stream); git = end(); file.close(); closelock( lockfd ); } void QSettingsHeading::parseLine(QTextStream &stream) { QString line = stream.readLine(); if (line.isEmpty()) // empty line... we'll allow it return; if (line[0] == QChar('#')) // commented line return; if (line[0] == QChar('[')) { QString gname = line; gname = gname.remove(0, 1); if (gname[(int)gname.length() - 1] == QChar(']')) gname = gname.remove(gname.length() - 1, 1); @@ -394,1562 +423,1638 @@ void QSettingsHeading::parseLine(QTextStream &stream) if (i == -1) { #if defined(QT_CHECK_STATE) qWarning("QSettings: malformed line '%s' in group '%s'", line.latin1(), git.key().latin1()); #endif return; } else { QString key, value; key = line.left(i); value = ""; bool esc=TRUE; i++; while (esc) { esc = FALSE; for ( ; i < (int)line.length(); i++ ) { if ( esc ) { if ( line[i] == 'n' ) value.append('\n'); // escaped newline else if ( line[i] == '0' ) value = QString::null; // escaped empty string else value.append(line[i]); esc = FALSE; } else if ( line[i] == '\\' ) esc = TRUE; else value.append(line[i]); } if ( esc ) { // Backwards-compatiblity... // still escaped at EOL - manually escaped "newline" if (stream.atEnd()) { #if defined(QT_CHECK_STATE) qWarning("QSettings: reached end of file, expected continued line"); #endif break; } value.append('\n'); line = stream.readLine(); i = 0; } } (*git).insert(key, value); } } } #ifdef Q_WS_WIN // for homedirpath reading from registry #include "qt_windows.h" #include "qlibrary.h" #ifndef CSIDL_APPDATA #define CSIDL_APPDATA 0x001a // <user name>\Application Data #endif #ifndef CSIDL_COMMON_APPDATA #define CSIDL_COMMON_APPDATA 0x0023 // All Users\Application Data #endif #endif QSettingsPrivate::QSettingsPrivate( QSettings::Format format ) : groupDirty( TRUE ), modified(FALSE), globalScope(TRUE) { -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( format != QSettings::Ini ) return; +#else + Q_UNUSED( format ); #endif QString appSettings(QDir::homeDirPath() + "/.qt/"); QString defPath; #ifdef Q_WS_WIN #ifdef Q_OS_TEMP TCHAR path[MAX_PATH]; SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); appSettings = QString::fromUcs2( path ); SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); defPath = QString::fromUcs2( path ); #else QLibrary library( "shell32" ); library.setAutoUnload( FALSE ); QT_WA( { typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPTSTR, int, BOOL); GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathW" ); if ( SHGetSpecialFolderPath ) { TCHAR path[MAX_PATH]; SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); appSettings = QString::fromUcs2( (ushort*)path ); SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); defPath = QString::fromUcs2( (ushort*)path ); } } , { typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, char*, int, BOOL); GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath)library.resolve( "SHGetSpecialFolderPathA" ); if ( SHGetSpecialFolderPath ) { char path[MAX_PATH]; SHGetSpecialFolderPath( 0, path, CSIDL_APPDATA, FALSE ); appSettings = QString::fromLocal8Bit( path ); SHGetSpecialFolderPath( 0, path, CSIDL_COMMON_APPDATA, FALSE ); defPath = QString::fromLocal8Bit( path ); } } ); #endif // Q_OS_TEMP #else // for now #define QSETTINGS_DEFAULT_PATH_SUFFIX "/etc/settings" defPath = qInstallPath(); defPath += QSETTINGS_DEFAULT_PATH_SUFFIX; #endif QDir dir(appSettings); if (! dir.exists()) { if (! dir.mkdir(dir.path())) #if defined(QT_CHECK_STATE) qWarning("QSettings: error creating %s", dir.path().latin1()); +#else + ; #endif } if ( !!defPath ) searchPaths.append(defPath); searchPaths.append(dir.path()); } QSettingsPrivate::~QSettingsPrivate() { } QSettingsGroup QSettingsPrivate::readGroup() { QSettingsHeading hd; QSettingsGroup grp; QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); if (headingsit != headings.end()) hd = *headingsit; QSettingsHeading::Iterator grpit = hd.find(group); if (grpit == hd.end()) { QStringList::Iterator it = searchPaths.begin(); + if ( !globalScope ) + ++it; while (it != searchPaths.end()) { QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); QString fn((*it++) + "/" + filebase + "rc"); if (! hd.contains(fn + "cached")) { hd.read(fn); hd.insert(fn + "cached", QSettingsGroup()); } } headings.replace(heading, hd); grpit = hd.find(group); if (grpit != hd.end()) grp = *grpit; } else if (hd.count() != 0) grp = *grpit; return grp; } void QSettingsPrivate::removeGroup(const QString &key) { QSettingsHeading hd; QSettingsGroup grp; bool found = FALSE; QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); if (headingsit != headings.end()) hd = *headingsit; QSettingsHeading::Iterator grpit = hd.find(group); if (grpit == hd.end()) { QStringList::Iterator it = searchPaths.begin(); + if ( !globalScope ) + ++it; while (it != searchPaths.end()) { QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); QString fn((*it++) + "/" + filebase + "rc"); if (! hd.contains(fn + "cached")) { hd.read(fn); hd.insert(fn + "cached", QSettingsGroup()); } } headings.replace(heading, hd); grpit = hd.find(group); if (grpit != hd.end()) { found = TRUE; grp = *grpit; } } else if (hd.count() != 0) { found = TRUE; grp = *grpit; } if (found) { grp.remove(key); if (grp.count() > 0) hd.replace(group, grp); else hd.remove(group); if (hd.count() > 0) headings.replace(heading, hd); else headings.remove(heading); modified = TRUE; } } void QSettingsPrivate::writeGroup(const QString &key, const QString &value) { QSettingsHeading hd; QSettingsGroup grp; QMap<QString,QSettingsHeading>::Iterator headingsit = headings.find(heading); if (headingsit != headings.end()) hd = *headingsit; QSettingsHeading::Iterator grpit = hd.find(group); if (grpit == hd.end()) { QStringList::Iterator it = searchPaths.begin(); + if ( !globalScope ) + ++it; while (it != searchPaths.end()) { QString filebase = heading.lower().replace(QRegExp("\\s+"), "_"); QString fn((*it++) + "/" + filebase + "rc"); if (! hd.contains(fn + "cached")) { hd.read(fn); hd.insert(fn + "cached", QSettingsGroup()); } } headings.replace(heading, hd); grpit = hd.find(group); if (grpit != hd.end()) grp = *grpit; } else if (hd.count() != 0) grp = *grpit; grp.modified = TRUE; grp.replace(key, value); hd.replace(group, grp); headings.replace(heading, hd); modified = TRUE; } QDateTime QSettingsPrivate::modificationTime() { QSettingsHeading hd = headings[heading]; QSettingsGroup grp = hd[group]; QDateTime datetime; QStringList::Iterator it = searchPaths.begin(); + if ( !globalScope ) + ++it; while (it != searchPaths.end()) { QFileInfo fi((*it++) + "/" + heading + "rc"); if (fi.exists() && fi.lastModified() > datetime) datetime = fi.lastModified(); } return datetime; } -static bool verifyKey( const QString &key ) +bool qt_verify_key( const QString &key ) { if ( key.isEmpty() || key[0] != '/' || key.contains( QRegExp("[=\\\\r\\\\n" ) ) ) return FALSE; return TRUE; } static inline QString groupKey( const QString &group, const QString &key ) { - if ( group.endsWith( "/" ) || key.startsWith( "/" ) ) + if ( group.isEmpty() || ( group.length() == 1 && group[0] == '/' ) ) { + // group is empty, or it contains a single '/', so we just return the key + if ( key.startsWith( "/" ) ) + return key; + return "/" + key; + } else if ( group.endsWith( "/" ) || key.startsWith( "/" ) ) { return group + key; + } return group + "/" + key; } /*! Inserts \a path into the settings search path. The semantics of \a path depends on the system \a s. When \a s is \e Windows and the execution environment is \e not Windows the function does nothing. Similarly when \a s is \e Unix and the execution environment is \e not Unix the function does nothing. When \a s is \e Windows, and the execution environment is Windows, the search path list will be used as the first subfolder of the "Software" folder in the registry. When reading settings the folders are searched forwards from the first folder (listed below) to the last, returning the first - settings found, and ignoring any folders for which the user doesn't + settings found, and ignoring any folders for which the user doesn't have read permission. \list 1 \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication \i HKEY_CURRENT_USER/Software/MyApplication \i HKEY_LOCAL_MACHINE/Software/MyApplication \endlist \code QSettings settings; settings.insertSearchPath( QSettings::Windows, "/MyCompany" ); settings.writeEntry( "/MyApplication/Tip of the day", TRUE ); \endcode The code above will write the subkey "Tip of the day" into the \e first of the registry folders listed below that is found and for which the user has write permission. \list 1 \i HKEY_LOCAL_MACHINE/Software/MyCompany/MyApplication \i HKEY_CURRENT_USER/Software/MyCompany/MyApplication \i HKEY_LOCAL_MACHINE/Software/MyApplication \i HKEY_CURRENT_USER/Software/MyApplication \endlist If a setting is found in the HKEY_CURRENT_USER space, this setting - is overwritten independently of write permissions in the + is overwritten independently of write permissions in the HKEY_LOCAL_MACHINE space. When \a s is \e Unix, and the execution environment is Unix, the search path list will be used when trying to determine a suitable filename for reading and writing settings files. By default, there are two entries in the search path: \list 1 \i INSTALL/etc - where \c INSTALL is the directory where Qt was installed. \i $HOME/.qt/ - where \c $HOME is the user's home directory. \endlist All insertions into the search path will go before $HOME/.qt/. For example: \code QSettings settings; settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/etc" ); settings.insertSearchPath( QSettings::Unix, "/opt/MyCompany/share/MyApplication/etc" ); // ... \endcode Will result in a search path of: \list 1 \i INSTALL/etc \i /opt/MyCompany/share/etc \i /opt/MyCompany/share/MyApplication/etc \i $HOME/.qt \endlist When reading settings the files are searched in the order shown above, with later settings overriding earlier settings. Files for which the user doesn't have read permission are ignored. When saving settings QSettings works in the order shown above, writing to the first settings file for which the user has write permission. Settings under Unix are stored in files whose names are based on the first subkey of the key (not including the search path). The algorithm for creating names is essentially: lowercase the first subkey, replace spaces with underscores and add 'rc', e.g. <tt>/MyCompany/MyApplication/background color</tt> will be stored in <tt>myapplicationrc</tt> (assuming that <tt>/MyCompany</tt> is part of the search path). \sa removeSearchPath() */ void QSettings::insertSearchPath( System s, const QString &path) { -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) { d->sysInsertSearchPath( s, path ); return; } #endif - if ( !verifyKey( path ) ) { +#if !defined(Q_WS_WIN) + if ( s == Windows ) + return; +#endif +#if !defined(Q_WS_WIN) + if ( s == Mac ) + return; +#endif + + if ( !qt_verify_key( path ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() ); #endif return; } -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd && s != Unix ) { #else if ( s != Unix ) { #endif -#ifdef Q_OS_MAC +#if !defined(QWS) && defined(Q_OS_MAC) if(s != Mac) //mac is respected on the mac as well #endif return; } + QString realPath = path; +#if defined(Q_WS_WIN) + QString defPath = d->globalScope ? d->searchPaths.first() : d->searchPaths.last(); + realPath = defPath + path; +#endif + QStringList::Iterator it = d->searchPaths.find(d->searchPaths.last()); if (it != d->searchPaths.end()) { - d->searchPaths.insert(it, path); + d->searchPaths.insert(it, realPath); } } /*! Removes all occurrences of \a path (using exact matching) from the settings search path for system \a s. Note that the default search paths cannot be removed. \sa insertSearchPath() */ void QSettings::removeSearchPath( System s, const QString &path) { - if ( !verifyKey( path ) ) { + if ( !qt_verify_key( path ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::insertSearchPath: Invalid key: '%s'", path.isNull() ? "(null)" : path.latin1() ); #endif return; } #ifdef Q_WS_WIN if ( d->sysd ) { d->sysRemoveSearchPath( s, path ); return; } #endif -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd && s != Unix ) { #else if ( s != Unix ) { #endif -#ifdef Q_OS_MAC +#if !defined(QWS) && defined(Q_OS_MAC) if(s != Mac) //mac is respected on the mac as well #endif return; } if (path == d->searchPaths.first() || path == d->searchPaths.last()) return; d->searchPaths.remove(path); } /*! Creates a settings object. */ QSettings::QSettings() { d = new QSettingsPrivate( Native ); Q_CHECK_PTR(d); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) d->sysd = 0; d->sysInit(); #endif } /*! Creates a settings object. If \a format is 'Ini' the settings will be stored in a text file, using the Unix strategy (see above). If \a format is 'Native', the settings will be stored in a platform specific way (ie. the Windows registry). */ QSettings::QSettings( Format format ) { d = new QSettingsPrivate( format ); Q_CHECK_PTR(d); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) d->sysd = 0; if ( format == Native ) d->sysInit(); #else Q_UNUSED(format); #endif } /*! Destroys the settings object. All modifications made to the settings will automatically be saved. */ QSettings::~QSettings() { sync(); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) d->sysClear(); #endif delete d; } /*! \internal Writes all modifications to the settings to disk. If any errors are encountered, this function returns FALSE, otherwise it will return TRUE. */ bool QSettings::sync() { -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysSync(); #endif if (! d->modified) // fake success return TRUE; bool success = TRUE; QMap<QString,QSettingsHeading>::Iterator it = d->headings.begin(); while (it != d->headings.end()) { // determine filename QSettingsHeading hd(*it); QSettingsHeading::Iterator hdit = hd.begin(); QFile file; QStringList::Iterator pit = d->searchPaths.begin(); + if ( !d->globalScope ) + ++pit; while (pit != d->searchPaths.end()) { QString filebase = it.key().lower().replace(QRegExp("\\s+"), "_"); QFileInfo di(*pit); QFileInfo fi((*pit++) + "/" + filebase + "rc"); if ((fi.exists() && fi.isFile() && fi.isWritable()) || (! fi.exists() && di.isDir() && di.isWritable())) { file.setName(fi.filePath()); break; } } - it++; + ++it; - if (file.name().isNull() || file.name().isEmpty()) { + if ( file.name().isEmpty() ) { #ifdef QT_CHECK_STATE qWarning("QSettings::sync: filename is null/empty"); #endif // QT_CHECK_STATE success = FALSE; continue; } HANDLE lockfd = openlock( file.name(), Q_LOCKWRITE ); if (! file.open(IO_WriteOnly)) { #ifdef QT_CHECK_STATE qWarning("QSettings::sync: failed to open '%s' for writing", file.name().latin1()); #endif // QT_CHECK_STATE success = FALSE; continue; } // spew to file QTextStream stream(&file); stream.setEncoding(QTextStream::UnicodeUTF8); while (hdit != hd.end()) { if ((*hdit).count() > 0) { stream << "[" << hdit.key() << "]" << endl; QSettingsGroup grp(*hdit); QSettingsGroup::Iterator grpit = grp.begin(); while (grpit != grp.end()) { QString v = grpit.data(); if ( v.isNull() ) { v = "\\0"; // escape null string } else { v.replace("\\", "\\\\"); // escape backslash v.replace("\n", "\\n"); // escape newlines } stream << grpit.key() << "=" << v << endl; - grpit++; + ++grpit; } stream << endl; } - hdit++; + ++hdit; } if (file.status() != IO_Ok) { #ifdef QT_CHECK_STATE qWarning("QSettings::sync: error at end of write"); #endif // QT_CHECK_STATE success = FALSE; } file.close(); closelock( lockfd ); } d->modified = FALSE; return success; } /*! \fn bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok ) const Reads the entry specified by \a key, and returns a bool, or the default value, \a def, if the entry couldn't be read. If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE otherwise. \sa readEntry(), readNumEntry(), readDoubleEntry(), writeEntry(), removeEntry() */ /*! \internal */ bool QSettings::readBoolEntry(const QString &key, bool def, bool *ok ) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::readBoolEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif if ( ok ) *ok = FALSE; return def; } - QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysReadBoolEntry( theKey, def, ok ); + return d->sysReadBoolEntry( groupKey( group(), key ), def, ok ); #endif - QString value = readEntry( theKey, ( def ? "true" : "false" ), ok ); + QString value = readEntry( key, ( def ? "true" : "false" ), ok ); if (value.lower() == "true") return TRUE; else if (value.lower() == "false") return FALSE; else if (value == "1") return TRUE; else if (value == "0") return FALSE; if (! value.isEmpty()) qWarning("QSettings::readBoolEntry: '%s' is not 'true' or 'false'", value.latin1()); if ( ok ) *ok = FALSE; return def; } /*! \fn double QSettings::readDoubleEntry(const QString &key, double def, bool *ok ) const Reads the entry specified by \a key, and returns a double, or the default value, \a def, if the entry couldn't be read. If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE otherwise. \sa readEntry(), readNumEntry(), readBoolEntry(), writeEntry(), removeEntry() */ /*! \internal */ double QSettings::readDoubleEntry(const QString &key, double def, bool *ok ) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::readDoubleEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif if ( ok ) *ok = FALSE; return def; } - QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysReadDoubleEntry( theKey, def, ok ); + return d->sysReadDoubleEntry( groupKey( group(), key ), def, ok ); #endif - QString value = readEntry( theKey, QString::number(def), ok ); + QString value = readEntry( key, QString::number(def), ok ); bool conv_ok; double retval = value.toDouble( &conv_ok ); if ( conv_ok ) return retval; if ( ! value.isEmpty() ) qWarning( "QSettings::readDoubleEntry: '%s' is not a number", value.latin1() ); if ( ok ) *ok = FALSE; return def; } /*! \fn int QSettings::readNumEntry(const QString &key, int def, bool *ok ) const Reads the entry specified by \a key, and returns an integer, or the default value, \a def, if the entry couldn't be read. If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE otherwise. \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry() */ /*! \internal */ int QSettings::readNumEntry(const QString &key, int def, bool *ok ) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::readNumEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif if ( ok ) *ok = FALSE; return def; } - QString theKey = groupKey( group(), key ); - -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysReadNumEntry( theKey, def, ok ); + return d->sysReadNumEntry( groupKey( group(), key ), def, ok ); #endif - QString value = readEntry( theKey, QString::number( def ), ok ); + QString value = readEntry( key, QString::number( def ), ok ); bool conv_ok; int retval = value.toInt( &conv_ok ); if ( conv_ok ) return retval; if ( ! value.isEmpty() ) qWarning( "QSettings::readNumEntry: '%s' is not a number", value.latin1() ); if ( ok ) *ok = FALSE; return def; } /*! \fn QString QSettings::readEntry(const QString &key, const QString &def, bool *ok ) const Reads the entry specified by \a key, and returns a QString, or the default value, \a def, if the entry couldn't be read. If \a ok is non-null, *ok is set to TRUE if the key was read, FALSE otherwise. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry() */ /*! \internal */ QString QSettings::readEntry(const QString &key, const QString &def, bool *ok ) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::readEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif if ( ok ) *ok = FALSE; return def; } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysReadEntry( theKey, def, ok ); #endif if ( ok ) // no, everything is not ok *ok = FALSE; QString realkey; if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 2) { #ifdef QT_CHECK_STATE qWarning("QSettings::readEntry: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE if ( ok ) *ok = FALSE; return def; } if (list.count() == 2) { d->heading = list[0]; d->group = "General"; realkey = list[1]; } else { d->heading = list[0]; d->group = list[1]; // remove the group from the list list.remove(list.at(1)); // remove the heading from the list list.remove(list.at(0)); realkey = list.join("/"); } } else realkey = theKey; QSettingsGroup grp = d->readGroup(); - QString retval = grp[realkey]; - if ( retval.isNull() ) - retval = def; - else if ( ok ) // everything is ok - *ok = TRUE; + QSettingsGroup::const_iterator it = grp.find( realkey ), end = grp.end(); + QString retval = def; + if ( it != end ) { + // found the value we needed + retval = *it; + if ( ok ) *ok = TRUE; + } return retval; } #if !defined(Q_NO_BOOL_TYPE) /*! Writes the boolean entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. If an error occurs the settings are left unchanged and FALSE is returned; otherwise TRUE is returned. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, bool value) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } - QString theKey = groupKey( group(), key ); - -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysWriteEntry( theKey, value ); + return d->sysWriteEntry( groupKey( group(), key ), value ); #endif QString s(value ? "true" : "false"); - return writeEntry(theKey, s); + return writeEntry(key, s); } #endif /*! \overload Writes the double entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. If an error occurs the settings are left unchanged and FALSE is returned; otherwise TRUE is returned. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, double value) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } - QString theKey = groupKey( group(), key ); - -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysWriteEntry( theKey, value ); + return d->sysWriteEntry( groupKey( group(), key ), value ); #endif QString s(QString::number(value)); - return writeEntry(theKey, s); + return writeEntry(key, s); } /*! \overload Writes the integer entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. If an error occurs the settings are left unchanged and FALSE is returned; otherwise TRUE is returned. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, int value) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } - QString theKey = groupKey( group(), key ); - -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) - return d->sysWriteEntry( theKey, value ); + return d->sysWriteEntry( groupKey( group(), key ), value ); #endif QString s(QString::number(value)); - return writeEntry(theKey, s); + return writeEntry(key, s); } /*! \internal Writes the entry specified by \a key with the string-literal \a value, replacing any previous setting. If \a value is zero-length or null, the entry is replaced by an empty setting. \e NOTE: This function is provided because some compilers use the writeEntry (const QString &, bool) overload for this code: writeEntry ("/foo/bar", "baz") If an error occurs, this functions returns FALSE and the object is left unchanged. \sa readEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, const char *value) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } - QString theKey = groupKey( group(), key ); - - return writeEntry(theKey, QString(value)); + return writeEntry(key, QString(value)); } /*! \overload Writes the string entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. If \a value is an empty string or a null string the key's value will be an empty string. If an error occurs the settings are left unchanged and FALSE is returned; otherwise TRUE is returned. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, const QString &value) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::writeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysWriteEntry( theKey, value ); #endif // NOTE: we *do* allow value to be a null/empty string QString realkey; if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 2) { #ifdef QT_CHECK_STATE qWarning("QSettings::writeEntry: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE return FALSE; } if (list.count() == 2) { d->heading = list[0]; d->group = "General"; realkey = list[1]; } else { d->heading = list[0]; d->group = list[1]; // remove the group from the list list.remove(list.at(1)); // remove the heading from the list list.remove(list.at(0)); realkey = list.join("/"); } } else realkey = theKey; d->writeGroup(realkey, value); return TRUE; } /*! Removes the entry specified by \a key. Returns TRUE if the entry existed and was removed; otherwise returns FALSE. \sa readEntry(), writeEntry() */ bool QSettings::removeEntry(const QString &key) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::removeEntry: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return FALSE; } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysRemoveEntry( theKey ); #endif QString realkey; if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 2) { #ifdef QT_CHECK_STATE qWarning("QSettings::removeEntry: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE return FALSE; } if (list.count() == 2) { d->heading = list[0]; d->group = "General"; realkey = list[1]; } else { d->heading = list[0]; d->group = list[1]; // remove the group from the list list.remove(list.at(1)); // remove the heading from the list list.remove(list.at(0)); realkey = list.join("/"); } } else realkey = theKey; d->removeGroup(realkey); return TRUE; } /*! Returns a list of the keys which contain entries under \a key. Does \e not return any keys that contain keys. Example settings: \code /MyCompany/MyApplication/background color /MyCompany/MyApplication/foreground color /MyCompany/MyApplication/geometry/x /MyCompany/MyApplication/geometry/y /MyCompany/MyApplication/geometry/width /MyCompany/MyApplication/geometry/height \endcode \code QStringList keys = entryList( "/MyCompany/MyApplication" ); \endcode \c keys contains 'background color' and 'foreground color'. It does not contain 'geometry' because this key contains keys not entries. To access the geometry values could either use subkeyList() to read the keys and then read each entry, or simply read each entry directly by specifying its full key, e.g. "/MyCompany/MyApplication/geometry/y". \sa subkeyList() */ QStringList QSettings::entryList(const QString &key) const { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::entryList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() ); #endif return QStringList(); } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysEntryList( theKey ); #endif QString realkey; if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 1) { #ifdef QT_CHECK_STATE qWarning("QSettings::listEntries: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE return QStringList(); } if (list.count() == 1) { d->heading = list[0]; d->group = "General"; } else { d->heading = list[0]; d->group = list[1]; // remove the group from the list list.remove(list.at(1)); // remove the heading from the list list.remove(list.at(0)); realkey = list.join("/"); } } else realkey = theKey; QSettingsGroup grp = d->readGroup(); QSettingsGroup::Iterator it = grp.begin(); QStringList ret; QString itkey; while (it != grp.end()) { itkey = it.key(); - it++; + ++it; if ( realkey.length() > 0 ) { if ( itkey.left( realkey.length() ) != realkey ) continue; else itkey.remove( 0, realkey.length() + 1 ); } if ( itkey.find( '/' ) != -1 ) continue; ret << itkey; } return ret; } /*! Returns a list of the keys which contain keys under \a key. Does \e not return any keys that contain entries. Example settings: \code /MyCompany/MyApplication/background color /MyCompany/MyApplication/foreground color /MyCompany/MyApplication/geometry/x /MyCompany/MyApplication/geometry/y /MyCompany/MyApplication/geometry/width /MyCompany/MyApplication/geometry/height /MyCompany/MyApplication/recent files/1 /MyCompany/MyApplication/recent files/2 /MyCompany/MyApplication/recent files/3 \endcode \code QStringList keys = subkeyList( "/MyCompany/MyApplication" ); \endcode \c keys contains 'geometry' and 'recent files'. It does not contain 'background color' or 'foreground color' because they are keys which contain entries not keys. To get a list of keys that have values rather than subkeys use entryList(). \sa entryList() */ QStringList QSettings::subkeyList(const QString &key) const { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::subkeyList: Invalid key: %s", key.isNull() ? "(null)" : key.latin1() ); #endif return QStringList(); } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return d->sysSubkeyList( theKey ); #endif QString realkey; + int subkeycount = 2; if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 1) { #ifdef QT_CHECK_STATE qWarning("QSettings::subkeyList: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE return QStringList(); } + subkeycount = list.count(); + if (list.count() == 1) { d->heading = list[0]; d->group = "General"; } else { d->heading = list[0]; d->group = list[1]; // remove the group from the list list.remove(list.at(1)); // remove the heading from the list list.remove(list.at(0)); realkey = list.join("/"); } + } else realkey = theKey; + QStringList ret; + if ( subkeycount == 1 ) { + QMap<QString,QSettingsHeading>::Iterator it = d->headings.begin(); + while ( it != d->headings.end() ) { + if ( it.key() != "General" && ! ret.contains( it.key() ) ) + ret << it.key(); + ++it; + } + + return ret; + } + QSettingsGroup grp = d->readGroup(); QSettingsGroup::Iterator it = grp.begin(); - QStringList ret; QString itkey; while (it != grp.end()) { itkey = it.key(); - it++; + ++it; if ( realkey.length() > 0 ) { if ( itkey.left( realkey.length() ) != realkey ) continue; else itkey.remove( 0, realkey.length() + 1 ); } int slash = itkey.find( '/' ); if ( slash == -1 ) continue; itkey.truncate( slash ); if ( ! ret.contains( itkey ) ) ret << itkey; } return ret; } /*! \internal This function returns the time of last modification for \a key. */ QDateTime QSettings::lastModficationTime(const QString &key) { - if ( !verifyKey( key ) ) { + if ( !qt_verify_key( key ) ) { #if defined(QT_CHECK_STATE) qWarning( "QSettings::lastModficationTime: Invalid key: '%s'", key.isNull() ? "(null)" : key.latin1() ); #endif return QDateTime(); } QString theKey = groupKey( group(), key ); -#if defined(Q_WS_WIN) || defined(Q_OS_MAC) +#if !defined(QWS) && (defined(Q_WS_WIN) || defined(Q_OS_MAC)) if ( d->sysd ) return QDateTime(); #endif if (theKey[0] == '/') { // parse our key QStringList list(QStringList::split('/', theKey)); if (list.count() < 2) { #ifdef QT_CHECK_STATE qWarning("QSettings::lastModficationTime: invalid key '%s'", theKey.latin1()); #endif // QT_CHECK_STATE return QDateTime(); } if (list.count() == 2) { d->heading = list[0]; d->group = "General"; } else { d->heading = list[0]; d->group = list[1]; } } return d->modificationTime(); } /*! \overload Writes the string list entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. The list is stored as a sequence of strings separated - by \a separator, so none of the strings in the list should contain - the separator. If the list is empty or null the key's value will - be an empty string. + by \a separator (using QStringList::join()), so none of the + strings in the list should contain the separator. If the list is + empty or null the key's value will be an empty string. + + \warning The list should not contain empty or null strings, as + readListEntry() will use QStringList::split() to recreate the + list. As the documentation states, QStringList::split() will omit + empty strings from the list. Because of this, it is impossible to + retrieve identical list data that is stored with this function. + We recommend using the writeEntry() and readListEntry() overloads + that do not take a \a separator argument. If an error occurs the settings are left unchanged and FALSE is returned; otherwise returns TRUE. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, const QStringList &value, const QChar &separator) { QString s(value.join(separator)); return writeEntry(key, s); } /*! \overload Writes the string list entry \a value into key \a key. The \a key is created if it doesn't exist. Any previous value is overwritten by \a value. If an error occurs the settings are left unchanged and FALSE is returned; otherwise returns TRUE. \sa readListEntry(), readNumEntry(), readDoubleEntry(), readBoolEntry(), removeEntry() */ bool QSettings::writeEntry(const QString &key, const QStringList &value) { QString s; for (QStringList::ConstIterator it=value.begin(); it!=value.end(); ++it) { QString el = *it; if ( el.isNull() ) { el = "^0"; } else { el.replace("^", "^^"); } s+=el; s+="^e"; // end of element } return writeEntry(key, s); } /*! \overload QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok ) const Reads the entry specified by \a key as a string. The \a separator is used to create a QStringList by calling QStringList::split(\a separator, entry). If \a ok is not 0: \a *ok is set to TRUE if the key was read, otherwise \a *ok is set to FALSE. + \warning As the documentation states, QStringList::split() will + omit empty strings from the list. Because of this, it is + impossible to retrieve identical list data with this function. We + recommend using the readListEntry() and writeEntry() overloads + that do not take a \a separator argument. + + Note that if you want to iterate over the list, you should iterate over a copy, e.g. \code QStringList list = mySettings.readListEntry( "size", " " ); QStringList::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split() */ /*! \internal */ QStringList QSettings::readListEntry(const QString &key, const QChar &separator, bool *ok ) { QString value = readEntry( key, QString::null, ok ); if ( ok && !*ok ) return QStringList(); return QStringList::split(separator, value); } /*! \fn QStringList QSettings::readListEntry(const QString &key, bool *ok ) const Reads the entry specified by \a key as a string. If \a ok is not 0, \a *ok is set to TRUE if the key was read, otherwise \a *ok is set to FALSE. Note that if you want to iterate over the list, you should iterate over a copy, e.g. \code QStringList list = mySettings.readListEntry( "recentfiles" ); QStringList::Iterator it = list.begin(); while( it != list.end() ) { myProcessing( *it ); ++it; } \endcode \sa readEntry(), readDoubleEntry(), readBoolEntry(), writeEntry(), removeEntry(), QStringList::split() */ /*! \internal */ QStringList QSettings::readListEntry(const QString &key, bool *ok ) { QString value = readEntry( key, QString::null, ok ); if ( ok && !*ok ) return QStringList(); QStringList l; QString s; bool esc=FALSE; for (int i=0; i<(int)value.length(); i++) { if ( esc ) { if ( value[i] == 'e' ) { // end-of-string l.append(s); s=""; } else if ( value[i] == '0' ) { // null string s=QString::null; } else { s.append(value[i]); } esc=FALSE; } else if ( value[i] == '^' ) { esc = TRUE; } else { s.append(value[i]); if ( i == (int)value.length()-1 ) l.append(s); } } return l; } +#ifdef Q_OS_MAC +void qt_setSettingsBasePath(const QString &); //qsettings_mac.cpp +#endif + /*! - Insert platform-dependent paths from platform-independent information. + Insert platform-dependent paths from platform-independent information. + + The \a domain should be an Internet domain name + controlled by the producer of the software, eg. Trolltech products + use "trolltech.com". - The \a domain should be an Internet domain name - controlled by the producer of the software, eg. Trolltech products - use "trolltech.com". + The \a product should be the official name of the product. - The \a product should be the official name of the product. + The \a scope should be + QSettings::User for user-specific settings, or + QSettings::Global for system-wide settings (generally + these will be read-only to many users). - The \a scope should be - QSettings::User for user-specific settings, or - QSettings::Global for system-wide settings (generally - these will be read-only to many users). + Not all information is relevant on all systems (e.g. scoping is + currently used only if QSettings accesses the Windows registry). */ void QSettings::setPath( const QString &domain, const QString &product, Scope scope ) { // On Windows, any trailing ".com(\..*)" is stripped from the domain. The // Global scope corresponds to HKEY_LOCAL_MACHINE, and User corresponds to // HKEY_CURRENT_USER. Note that on some installations, not all users can // write to the Global scope. On UNIX, any trailing ".com(\..*)" is stripped // from the domain. The Global scope corresponds to "/opt" (this would be // configurable at library build time - eg. to "/usr/local" or "/usr"), // while the User scope corresponds to $HOME/.*rc. // Note that on most installations, not all users can write to the System // scope. -// +// // On MacOS X, if there is no "." in domain, append ".com", then reverse the // order of the elements (Mac OS uses "com.apple.finder" as domain+product). // The Global scope corresponds to /Library/Preferences/*.plist, while the // User scope corresponds to ~/Library/Preferences/*.plist. // Note that on most installations, not all users can write to the System // scope. + d->globalScope = scope == Global; + QString actualSearchPath; int lastDot = domain.findRev( '.' ); #if defined(Q_WS_WIN) actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product; insertSearchPath( Windows, actualSearchPath ); -#elif defined(Q_WS_MAC) +#elif !defined(QWS) && defined(Q_OS_MAC) QString topLevelDomain = domain.right( domain.length() - lastDot - 1 ) + "."; - if ( topLevelDomain.isEmpty() ) - topLevelDomain = "com."; - actualSearchPath = "/" + topLevelDomain + domain.left( lastDot ) + product; + if ( !topLevelDomain.isEmpty() ) + qt_setSettingsBasePath( topLevelDomain ); + actualSearchPath = "/" + domain.left( lastDot ) + product; insertSearchPath( Mac, actualSearchPath ); #else actualSearchPath = "/" + domain.mid( 0, lastDot ) + "/" + product; insertSearchPath( Unix, actualSearchPath ); #endif - - d->globalScope = scope == Global; } /*! Appends \a group to the current key prefix. + + \code + QSettings settings; + settings.beginGroup( "/MainWindow" ); + // read values + settings.endGroup(); + \endcode */ void QSettings::beginGroup( const QString &group ) { d->groupStack.push( group ); d->groupDirty = TRUE; } /*! Undo previous calls to beginGroup(). Note that a single beginGroup("a/b/c") is undone by a single call to endGroup(). + + \code + QSettings settings; + settings.beginGroup( "/MainWindow/Geometry" ); + // read values + settings.endGroup(); + \endcode */ void QSettings::endGroup() { d->groupStack.pop(); d->groupDirty = TRUE; } /*! Set the current key prefix to the empty string. */ void QSettings::resetGroup() { d->groupStack.clear(); d->groupDirty = FALSE; d->groupPrefix = QString::null; } /*! Returns the current key prefix, or a null string if there is no key prefix set. \sa beginGroup(); */ QString QSettings::group() const { if ( d->groupDirty ) { d->groupDirty = FALSE; d->groupPrefix = QString::null; QValueStack<QString>::Iterator it = d->groupStack.begin(); while ( it != d->groupStack.end() ) { QString group = *it; ++it; if ( group[0] != '/' ) - group = "/" + group; + group.prepend( "/" ); d->groupPrefix += group; } } return d->groupPrefix; } #endif diff --git a/qmake/tools/qstring.cpp b/qmake/tools/qstring.cpp index 56df62b..7f1fac3 100644 --- a/qmake/tools/qstring.cpp +++ b/qmake/tools/qstring.cpp @@ -1,125 +1,129 @@ /**************************************************************************** ** $Id$ ** ** Implementation of the QString class and related Unicode functions ** ** Created : 920722 ** -** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** Copyright (C) 1992-2002 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. ** **********************************************************************/ // Don't define it while compiling this module, or USERS of Qt will // not be able to link. #ifdef QT_NO_CAST_ASCII #undef QT_NO_CAST_ASCII #endif #include "qstring.h" #include "qregexp.h" #include "qdatastream.h" #ifndef QT_NO_TEXTCODEC #include "qtextcodec.h" #endif -#include <ctype.h> #include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #if defined(Q_WS_WIN) #include "qt_windows.h" #endif #if !defined( QT_NO_COMPONENT ) && !defined( QT_LITE_COMPONENT ) #include "qcleanuphandler.h" #endif +#ifdef QT_NO_UNICODETABLES +# include <ctype.h> +#endif + /* ------------------------------------------------------------------------- * unicode information * these tables are generated from the unicode reference file * ftp://ftp.unicode.org/Public/3.2-Update/UnicodeData.txt * * Lars * ------------------------------------------------------------------------- */ /* Perl script to generate (run perl -x tools/qstring.cpp) #!perl sub numberize { my(%r, $n, $id); for $id ( @_ ) { $i = $id; $i="" if $i eq "EMPTY"; $r{$i}=$n++; } return %r; } sub readUnicodeDataLine { $code = shift @_; for $n (qw{ name category combining_class bidi_category character_decomposition decimal_digit_value digit_value numeric_value mirrored oldname comment uppercase lowercase titlecase}) { $id = shift @_; $codes = "${n}_code"; if ( defined %$codes && defined $$codes{$id} ) { $id = $$codes{$id}; } ${$n}{$code}=$id; } $decomp = $character_decomposition{$code}; if ( length $decomp == 0 ) { $decomp = "<single>"; } if (substr($decomp, 0, 1) ne '<') { $decomp = "<canonical> " . $decomp; } @_ = split(" ", $decomp); $tag = shift @_; $tag = $character_decomposition_tag{$tag}; $decomp = join( ", 0x", @_ ); $decomp = "0x".$decomp; $decomposition{$code} = $decomp; $decomposition_tag{$code} = $tag; $decomposition_pos{$code} = $position; $len = scalar(@_); $decomposition_len{$code} = $len; # we use canonical decompositions longer than 1 char # we exlude Arabic ligatures from the table if($len > 1 and $tag == 1) { # ligature to add... $start = shift @_; @@ -11726,242 +11730,244 @@ static const Q_INT8 * const decimal_info[256] = { // 47354 bytes // END OF GENERATED DATA #endif static inline QChar::Category category( const QChar &c ) { #ifndef QT_NO_UNICODETABLES return (QChar::Category)(unicode_info[c.row()][c.cell()]); #else // ### just ASCII if ( c.unicode() < 0x100 ) { return (QChar::Category)(ui_00[c.unicode()]); } return QChar::Letter_Uppercase; //####### #endif } static inline QChar lower( const QChar &c ) { #ifndef QT_NO_UNICODETABLES uchar row = c.row(); uchar cell = c.cell(); if ( unicode_info[row][cell] != QChar::Letter_Uppercase ) return c; Q_UINT16 lower = *( case_info[row] + cell ); if ( lower == 0 ) return c; return lower; #else if ( c.row() ) return c; else return QChar( tolower((uchar) c.latin1()) ); #endif } static inline QChar upper( const QChar &c ) { #ifndef QT_NO_UNICODETABLES uchar row = c.row(); uchar cell = c.cell(); if ( unicode_info[row][cell] != QChar::Letter_Lowercase ) return c; Q_UINT16 upper = *(case_info[row]+cell); if ( upper == 0 ) return c; return upper; #else if ( c.row() ) return c; else return QChar( toupper((uchar) c.latin1()) ); #endif } static inline QChar::Direction direction( const QChar &c ) { #ifndef QT_NO_UNICODETABLES const Q_UINT8 *rowp = direction_info[c.row()]; if(!rowp) return QChar::DirL; return (QChar::Direction) ( *(rowp+c.cell()) & 0x1f ); #else + Q_UNUSED(c); return QChar::DirL; #endif } static inline bool mirrored( const QChar &c ) { #ifndef QT_NO_UNICODETABLES const Q_UINT8 *rowp = direction_info[c.row()]; if ( !rowp ) return FALSE; return *(rowp+c.cell())>128; #else + Q_UNUSED(c); return FALSE; #endif } #ifndef QT_NO_UNICODETABLES static const Q_UINT16 symmetricPairs[] = { 0x0028, 0x0029, 0x003C, 0x003E, 0x005B, 0x005D, 0x007B, 0x007D, 0x00AB, 0x00BB, 0x2039, 0x203A, 0x2045, 0x2046, 0x207D, 0x207E, 0x208D, 0x208E, 0x2208, 0x220B, 0x2209, 0x220C, 0x220A, 0x220D, 0x2215, 0x29F5, 0x223C, 0x223D, 0x2243, 0x22CD, 0x2252, 0x2253, 0x2254, 0x2255, 0x2264, 0x2265, 0x2266, 0x2267, 0x2268, 0x2269, 0x226A, 0x226B, 0x226E, 0x226F, 0x2270, 0x2271, 0x2272, 0x2273, 0x2274, 0x2275, 0x2276, 0x2277, 0x2278, 0x2279, 0x227A, 0x227B, 0x227C, 0x227D, 0x227E, 0x227F, 0x2280, 0x2281, 0x2282, 0x2283, 0x2284, 0x2285, 0x2286, 0x2287, 0x2288, 0x2289, 0x228A, 0x228B, 0x228F, 0x2290, 0x2291, 0x2292, 0x2298, 0x29B8, 0x22A2, 0x22A3, 0x22A6, 0x2ADE, 0x22A8, 0x2AE4, 0x22A9, 0x2AE3, 0x22AB, 0x2AE5, 0x22B0, 0x22B1, 0x22B2, 0x22B3, 0x22B4, 0x22B5, 0x22B6, 0x22B7, 0x22C9, 0x22CA, 0x22CB, 0x22CC, 0x22D0, 0x22D1, 0x22D6, 0x22D7, 0x22D8, 0x22D9, 0x22DA, 0x22DB, 0x22DC, 0x22DD, 0x22DE, 0x22DF, 0x22E0, 0x22E1, 0x22E2, 0x22E3, 0x22E4, 0x22E5, 0x22E6, 0x22E7, 0x22E8, 0x22E9, 0x22EA, 0x22EB, 0x22EC, 0x22ED, 0x22F0, 0x22F1, 0x22F2, 0x22FA, 0x22F3, 0x22FB, 0x22F4, 0x22FC, 0x22F6, 0x22FD, 0x22F7, 0x22FE, 0x2308, 0x2309, 0x230A, 0x230B, 0x2329, 0x232A, 0x2768, 0x2769, 0x276A, 0x276B, 0x276C, 0x276D, 0x276E, 0x276F, 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, 0x2775, 0x27D5, 0x27D6, 0x27DD, 0x27DE, 0x27E2, 0x27E3, 0x27E4, 0x27E5, 0x27E6, 0x27E7, 0x27E8, 0x27E9, 0x27EA, 0x27EB, 0x2983, 0x2984, 0x2985, 0x2986, 0x2987, 0x2988, 0x2989, 0x298A, 0x298B, 0x298C, 0x298D, 0x2990, 0x298E, 0x298F, 0x2991, 0x2992, 0x2993, 0x2994, 0x2995, 0x2996, 0x2997, 0x2998, 0x29C0, 0x29C1, 0x29C4, 0x29C5, 0x29CF, 0x29D0, 0x29D1, 0x29D2, 0x29D4, 0x29D5, 0x29D8, 0x29D9, 0x29DA, 0x29DB, 0x29F8, 0x29F9, 0x29FC, 0x29FD, 0x2A2B, 0x2A2C, 0x2A34, 0x2A35, 0x2A3C, 0x2A3D, 0x2A64, 0x2A65, 0x2A79, 0x2A7A, 0x2A7D, 0x2A7E, 0x2A7F, 0x2A80, 0x2A81, 0x2A82, 0x2A83, 0x2A84, 0x2A8B, 0x2A8C, 0x2A91, 0x2A92, 0x2A93, 0x2A94, 0x2A95, 0x2A96, 0x2A97, 0x2A98, 0x2A99, 0x2A9A, 0x2A9B, 0x2A9C, 0x2AA1, 0x2AA2, 0x2AA6, 0x2AA7, 0x2AA8, 0x2AA9, 0x2AAA, 0x2AAB, 0x2AAC, 0x2AAD, 0x2AAF, 0x2AB0, 0x2AB3, 0x2AB4, 0x2ABB, 0x2ABC, 0x2ABD, 0x2ABE, 0x2ABF, 0x2AC0, 0x2AC1, 0x2AC2, 0x2AC3, 0x2AC4, 0x2AC5, 0x2AC6, 0x2ACD, 0x2ACE, 0x2ACF, 0x2AD0, 0x2AD1, 0x2AD2, 0x2AD3, 0x2AD4, 0x2AD5, 0x2AD6, 0x2AEC, 0x2AED, 0x2AF7, 0x2AF8, 0x2AF9, 0x2AFA, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F, 0x3010, 0x3011, 0x3014, 0x3015, 0x3016, 0x3017, 0x3018, 0x3019, 0x301A, 0x301B, 0xFF08, 0xFF09, 0xFF1C, 0xFF1E, 0xFF3B, 0xFF3D, 0xFF5B, 0xFF5D, 0xFF5F, 0xFF60, 0xFF62, 0xFF63, }; // ### shouldn't this be const? static const int symmetricPairsSize = sizeof(symmetricPairs)/sizeof(symmetricPairs[0]); /* * ---------------------------------------------------------------------- * End of unicode tables * ---------------------------------------------------------------------- */ #endif static int ucstrcmp( const QString &as, const QString &bs ) { const QChar *a = as.unicode(); const QChar *b = bs.unicode(); if ( a == b ) return 0; if ( a == 0 ) return 1; if ( b == 0 ) return -1; int l=QMIN(as.length(),bs.length()); while ( l-- && *a == *b ) a++,b++; if ( l==-1 ) return ( as.length()-bs.length() ); return a->unicode() - b->unicode(); } static int ucstrncmp( const QChar *a, const QChar *b, int l ) { while ( l-- && *a == *b ) a++,b++; if ( l==-1 ) return 0; return a->unicode() - b->unicode(); } static int ucstrnicmp( const QChar *a, const QChar *b, int l ) { while ( l-- && ::lower( *a ) == ::lower( *b ) ) a++,b++; if ( l==-1 ) return 0; return ::lower( *a ).unicode() - ::lower( *b ).unicode(); } static uint computeNewMax( uint len ) { uint newMax = 4; while ( newMax < len ) newMax *= 2; - // try to spare some memory + // try to save some memory if ( newMax >= 1024 * 1024 && len <= newMax - (newMax >> 2) ) newMax -= newMax >> 2; return newMax; } /*! \class QCharRef qstring.h \reentrant \brief The QCharRef class is a helper class for QString. \ingroup text When you get an object of type QCharRef, if you can assign to it, the assignment will apply to the character in the string from which you got the reference. That is its whole purpose in life. The QCharRef becomes invalid once modifications are made to the string: if you want to keep the character, copy it into a QChar. Most of the QChar member functions also exist in QCharRef. However, they are not explicitly documented here. \sa QString::operator[]() QString::at() QChar */ /*! \class QChar qstring.h \reentrant \brief The QChar class provides a lightweight Unicode character. \ingroup text Unicode characters are (so far) 16-bit entities without any markup or structure. This class represents such an entity. It is lightweight, so it can be used everywhere. Most compilers treat it like a "short int". (In a few years it may be necessary to make QChar 32-bit when more than 65536 Unicode code points have been defined and come into use.) QChar provides a full complement of testing/classification functions, converting to and from other formats, converting from composed to decomposed Unicode, and trying to compare and case-convert if you ask it to. The classification functions include functions like those in ctype.h, but operating on the full range of Unicode characters. They all return TRUE if the character is a certain type of character; otherwise they return FALSE. These classification functions are isNull() (returns TRUE if the character is U+0000), isPrint() (TRUE if the character is any sort of printable character, including whitespace), isPunct() (any sort of punctation), isMark() (Unicode Mark), isLetter (a letter), isNumber() (any sort of numeric character), isLetterOrNumber(), and isDigit() (decimal digits). All of these are wrappers around category() which return the Unicode-defined category of each character. QChar further provides direction(), which indicates the "natural" writing direction of this character. The joining() function indicates how the character joins with its neighbors (needed mostly for Arabic) and finally mirrored(), which indicates whether the character needs to be mirrored when it is printed in its "unnatural" writing direction. Composed Unicode characters (like å) can be converted to @@ -12830,232 +12836,232 @@ static inline bool format(QChar::Decomposition tag, QString & str, void QString::compose() { #ifndef QT_NO_UNICODETABLES unsigned int index=0, len; unsigned int cindex = 0; QChar code, head; QMemArray<QChar> dia; QString composed = *this; while (index < length()) { code = at(index); //printf("\n\nligature for 0x%x:\n", code.unicode()); QLigature ligature(code); ligature.first(); while(ligature.current()) { if ((len = ligature.match(*this, index)) != 0) { head = ligature.head(); unsigned short code = head.unicode(); // we exclude Arabic presentation forms A and a few // other ligatures, which are undefined in most fonts if(!(code > 0xfb50 && code < 0xfe80) && !(code > 0xfb00 && code < 0xfb2a)) { // joining info is only needed for Arabic if (format(ligature.tag(), *this, index, len)) { //printf("using ligature 0x%x, len=%d\n",code,len); // replace letter composed.replace(cindex, len, QChar(head)); index += len-1; // we continue searching in case we have a final // form because medial ones are preferred. if ( len != 1 || ligature.tag() !=QChar::Final ) break; } } } ligature.next(); } cindex++; index++; } *this = composed; #endif } // These macros are used for efficient allocation of QChar strings. // IMPORTANT! If you change these, make sure you also change the // "delete unicode" statement in ~QStringData() in qstring.h correspondingly! #define QT_ALLOC_QCHAR_VEC( N ) (QChar*) new char[ sizeof(QChar)*( N ) ] #define QT_DELETE_QCHAR_VEC( P ) delete[] ((char*)( P )) /*! This utility function converts the 8-bit string \a ba to Unicode, returning the result. The caller is responsible for deleting the return value with delete[]. */ -QChar* QString::asciiToUnicode( const QByteArray& ba, uint* len ) +QChar* QString::latin1ToUnicode( const QByteArray& ba, uint* len ) { if ( ba.isNull() ) { *len = 0; return 0; } int l = 0; while ( l < (int)ba.size() && ba[l] ) l++; char* str = ba.data(); QChar *uc = new QChar[ l ]; // Can't use macro, since function is public QChar *result = uc; if ( len ) *len = l; while (l--) *uc++ = *str++; return result; } -static QChar* internalAsciiToUnicode( const QByteArray& ba, uint* len ) +static QChar* internalLatin1ToUnicode( const QByteArray& ba, uint* len ) { if ( ba.isNull() ) { *len = 0; return 0; } int l = 0; while ( l < (int)ba.size() && ba[l] ) l++; char* str = ba.data(); QChar *uc = QT_ALLOC_QCHAR_VEC( l ); QChar *result = uc; if ( len ) *len = l; while (l--) *uc++ = *str++; return result; } /*! \overload This utility function converts the '\0'-terminated 8-bit string \a str to Unicode, returning the result and setting \a *len to the length of the Unicode string. The caller is responsible for deleting the return value with delete[]. */ -QChar* QString::asciiToUnicode( const char *str, uint* len, uint maxlen ) +QChar* QString::latin1ToUnicode( const char *str, uint* len, uint maxlen ) { QChar* result = 0; uint l = 0; if ( str ) { if ( maxlen != (uint)-1 ) { while ( l < maxlen && str[l] ) l++; } else { // Faster? - l = qstrlen(str); + l = strlen( str ); } QChar *uc = new QChar[ l ]; // Can't use macro since function is public result = uc; uint i = l; while ( i-- ) *uc++ = *str++; } if ( len ) *len = l; return result; } -static QChar* internalAsciiToUnicode( const char *str, uint* len, +static QChar* internalLatin1ToUnicode( const char *str, uint* len, uint maxlen = (uint)-1 ) { QChar* result = 0; uint l = 0; if ( str ) { if ( maxlen != (uint)-1 ) { while ( l < maxlen && str[l] ) l++; } else { // Faster? - l = qstrlen(str); + l = strlen( str ); } QChar *uc = QT_ALLOC_QCHAR_VEC( l ); result = uc; uint i = l; while ( i-- ) *uc++ = *str++; } if ( len ) *len = l; return result; } /*! This utility function converts \a l 16-bit characters from \a uc to ASCII, returning a '\0'-terminated string. The caller is responsible for deleting the resultant string with delete[]. */ -char* QString::unicodeToAscii(const QChar *uc, uint l) +char* QString::unicodeToLatin1(const QChar *uc, uint l) { if (!uc) { return 0; } char *a = new char[l+1]; char *result = a; while (l--) { *a++ = (uc->unicode() > 0xff) ? '?' : (char)uc->unicode(); uc++; } *a = '\0'; return result; } /***************************************************************************** QString member functions *****************************************************************************/ /*! \class QString qstring.h \reentrant \brief The QString class provides an abstraction of Unicode text and the classic C '\0'-terminated char array. \ingroup tools \ingroup shared \ingroup text \mainclass QString uses \link shclass.html implicit sharing\endlink, which makes it very efficient and easy to use. In all of the QString methods that take \c {const char *} parameters, the \c {const char *} is interpreted as a classic C-style '\0'-terminated ASCII string. It is legal for the \c {const char *} parameter to be 0. If the \c {const char *} is not '\0'-terminated, the results are undefined. Functions that copy classic C strings into a QString will not copy the terminating '\0' character. The QChar array of the QString (as returned by unicode()) is generally not terminated by a '\0'. If you need to pass a QString to a function that requires a C '\0'-terminated string use latin1(). \keyword QString::null A QString that has not been assigned to anything is \e null, i.e. both the length and data pointer is 0. A QString that references the empty string ("", a single '\0' char) is \e empty. Both null and empty QStrings are legal parameters to the methods. Assigning \c{(const char *) 0} to QString gives a null QString. For convenience, \c QString::null is a null QString. When sorting, empty strings come first, followed by non-empty strings, followed by null strings. We recommend using \c{if ( !str.isNull() )} to check for a non-null string rather than \c{if ( !str )}; see \l operator!() for an explanation. Note that if you find that you are mixing usage of \l QCString, QString, and \l QByteArray, this causes lots of unnecessary copying and might indicate that the true nature of the data you are dealing with is uncertain. If the data is '\0'-terminated 8-bit data, use \l QCString; if it is unterminated (i.e. contains '\0's) 8-bit data, use \l QByteArray; if it is text, use QString. Lists of strings are handled by the QStringList class. You can @@ -13096,516 +13102,520 @@ char* QString::unicodeToAscii(const QChar *uc, uint l) QString func( const QString& input ) { QString output = input; // process output return output; } \endcode The 'copying' of input to output is almost as fast as copying a pointer because behind the scenes copying is achieved by incrementing a reference count. QString (like all Qt's implicitly shared classes) operates on a copy-on-write basis, only copying if an instance is actually changed. If you wish to create a deep copy of a QString without losing any Unicode information then you should use QDeepCopy. \sa QChar QCString QByteArray QConstString */ /*! \enum Qt::ComparisonFlags \internal */ /*! \enum Qt::StringComparisonMode This enum type is used to set the string comparison mode when searching for an item. It is used by QListBox, QListView and QIconView, for example. We'll refer to the string being searched as the 'target' string. \value CaseSensitive The strings must match case sensitively. \value ExactMatch The target and search strings must match exactly. \value BeginsWith The target string begins with the search string. \value EndsWith The target string ends with the search string. \value Contains The target string contains the search string. If you OR these flags together (excluding \c CaseSensitive), the search criteria be applied in the following order: \c ExactMatch, \c BeginsWith, \c EndsWith, \c Contains. Matching is case-insensitive unless \c CaseSensitive is set. \c CaseSensitive may be OR-ed with any combination of the other flags. */ Q_EXPORT QStringData *QString::shared_null = 0; QT_STATIC_CONST_IMPL QString QString::null; QT_STATIC_CONST_IMPL QChar QChar::null; QT_STATIC_CONST_IMPL QChar QChar::replacement((ushort)0xfffd); QT_STATIC_CONST_IMPL QChar QChar::byteOrderMark((ushort)0xfeff); QT_STATIC_CONST_IMPL QChar QChar::byteOrderSwapped((ushort)0xfffe); QT_STATIC_CONST_IMPL QChar QChar::nbsp((ushort)0x00a0); QStringData* QString::makeSharedNull() { QString::shared_null = new QStringData; #if defined( Q_OS_MAC ) QString *that = const_cast<QString *>(&QString::null); that->d = QString::shared_null; #endif return QString::shared_null; } -// Uncomment this to get some useful statistics. -// #define Q2HELPER(x) x - -#ifdef Q2HELPER -static int stat_construct_charstar=0; -static int stat_construct_charstar_size=0; -static int stat_construct_null=0; -static int stat_construct_int=0; -static int stat_construct_int_size=0; -static int stat_construct_ba=0; -static int stat_get_ascii=0; -static int stat_get_ascii_size=0; -static int stat_copy_on_write=0; -static int stat_copy_on_write_size=0; -static int stat_fast_copy=0; -Q_EXPORT void qt_qstring_stats() -{ - qDebug("construct_charstar = %d (%d chars)", stat_construct_charstar, stat_construct_charstar_size); - qDebug("construct_null = %d", stat_construct_null); - qDebug("construct_int = %d (%d chars)", stat_construct_int, stat_construct_int_size); - qDebug("construct_ba = %d", stat_construct_ba); - qDebug("get_ascii = %d (%d chars)", stat_get_ascii, stat_get_ascii_size); - qDebug("copy_on_write = %d (%d chars)", stat_copy_on_write, stat_copy_on_write_size); - qDebug("fast_copy = %d", stat_fast_copy); -} -#else -#define Q2HELPER(x) -#endif - /*! \fn QString::QString() Constructs a null string, i.e. both the length and data pointer are 0. \sa isNull() */ /*! Constructs a string of length one, containing the character \a ch. */ QString::QString( QChar ch ) { d = new QStringData( QT_ALLOC_QCHAR_VEC( 1 ), 1, 1 ); d->unicode[0] = ch; } /*! Constructs an implicitly shared copy of \a s. This is very fast since it only involves incrementing a reference count. */ QString::QString( const QString &s ) : d(s.d) { - Q2HELPER(stat_fast_copy++) d->ref(); } /*! \internal Private function. Constructs a string with preallocated space for \a size characters. The string is empty. \sa isNull() */ QString::QString( int size, bool /*dummy*/ ) { if ( size ) { - Q2HELPER(stat_construct_int++) int l = size; - Q2HELPER(stat_construct_int_size+=l) QChar* uc = QT_ALLOC_QCHAR_VEC( l ); d = new QStringData( uc, 0, l ); } else { - Q2HELPER(stat_construct_null++) d = shared_null ? shared_null : (shared_null=new QStringData); d->ref(); } } /*! Constructs a string that is a deep copy of \a ba interpreted as a classic C string. */ QString::QString( const QByteArray& ba ) { - Q2HELPER(stat_construct_ba++) +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + d = 0; + *this = fromAscii( ba.data(), ba.size() ); + return; + } +#endif uint l; - QChar *uc = internalAsciiToUnicode(ba,&l); + QChar *uc = internalLatin1ToUnicode(ba,&l); d = new QStringData(uc,l,l); } /*! Constructs a string that is a deep copy of the first \a length characters in the QChar array. If \a unicode and \a length are 0, then a null string is created. If only \a unicode is 0, the string is empty but has \a length characters of space preallocated: QString expands automatically anyway, but this may speed up some cases a little. We recommend using the plain constructor and setLength() for this purpose since it will result in more readable code. \sa isNull() setLength() */ QString::QString( const QChar* unicode, uint length ) { if ( !unicode && !length ) { d = shared_null ? shared_null : makeSharedNull(); d->ref(); } else { QChar* uc = QT_ALLOC_QCHAR_VEC( length ); if ( unicode ) memcpy(uc, unicode, length*sizeof(QChar)); d = new QStringData(uc,unicode ? length : 0,length); } } /*! Constructs a string that is a deep copy of \a str, interpreted as a classic C string. If \a str is 0, then a null string is created. This is a cast constructor, but it is perfectly safe: converting a Latin1 const char* to QString preserves all the information. You can disable this constructor by defining \c QT_NO_CAST_ASCII when you compile your applications. You can also make QString objects by using setLatin1(), fromLatin1(), fromLocal8Bit(), and fromUtf8(). Or whatever encoding is appropriate for the 8-bit data you have. \sa isNull() */ QString::QString( const char *str ) { - Q2HELPER(stat_construct_charstar++) +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + d = 0; + *this = fromAscii( str ); + return; + } +#endif + uint l; + QChar *uc = internalLatin1ToUnicode(str,&l); + d = new QStringData(uc,l,l); +} + +#ifndef QT_NO_STL +/*! + Constructs a string that is a deep copy of \a str. + + This is the same as fromAscii(\a str). +*/ + +QString::QString( const std::string &str ) +{ +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + d = 0; + *this = fromAscii( str.c_str() ); + return; + } +#endif uint l; - QChar *uc = internalAsciiToUnicode(str,&l); - Q2HELPER(stat_construct_charstar_size+=l) + QChar *uc = internalLatin1ToUnicode(str.c_str(),&l); d = new QStringData(uc,l,l); } +#endif /*! \fn QString::~QString() Destroys the string and frees the string's data if this is the last reference to the string. */ /*! Deallocates any space reserved solely by this QString. If the string does not share its data with another QString instance, nothing happens; otherwise the function creates a new, unique copy of this string. This function is called whenever the string is modified. */ void QString::real_detach() { setLength( length() ); } void QString::deref() { - if ( d->deref() ) { + if ( d && d->deref() ) { if ( d != shared_null ) delete d; - d = 0; // helps debugging + d = 0; } } void QStringData::deleteSelf() { delete this; } /*! \fn QString& QString::operator=( QChar c ) Sets the string to contain just the single character \a c. */ /*! + \fn QString& QString::operator=( const std::string& s ) + + \overload + + Makes a deep copy of \a s and returns a reference to the deep + copy. +*/ + +/*! \fn QString& QString::operator=( char c ) \overload Sets the string to contain just the single character \a c. */ /*! \overload Assigns a shallow copy of \a s to this string and returns a reference to this string. This is very fast because the string isn't actually copied. */ QString &QString::operator=( const QString &s ) { - Q2HELPER(stat_fast_copy++) s.d->ref(); deref(); d = s.d; return *this; } /*! \overload Assigns a deep copy of \a cs, interpreted as a classic C string, to this string and returns a reference to this string. */ QString &QString::operator=( const QCString& cs ) { - return setLatin1(cs); + return setAscii(cs); } /*! \overload Assigns a deep copy of \a str, interpreted as a classic C string to this string and returns a reference to this string. If \a str is 0, then a null string is created. \sa isNull() */ QString &QString::operator=( const char *str ) { - return setLatin1(str); + return setAscii(str); } /*! \fn bool QString::isNull() const Returns TRUE if the string is null; otherwise returns FALSE. A null string is always empty. \code QString a; // a.unicode() == 0, a.length() == 0 a.isNull(); // TRUE, because a.unicode() == 0 a.isEmpty(); // TRUE \endcode \sa isEmpty(), length() */ /*! \fn bool QString::isEmpty() const Returns TRUE if the string is empty, i.e. if length() == 0; otherwise returns FALSE. Null strings are also empty. \code QString a( "" ); a.isEmpty(); // TRUE a.isNull(); // FALSE QString b; b.isEmpty(); // TRUE b.isNull(); // TRUE \endcode \sa isNull(), length() */ /*! \fn uint QString::length() const Returns the length of the string. Null strings and empty strings have zero length. \sa isNull(), isEmpty() */ /*! If \a newLen is less than the length of the string, then the string is truncated at position \a newLen. Otherwise nothing happens. \code QString s = "truncate me"; s.truncate( 5 ); // s == "trunc" \endcode \sa setLength() */ void QString::truncate( uint newLen ) { if ( newLen < d->len ) setLength( newLen ); } /*! Ensures that at least \a newLen characters are allocated to the string, and sets the length of the string to \a newLen. Any new space allocated contains arbitrary data. - If \a newLen is 0, then the string becomes empty, unless the - string is null, in which case it remains null. + If \a newLen is 0, then the string becomes empty (non-null). If it is not possible to allocate enough memory, the string remains unchanged. This function always detaches the string from other references to the same data. This function is useful for code that needs to build up a long string and wants to avoid repeated reallocation. In this example, we want to add to the string until some condition is true, and we're fairly sure that size is big enough: \code QString result; - int resultLength = 0; - result.setLength( newLen ) // allocate some space + int len = 0; + result.setLength( maxLen ); // allocate some space while ( ... ) { - result[resultLength++] = ... // fill (part of) the space with data + result[len++] = ... // fill part of the space } - result.truncate[resultLength]; // and get rid of the undefined junk + result.truncate( len ); // and get rid of the rest \endcode If \a newLen is an underestimate, the worst that will happen is that the loop will slow down. \sa truncate(), isNull(), isEmpty(), length() */ void QString::setLength( uint newLen ) { if ( d->count != 1 || newLen > d->maxl || ( newLen * 4 < d->maxl && d->maxl > 4 ) ) { // detach, grow or shrink - Q2HELPER(stat_copy_on_write++) - Q2HELPER(stat_copy_on_write_size+=d->len) uint newMax = computeNewMax( newLen ); QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); if ( nd ) { uint len = QMIN( d->len, newLen ); if ( d->unicode ) memcpy( nd, d->unicode, sizeof(QChar)*len ); deref(); d = new QStringData( nd, newLen, newMax ); } } else { d->len = newLen; d->setDirty(); } } /*! This function will return a string that replaces the lowest numbered occurrence of \c %1, \c %2, ..., \c %9 with \a a. The \a fieldwidth value specifies the minimum amount of space that \a a is padded to. A positive value will produce right-aligned text, whereas a negative value will produce left-aligned text. + The following example shows how we could create a 'status' string + when processing a list of files: \code - QString firstName( "Joe" ); - QString lastName( "Bloggs" ); - QString fullName; - fullName = QString( "First name is '%1', last name is '%2'" ) - .arg( firstName ) - .arg( lastName ); - - // fullName == First name is 'Joe', last name is 'Bloggs' + QString status = QString( "Processing file %1 of %2: %3" ) + .arg( i ) // current file's number + .arg( total ) // number of files to process + .arg( fileName ); // current file's name \endcode - Note that using arg() to construct sentences as we've done in the - example above does not usually translate well into other languages - because sentence structure and word order often differ between - languages. + It is generally fine to use filenames and numbers as we have done + in the example above. But note that using arg() to construct + natural language sentences does not usually translate well into + other languages because sentence structure and word order often + differ between languages. If there is no place marker (\c %1 or \c %2, etc.), a warning message (qWarning()) is output and the text is appended at the end of the string. We recommend that the correct number of place markers is always used in production code. */ QString QString::arg( const QString& a, int fieldwidth ) const { int pos, len; QString r = *this; if ( !findArg( pos, len ) ) { qWarning( "QString::arg(): Argument missing: %s, %s", latin1(), a.latin1() ); // Make sure the text at least appears SOMEWHERE r += ' '; pos = r.length(); len = 0; } r.replace( pos, len, a ); if ( fieldwidth < 0 ) { QString s; while ( (uint)-fieldwidth > a.length() ) { s += ' '; fieldwidth++; } r.insert( pos + a.length(), s ); } else if ( fieldwidth ) { QString s; while ( (uint)fieldwidth > a.length() ) { s += ' '; fieldwidth--; } r.insert( pos, s ); } return r; } /*! \overload The \a fieldwidth value specifies the minimum amount of space that \a a is padded to. A positive value will produce a right-aligned number, whereas a negative value will produce a left-aligned number. \a a is expressed in base \a base, which is 10 by default and must be between 2 and 36. \code QString str; str = QString( "Decimal 63 is %1 in hexadecimal" ) .arg( 63, 0, 16 ); // str == "Decimal 63 is 3f in hexadecimal" \endcode */ QString QString::arg( long a, int fieldwidth, int base ) const { return arg( QString::number(a, base), fieldwidth ); } @@ -13713,129 +13723,129 @@ QString QString::arg( double a, int fieldwidth, char fmt, int prec ) const } /* Just 1-digit arguments. */ bool QString::findArg( int& pos, int& len ) const { char lowest=0; register const QChar *uc = d->unicode; const uint l = length(); for (uint i = 0; i < l; i++) { if ( uc[i] == '%' && i+1<l ) { QChar dig = uc[i+1]; if ( dig >= '0' && dig <= '9' ) { if ( !lowest || dig < lowest ) { lowest = dig; pos = i; len = 2; } } } } return lowest != 0; } /*! Safely builds a formatted string from the format string \a cformat and an arbitrary list of arguments. The format string supports all the escape sequences of printf() in the standard C library. The %s escape sequence expects a utf8() encoded string. The format string \e cformat is expected to be in latin1. If you need a Unicode format string, use arg() instead. For typesafe string building, with full Unicode support, you can use QTextOStream like this: \code QString str; QString s = ...; int x = ...; QTextOStream( &str ) << s << " : " << x; \endcode For \link QObject::tr() translations,\endlink especially if the strings contains more than one escape sequence, you should consider using the arg() function instead. This allows the order of the replacements to be controlled by the translator, and has Unicode support. \sa arg() */ #ifndef QT_NO_SPRINTF QString &QString::sprintf( const char* cformat, ... ) { va_list ap; va_start( ap, cformat ); if ( !cformat || !*cformat ) { // Qt 1.x compat *this = fromLatin1( "" ); return *this; } - QString format = fromLatin1( cformat ); + QString format = fromAscii( cformat ); QRegExp escape( "%#?0?-? ?\\+?'?[0-9*]*\\.?[0-9*]*h?l?L?q?Z?" ); QString result; uint last = 0; int pos; int len = 0; for (;;) { pos = escape.search( format, last ); len = escape.matchedLength(); // Non-escaped text if ( pos > (int)last ) result += format.mid( last, pos - last ); if ( pos < 0 ) { // The rest if ( last < format.length() ) result += format.mid( last ); break; } last = pos + len + 1; // Escape QString f = format.mid( pos, len ); uint width, decimals; int params = 0; int wpos = f.find('*'); if ( wpos >= 0 ) { params++; width = va_arg( ap, int ); if ( f.find('*', wpos + 1) >= 0 ) { decimals = va_arg( ap, int ); params++; } else { decimals = 0; } } else { decimals = width = 0; } QString replacement; if ( format[pos + len] == 's' || format[pos + len] == 'S' || format[pos + len] == 'c' ) { bool rightjust = ( f.find('-') < 0 ); // %-5s really means left adjust in sprintf if ( wpos < 0 ) { QRegExp num( fromLatin1("[0-9]+") ); int p = num.search( f ); int nlen = num.matchedLength(); int q = f.find( '.' ); if ( q < 0 || (p < q && p >= 0) ) width = f.mid( p, nlen ).toInt(); if ( q >= 0 ) { p = num.search( f, q ); // "decimals" is used to specify string truncation if ( p >= 0 ) decimals = f.mid( p, nlen ).toInt(); } } if ( format[pos + len] == 's' ) { QString s = QString::fromUtf8( va_arg(ap, char*) ); replacement = ( decimals <= 0 ) ? s : s.left( decimals ); } else { @@ -13852,129 +13862,129 @@ QString &QString::sprintf( const char* cformat, ... ) } else if ( format[pos+len] == 'n' ) { int* n = va_arg(ap, int*); *n = result.length(); } else { char in[64], out[330]; strncpy(in,f.latin1(),63); out[0] = '\0'; char fch = format[pos+len].latin1(); in[f.length()] = fch; switch ( fch ) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { int value = va_arg( ap, int ); switch ( params ) { case 0: ::sprintf( out, in, value ); break; case 1: ::sprintf( out, in, width, value ); break; case 2: ::sprintf( out, in, width, decimals, value ); } } break; case 'e': case 'E': case 'f': case 'g': case 'G': { double value = va_arg( ap, double ); switch ( params ) { case 0: ::sprintf( out, in, value ); break; case 1: ::sprintf( out, in, width, value ); break; case 2: ::sprintf( out, in, width, decimals, value ); } } break; case 'p': { void* value = va_arg( ap, void * ); switch ( params ) { case 0: ::sprintf( out, in, value ); break; case 1: ::sprintf( out, in, width, value ); break; case 2: ::sprintf( out, in, width, decimals, value ); } } } - replacement = fromLatin1( out ); + replacement = fromAscii( out ); } result += replacement; } *this = result; va_end( ap ); return *this; } #endif /*! Fills the string with \a len characters of value \a c, and returns a reference to the string. If \a len is negative (the default), the current string length is used. \code QString str; str.fill( 'g', 5 ); // string == "ggggg" \endcode */ QString& QString::fill( QChar c, int len ) { if ( len < 0 ) len = length(); if ( len == 0 ) { *this = ""; } else { deref(); QChar * nd = QT_ALLOC_QCHAR_VEC( len ); d = new QStringData(nd,len,len); while (len--) *nd++ = c; } return *this; } /*! \fn QString QString::copy() const \obsolete In Qt 2.0 and later, all calls to this function are needless. Just remove them. */ /*! \overload Finds the first occurrence of the character \a c, starting at position \a index. If \a index is -1, the search starts at the last character; if -2, at the next to last character and so on. (See findRev() for searching backwards.) If \a cs is TRUE, the search is case sensitive; otherwise the search is case insensitive. Returns the position of \a c or -1 if \a c could not be found. */ int QString::find( QChar c, int index, bool cs ) const { @@ -14063,279 +14073,287 @@ static int bm_find( const QString &str, int index, const QString &pattern, uint if ( skiptable[ (current-skip)->cell() ] == pl ) skip = pl - skip; else skip = 1; } current += skip; } } else { while( current < end ) { uint skip = skiptable[ ::lower( *current ).cell() ]; if ( !skip ) { // possible match while( skip < pl ) { if ( ::lower( *(current - skip) ) != ::lower( puc[pl_minus_one-skip] ) ) break; skip++; } if ( skip > pl_minus_one ) // we have a match return (current - uc) - skip + 1; // in case we don't have a match we are a bit inefficient as we only skip by one // when we have the non matching char in the string. if ( skiptable[ ::lower( (current - skip)->cell() ) ] == pl ) skip = pl - skip; else skip = 1; } current += skip; } } // not found return -1; } #define REHASH( a ) \ if ( sl_minus_1 < sizeof(uint) * CHAR_BIT ) \ hashHaystack -= (a) << sl_minus_1; \ hashHaystack <<= 1 /*! \overload Finds the first occurrence of the string \a str, starting at position \a index. If \a index is -1, the search starts at the last character, if it is -2, at the next to last character and so on. (See findRev() for searching backwards.) If \a cs is TRUE, the search is case sensitive; otherwise the search is case insensitive. Returns the position of \a str or -1 if \a str could not be found. */ int QString::find( const QString& str, int index, bool cs ) const { const uint l = length(); const uint sl = str.length(); if ( index < 0 ) index += l; if ( sl + index > l ) return -1; if ( !sl ) return index; +#ifndef MACOSX_101 if ( sl == 1 ) return find( *str.unicode(), index, cs ); +#endif // we use the Boyer-Moore algorithm in cases where the overhead // for the hash table should pay off, otherwise we use a simple // hash function if ( l > 500 && sl > 5 ) { uint skiptable[0x100]; bm_init_skiptable( str, skiptable, cs ); return bm_find( *this, index, str, skiptable, cs ); } /* We use some hashing for efficiency's sake. Instead of comparing strings, we compare the hash value of str with that of a part of this QString. Only if that matches, we call ucstrncmp or ucstrnicmp. */ const QChar* needle = str.unicode(); const QChar* haystack = unicode() + index; const QChar* end = unicode() + (l-sl); const uint sl_minus_1 = sl-1; uint hashNeedle = 0, hashHaystack = 0, i; if ( cs ) { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + needle[i].unicode() ); hashHaystack = ((hashHaystack<<1) + haystack[i].unicode() ); } hashHaystack -= (haystack+sl_minus_1)->unicode(); while ( haystack <= end ) { hashHaystack += (haystack+sl_minus_1)->unicode(); if ( hashHaystack == hashNeedle && ucstrncmp( needle, haystack, sl ) == 0 ) return haystack-unicode(); REHASH( haystack->unicode() ); ++haystack; } } else { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + ::lower( needle[i].unicode() ).unicode() ); hashHaystack = ((hashHaystack<<1) + ::lower( haystack[i].unicode() ).unicode() ); } hashHaystack -= ::lower(*(haystack+sl_minus_1)).unicode(); while ( haystack <= end ) { hashHaystack += ::lower(*(haystack+sl_minus_1)).unicode(); if ( hashHaystack == hashNeedle && ucstrnicmp( needle, haystack, sl ) == 0 ) return haystack-unicode(); REHASH( ::lower(*haystack).unicode() ); ++haystack; } } return -1; } /*! \fn int QString::findRev( const char* str, int index ) const Equivalent to findRev(QString(\a str), \a index). */ /*! \fn int QString::find( const char* str, int index ) const \overload Equivalent to find(QString(\a str), \a index). */ /*! \overload Finds the first occurrence of the character \a c, starting at position \a index and searching backwards. If the index is -1, the search starts at the last character, if it is -2, at the next to last character and so on. Returns the position of \a c or -1 if \a c could not be found. If \a cs is TRUE, the search is case sensitive; otherwise the search is case insensitive. \code QString string( "bananas" ); int i = string.findRev( 'a' ); // i == 5 \endcode */ int QString::findRev( QChar c, int index, bool cs ) const { +#ifdef MACOSX_101 + return findRev( QString( c ), index, cs ); +#else const uint l = length(); if ( index < 0 ) index += l; if ( (uint)index >= l ) return -1; const QChar *end = unicode(); register const QChar *uc = end + index; if ( cs ) { while ( uc >= end && *uc != c ) uc--; } else { c = ::lower( c ); while ( uc >= end && ::lower( *uc ) != c ) uc--; } return uc - end; +#endif } /*! \overload Finds the first occurrence of the string \a str, starting at position \a index and searching backwards. If the index is -1, the search starts at the last character, if it is -2, at the next to last character and so on. Returns the position of \a str or -1 if \a str could not be found. If \a cs is TRUE, the search is case sensitive; otherwise the search is case insensitive. \code QString string("bananas"); int i = string.findRev( "ana" ); // i == 3 \endcode */ int QString::findRev( const QString& str, int index, bool cs ) const { /* See QString::find() for explanations. */ const uint l = length(); if ( index < 0 ) index += l; const uint sl = str.length(); int delta = l-sl; if ( index < 0 || index > (int)l || delta < 0 ) return -1; if ( index > delta ) index = delta; +#ifndef MACOSX_101 if ( sl == 1 ) return findRev( *str.unicode(), index, cs ); +#endif const QChar* needle = str.unicode(); const QChar* haystack = unicode() + index; const QChar* end = unicode(); const uint sl_minus_1 = sl-1; const QChar* n = needle+sl_minus_1; const QChar* h = haystack+sl_minus_1; uint hashNeedle = 0, hashHaystack = 0, i; if ( cs ) { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + (n-i)->unicode() ); hashHaystack = ((hashHaystack<<1) + (h-i)->unicode() ); } hashHaystack -= haystack->unicode(); while ( haystack >= end ) { hashHaystack += haystack->unicode(); if ( hashHaystack == hashNeedle && ucstrncmp( needle, haystack, sl ) == 0 ) return haystack-unicode(); --haystack; REHASH( (haystack+sl)->unicode() ); } } else { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + ::lower( (n-i)->unicode() ).unicode() ); hashHaystack = ((hashHaystack<<1) + ::lower( (h-i)->unicode() ).unicode() ); } hashHaystack -= ::lower(*haystack).unicode(); while ( haystack >= end ) { hashHaystack += ::lower(*haystack).unicode(); if ( hashHaystack == hashNeedle && ucstrnicmp( needle, haystack, sl ) == 0 ) return haystack-unicode(); --haystack; REHASH( ::lower(*(haystack+sl)).unicode() ); } } return -1; } #undef REHASH /*! \enum QString::SectionFlags \value SectionDefault Empty fields are counted, leading and trailing separators are not included, and the separator is compared case sensitively. \value SectionSkipEmpty Treat empty fields as if they don't exist, i.e. they are not considered as far as \e start and \e end are concerned. \value SectionIncludeLeadingSep Include the leading separator (if any) in the result string. \value SectionIncludeTrailingSep Include the trailing separator (if any) in the result string. @@ -14918,400 +14936,420 @@ QString QString::leftJustify( uint width, QChar fill, bool truncate ) const while (padlen--) *uc++ = fill; } else { if ( truncate ) result = left( width ); else result = *this; } return result; } /*! Returns a string of length \a width that contains the \a fill character followed by the string. If \a truncate is FALSE and the length of the string is more than \a width, then the returned string is a copy of the string. If \a truncate is TRUE and the length of the string is more than \a width, then the resulting string is truncated at position \a width. \code QString string( "apple" ); QString t = string.rightJustify( 8, '.' ); // t == "...apple" \endcode \sa leftJustify() */ QString QString::rightJustify( uint width, QChar fill, bool truncate ) const { QString result; int len = length(); int padlen = width - len; if ( padlen > 0 ) { result.setLength( len+padlen ); QChar* uc = result.d->unicode; while (padlen--) *uc++ = fill; if ( len ) memcpy( uc, unicode(), sizeof(QChar)*len ); } else { if ( truncate ) result = left( width ); else result = *this; } return result; } /*! Returns a lowercase copy of the string. \code QString string( "TROlltECH" ); str = string.lower(); // str == "trolltech" \endcode \sa upper() */ QString QString::lower() const { - QString s(*this); - int l=length(); - if ( l ) { - s.real_detach(); // could do this only when we find a change - register QChar *p=s.d->unicode; - if ( p ) { - while ( l-- ) { + int l = length(); + register QChar *p = d->unicode; + while ( l ) { + if ( *p != ::lower(*p) ) { + QString s( *this ); + s.real_detach(); + p = s.d->unicode + ( p - d->unicode ); + while ( l ) { *p = ::lower( *p ); + l--; p++; } + return s; } + l--; + p++; } - return s; + return *this; } /*! Returns an uppercase copy of the string. \code QString string( "TeXt" ); str = string.upper(); // t == "TEXT" \endcode \sa lower() */ QString QString::upper() const { - QString s(*this); - int l=length(); - if ( l ) { - s.real_detach(); // could do this only when we find a change - register QChar *p=s.d->unicode; - if ( p ) { - while ( l-- ) { + int l = length(); + register QChar *p = d->unicode; + while ( l ) { + if ( *p != ::upper(*p) ) { + QString s( *this ); + s.real_detach(); + p = s.d->unicode + ( p - d->unicode ); + while ( l ) { *p = ::upper( *p ); + l--; p++; } + return s; } + l--; + p++; } - return s; + return *this; } /*! Returns a string that has whitespace removed from the start and the end. Whitespace means any character for which QChar::isSpace() returns TRUE. This includes Unicode characters with decimal values 9 (TAB), 10 (LF), 11 (VT), 12 (FF), 13 (CR) and 32 (Space), and may also include other Unicode characters. \code QString string = " white space "; QString s = string.stripWhiteSpace(); // s == "white space" \endcode \sa simplifyWhiteSpace() */ QString QString::stripWhiteSpace() const { if ( isEmpty() ) // nothing to do return *this; register const QChar *s = unicode(); if ( !s->isSpace() && !s[length()-1].isSpace() ) return *this; int start = 0; int end = length() - 1; while ( start<=end && s[start].isSpace() ) // skip white space from start start++; if ( start <= end ) { // only white space while ( end && s[end].isSpace() ) // skip white space from end end--; } int l = end - start + 1; if ( l <= 0 ) return QString::fromLatin1(""); QString result( l, TRUE ); memcpy( result.d->unicode, &s[start], sizeof(QChar)*l ); result.d->len = l; return result; } /*! Returns a string that has whitespace removed from the start and the end, and which has each sequence of internal whitespace replaced with a single space. Whitespace means any character for which QChar::isSpace() returns TRUE. This includes Unicode characters with decimal values 9 (TAB), 10 (LF), 11 (VT), 12 (FF), 13 (CR), and 32 (Space). \code QString string = " lots\t of\nwhite space "; QString t = string.simplifyWhiteSpace(); // t == "lots of white space" \endcode \sa stripWhiteSpace() */ QString QString::simplifyWhiteSpace() const { if ( isEmpty() ) return *this; QString result; result.setLength( length() ); const QChar *from = unicode(); const QChar *fromend = from+length(); int outc=0; QChar *to = result.d->unicode; for (;;) { while ( from!=fromend && from->isSpace() ) from++; while ( from!=fromend && !from->isSpace() ) to[outc++] = *from++; if ( from!=fromend ) to[outc++] = ' '; else break; } if ( outc > 0 && to[outc-1] == ' ' ) outc--; result.truncate( outc ); return result; } /*! Inserts \a s into the string at position \a index. If \a index is beyond the end of the string, the string is extended with spaces to length \a index and \a s is then appended and returns a reference to the string. \code QString string( "I like fish" ); str = string.insert( 2, "don't " ); // str == "I don't like fish" \endcode \sa remove(), replace() */ QString &QString::insert( uint index, const QString &s ) { // the sub function takes care of &s == this case. return insert( index, s.unicode(), s.length() ); } /*! \overload - Inserts the character in \a s into the string at position \a index - \a len number of times and returns a reference to the string. + Inserts the first \a len characters in \a s into the string at + position \a index and returns a reference to the string. */ QString &QString::insert( uint index, const QChar* s, uint len ) { if ( len == 0 ) return *this; uint olen = length(); int nlen = olen + len; if ( s >= d->unicode && (uint)(s - d->unicode) < d->maxl ) { // Part of me - take a copy. QChar *tmp = QT_ALLOC_QCHAR_VEC( len ); memcpy(tmp,s,len*sizeof(QChar)); insert(index,tmp,len); QT_DELETE_QCHAR_VEC( tmp ); return *this; } if ( index >= olen ) { // insert after end of string setLength( len + index ); int n = index - olen; QChar* uc = d->unicode+olen; while (n--) *uc++ = ' '; memcpy( d->unicode+index, s, sizeof(QChar)*len ); } else { // normal insert setLength( nlen ); memmove( d->unicode + index + len, unicode() + index, sizeof(QChar) * (olen - index) ); memcpy( d->unicode + index, s, sizeof(QChar) * len ); } return *this; } /*! \overload Insert \a c into the string at position \a index and returns a reference to the string. If \a index is beyond the end of the string, the string is extended with spaces (ASCII 32) to length \a index and \a c is then appended. */ QString &QString::insert( uint index, QChar c ) // insert char { QString s( c ); return insert( index, s ); } /*! \fn QString& QString::insert( uint index, char c ) \overload Insert character \a c at position \a index. */ /*! \fn QString &QString::prepend( const QString &s ) Inserts \a s at the beginning of the string and returns a reference to the string. Equivalent to insert(0, \a s). \code QString string = "42"; string.prepend( "The answer is " ); // string == "The answer is 42" \endcode \sa insert() */ /*! \fn QString& QString::prepend( char ch ) \overload Inserts \a ch at the beginning of the string and returns a reference to the string. Equivalent to insert(0, \a ch). \sa insert() */ /*! \fn QString& QString::prepend( QChar ch ) \overload Inserts \a ch at the beginning of the string and returns a reference to the string. Equivalent to insert(0, \a ch). \sa insert() */ /*! \fn QString& QString::prepend( const QByteArray &s ) \overload Inserts \a s at the beginning of the string and returns a reference to the string. Equivalent to insert(0, \a s). \sa insert() */ +/*! \fn QString& QString::prepend( const std::string &s ) + \overload + + Inserts \a s at the beginning of the string and returns a reference to the string. + + Equivalent to insert(0, \a s). + + \sa insert() + */ + /*! \overload Inserts \a s at the beginning of the string and returns a reference to the string. Equivalent to insert(0, \a s). \sa insert() */ QString &QString::prepend( const char *s ) { return insert( 0, QString(s) ); } /*! Removes \a len characters from the string starting at position \a index, and returns a reference to the string. If \a index is beyond the length of the string, nothing happens. If \a index is within the string, but \a index + \a len is beyond the end of the string, the string is truncated at position \a index. \code QString string( "Montreal" ); string.remove( 1, 4 ); // string == "Meal" \endcode \sa insert(), replace() */ QString &QString::remove( uint index, uint len ) { uint olen = length(); if ( index >= olen ) { // range problems } else if ( index + len >= olen ) { // index ok setLength( index ); } else if ( len != 0 ) { real_detach(); memmove( d->unicode+index, d->unicode+index+len, sizeof(QChar)*(olen-index-len) ); setLength( olen-len ); } return *this; } /*! \overload Removes every occurrence of the character \a c in the string. Returns a reference to the string. This is the same as replace(\a c, ""). */ QString &QString::remove( QChar c ) { int i = 0; while ( i < (int) length() ) { if ( constref(i) == c ) { remove( i, 1 ); } else { i++; } } @@ -15787,383 +15825,391 @@ int QString::find( const QRegExp &rx, int index ) const \sa find() */ int QString::findRev( const QRegExp &rx, int index ) const { return rx.searchRev( *this, index ); } /*! \overload Returns the number of times the regexp, \a rx, matches in the string. This function counts overlapping matches, so in the example below, there are four instances of "ana" or "ama". \code QString str = "banana and panama"; QRegExp rxp = QRegExp( "a[nm]a", TRUE, FALSE ); int i = str.contains( rxp ); // i == 4 \endcode \sa find() findRev() */ int QString::contains( const QRegExp &rx ) const { int count = 0; int index = -1; int len = length(); while ( index < len - 1 ) { // count overlapping matches index = rx.search( *this, index + 1 ); if ( index == -1 ) break; count++; } return count; } #endif //QT_NO_REGEXP static bool ok_in_base( QChar c, int base ) { if ( base <= 10 ) return c.isDigit() && c.digitValue() < base; else return c.isDigit() || (c >= 'a' && c < char('a'+base-10)) || (c >= 'A' && c < char('A'+base-10)); } /*! Returns the string converted to a \c long value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \sa number() */ long QString::toLong( bool *ok, int base ) const { const QChar *p = unicode(); - long val = 0; + ulong val = 0; int l = length(); - const long max_mult = INT_MAX / base; + const ulong max_mult = LONG_MAX / base; bool is_ok = FALSE; int neg = 0; if ( !p ) goto bye; while ( l && p->isSpace() ) // skip leading space l--,p++; if ( !l ) goto bye; if ( *p == '-' ) { l--; p++; neg = 1; } else if ( *p == '+' ) { l--; p++; } // NOTE: toULong() code is similar if ( !l || !ok_in_base(*p,base) ) goto bye; while ( l && ok_in_base(*p,base) ) { l--; int dv; if ( p->isDigit() ) { dv = p->digitValue(); } else { if ( *p >= 'a' && *p <= 'z' ) dv = *p - 'a' + 10; else dv = *p - 'A' + 10; } if ( val > max_mult || - (val == max_mult && dv > (INT_MAX % base) + neg) ) + (val == max_mult && dv > (LONG_MAX % base) + neg) ) goto bye; val = base * val + dv; p++; } - if ( neg ) - val = -val; while ( l && p->isSpace() ) // skip trailing space - l--,p++; + l--, p++; if ( !l ) is_ok = TRUE; bye: if ( ok ) *ok = is_ok; - return is_ok ? val : 0; + return is_ok ? ( neg ? -( (long) val ) : (long) val ) : 0L; } /*! Returns the string converted to an \c {unsigned long} value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \sa number() */ ulong QString::toULong( bool *ok, int base ) const { const QChar *p = unicode(); ulong val = 0; int l = length(); - const ulong max_mult = UINT_MAX / base; + const ulong max_mult = ULONG_MAX / base; bool is_ok = FALSE; if ( !p ) goto bye; while ( l && p->isSpace() ) // skip leading space l--,p++; if ( !l ) goto bye; if ( *p == '+' ) l--,p++; // NOTE: toLong() code is similar if ( !l || !ok_in_base(*p,base) ) goto bye; while ( l && ok_in_base(*p,base) ) { l--; uint dv; if ( p->isDigit() ) { dv = p->digitValue(); } else { if ( *p >= 'a' && *p <= 'z' ) dv = *p - 'a' + 10; else dv = *p - 'A' + 10; } - if ( val > max_mult || (val == max_mult && dv > UINT_MAX % base) ) + if ( val > max_mult || (val == max_mult && dv > ULONG_MAX % base) ) goto bye; val = base * val + dv; p++; } while ( l && p->isSpace() ) // skip trailing space l--,p++; if ( !l ) is_ok = TRUE; bye: if ( ok ) *ok = is_ok; return is_ok ? val : 0; } /*! Returns the string converted to a \c short value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. */ short QString::toShort( bool *ok, int base ) const { long v = toLong( ok, base ); - if ( ok && *ok && (v < -32768 || v > 32767) ) { + if ( ok && *ok && (v < SHRT_MIN || v > SHRT_MAX) ) { *ok = FALSE; v = 0; } return (short)v; } /*! Returns the string converted to an \c {unsigned short} value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. */ ushort QString::toUShort( bool *ok, int base ) const { ulong v = toULong( ok, base ); - if ( ok && *ok && (v > 65535) ) { + if ( ok && *ok && (v > USHRT_MAX) ) { *ok = FALSE; v = 0; } return (ushort)v; } /*! Returns the string converted to an \c int value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \code QString str( "FF" ); bool ok; int hex = str.toInt( &ok, 16 ); // hex == 255, ok == TRUE int dec = str.toInt( &ok, 10 ); // dec == 0, ok == FALSE \endcode \sa number() */ int QString::toInt( bool *ok, int base ) const { - return (int)toLong( ok, base ); + long v = toLong( ok, base ); + if ( ok && *ok && (v < INT_MIN || v > INT_MAX) ) { + *ok = FALSE; + v = 0; + } + return (int)v; } /*! Returns the string converted to an \c{unsigned int} value to the base \a base, which is 10 by default and must be between 2 and 36. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \sa number() */ uint QString::toUInt( bool *ok, int base ) const { - return (uint)toULong( ok, base ); + ulong v = toULong( ok, base ); + if ( ok && *ok && (v > UINT_MAX) ) { + *ok = FALSE; + v = 0; + } + return (uint)v; } /*! Returns the string converted to a \c double value. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \code QString string( "1234.56" ); double a = string.toDouble(); // a == 1234.56 \endcode \sa number() */ double QString::toDouble( bool *ok ) const { char *end; const char *a = latin1(); double val = strtod( a ? a : "", &end ); if ( ok ) - *ok = ( a && *a && (end == 0 || (end - a) == (int)length()) ); + *ok = ( a && *a && (end == 0 || *end == '\0') ); return val; } /*! Returns the string converted to a \c float value. If \a ok is not 0: if a conversion error occurs, \a *ok is set to FALSE; otherwise \a *ok is set to TRUE. \sa number() */ float QString::toFloat( bool *ok ) const { return (float)toDouble( ok ); } /*! Sets the string to the printed value of \a n in base \a base and returns a reference to the string. The base is 10 by default and must be between 2 and 36. \code QString string; string = string.setNum( 1234 ); // string == "1234" \endcode */ QString &QString::setNum( long n, int base ) { #if defined(QT_CHECK_RANGE) if ( base < 2 || base > 36 ) { qWarning( "QString::setNum: Invalid base %d", base ); base = 10; } #endif char charbuf[65*sizeof(QChar)]; QChar *buf = (QChar*)charbuf; QChar *p = &buf[64]; int len = 0; bool neg; if ( n < 0 ) { neg = TRUE; - if ( n == INT_MIN ) { + if ( n == LONG_MIN ) { // Cannot always negate this special case QString s1, s2; - s1.setNum(n/base); - s2.setNum((-(n+base))%base); + s1.setNum(n/base, base ); + s2.setNum((-(n+base))%base, base ); *this = s1 + s2; return *this; } n = -n; } else { neg = FALSE; } do { *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; n /= base; ++len; } while ( n ); if ( neg ) { *--p = '-'; ++len; } return setUnicode( p, len ); } /*! \overload Sets the string to the printed value of \a n in base \a base and returns a reference to the string. The base is 10 by default and must be between 2 and 36. */ QString &QString::setNum( ulong n, int base ) { #if defined(QT_CHECK_RANGE) if ( base < 2 || base > 36 ) { qWarning( "QString::setNum: Invalid base %d", base ); base = 10; } #endif char charbuf[65*sizeof(QChar)]; QChar *buf = (QChar*)charbuf; QChar *p = &buf[64]; int len = 0; do { *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; n /= base; len++; } while ( n ); return setUnicode(p,len); } /*! \fn QString &QString::setNum( int n, int base ) \overload Sets the string to the printed value of \a n in base \a base and returns a reference to the string. The base is 10 by default and must be between 2 and 36. */ /*! \fn QString &QString::setNum( uint n, int base ) \overload @@ -16400,488 +16446,568 @@ void QString::setExpand( uint index, QChar c ) if ( name ) doSomethingWith(name); \endcode It will call "operator const char*()", which is inefficent; you may wish to define the macro \c QT_NO_ASCII_CAST when writing code which you wish to remain Unicode-clean. When you want the above semantics, use: \code QString name = getName(); if ( !name.isNull() ) doSomethingWith(name); \endcode \sa isEmpty() */ /*! \fn QString& QString::append( const QString& str ) Appends \a str to the string and returns a reference to the result. \code string = "Test"; string.append( "ing" ); // string == "Testing" \endcode Equivalent to operator+=(). */ /*! \fn QString& QString::append( char ch ) \overload Appends character \a ch to the string and returns a reference to the result. Equivalent to operator+=(). */ /*! \fn QString& QString::append( QChar ch ) \overload Appends character \a ch to the string and returns a reference to the result. Equivalent to operator+=(). */ /*! \fn QString& QString::append( const QByteArray &str ) \overload Appends \a str to the string and returns a reference to the result. Equivalent to operator+=(). */ +/*! \fn QString& QString::append( const std::string &str ) + \overload + + Appends \a str to the string and returns a reference to the result. + + Equivalent to operator+=(). + */ + + /*! \fn QString& QString::append( const char *str ) \overload Appends \a str to the string and returns a reference to the result. Equivalent to operator+=(). */ /*! Appends \a str to the string and returns a reference to the string. */ QString& QString::operator+=( const QString &str ) { uint len1 = length(); uint len2 = str.length(); if ( len2 ) { setLength(len1+len2); memcpy( d->unicode+len1, str.unicode(), sizeof(QChar)*len2 ); } else if ( isNull() && !str.isNull() ) { // ## just for 1.x compat: *this = fromLatin1( "" ); } return *this; } /*! \overload Appends \a str to the string and returns a reference to the string. */ +#ifndef QT_NO_CAST_ASCII QString& QString::operator+=( const char *str ) { if ( str ) { +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) + return operator+=( fromAscii( str ) ); +#endif + uint len1 = length(); uint len2 = strlen( str ); if ( len2 ) { setLength(len1+len2); uint i = 0; while( i < len2 ) { d->unicode[len1+i] = str[i]; i++; } } else if ( isNull() ) { // ## just for 1.x compat: *this = fromLatin1( "" ); } } return *this; } +#endif /*! \overload Appends \a c to the string and returns a reference to the string. */ QString &QString::operator+=( QChar c ) { setLength(length()+1); d->unicode[length()-1] = c; return *this; } /*! \overload Appends \a c to the string and returns a reference to the string. */ QString &QString::operator+=( char c ) { +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) + return operator+=( fromAscii( &c, 1 ) ); +#endif setLength(length()+1); d->unicode[length()-1] = c; return *this; } /*! \fn QString &QString::operator+=( const QByteArray &str ) \overload Appends \a str to the string and returns a reference to the string. */ +/*! + \fn QString &QString::operator+=( const std::string &str ) + \overload + + Appends \a str to the string and returns a reference to the string. +*/ + /*! \fn char QChar::latin1() const - Returns a latin-1 copy of this character, if this character is in - the latin-1 character set. If not, this function returns 0. + Returns the Latin-1 value of this character, or 0 if it + cannot be represented in Latin-1. */ /*! - Returns a Latin-1 representation of the string. Note that the + Returns a Latin-1 representation of the string. The returned value is undefined if the string contains non-Latin-1 characters. If you want to convert strings into formats other than Unicode, see the QTextCodec classes. This function is mainly useful for boot-strapping legacy code to use Unicode. The result remains valid so long as one unmodified copy of the source string exists. - \sa utf8(), local8Bit() + \sa fromLatin1(), ascii(), utf8(), local8Bit() */ const char* QString::latin1() const { - if ( !d->ascii ) { - Q2HELPER(stat_get_ascii++) - Q2HELPER(stat_get_ascii_size+=d->len) - d->ascii = unicodeToAscii( d->unicode, d->len ); + if ( !d->ascii || !d->islatin1 ) { + d->ascii = unicodeToLatin1( d->unicode, d->len ); + d->islatin1 = TRUE; } return d->ascii; } /*! - \fn const char* QString::ascii() const - \obsolete + Returns an 8-bit ASCII representation of the string. - This function simply calls latin1() and returns the result. + If a codec has been set using QTextCodec::codecForCStrings(), + it is used to convert Unicode to 8-bit char. Otherwise, this function + does the same as latin1(). + + \sa fromAscii(), latin1(), utf8(), local8Bit() */ +const char* QString::ascii() const +{ +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + if ( !d->ascii || d->islatin1 ) { + QCString s = QTextCodec::codecForCStrings()->fromUnicode( *this ); + s.detach(); + d->ascii = s.data(); + d->islatin1 = FALSE; + s.resetRawData( s.data(), s.size() ); // we have stolen the data + } + return d->ascii; + } +#endif // QT_NO_TEXTCODEC + return latin1(); +} /*! - Returns the string encoded in UTF8 format. + Returns the string encoded in UTF-8 format. See QTextCodec for more diverse coding/decoding of Unicode strings. - \sa QString::fromUtf8(), local8Bit(), latin1() + \sa fromUtf8(), ascii(), latin1(), local8Bit() */ QCString QString::utf8() const { int l = length(); int rlen = l*3+1; QCString rstr(rlen); uchar* cursor = (uchar*)rstr.data(); const QChar *ch = d->unicode; for (int i=0; i<l; i++) { ushort u = ch->unicode(); if ( u < 0x80 ) { *cursor++ = (uchar)u; } else { if ( u < 0x0800 ) { *cursor++ = 0xc0 | ((uchar) (u >> 6)); } else { *cursor++ = 0xe0 | ((uchar) (u >> 12)); *cursor++ = 0x80 | ( ((uchar) (u >> 6)) & 0x3f); } *cursor++ = 0x80 | ((uchar) (u&0x3f)); } ch++; } rstr.truncate( cursor - (uchar*)rstr.data() ); return rstr; } /*! Returns the Unicode string decoded from the first \a len characters of \a utf8, ignoring the rest of \a utf8. If \a len is -1 then the length of \a utf8 is used. If \a len is bigger than the length of \a utf8 then it will use the length of \a utf8. \code QString str = QString::fromUtf8( "123456789", 5 ); // str == "12345" \endcode See QTextCodec for more diverse coding/decoding of Unicode strings. */ QString QString::fromUtf8( const char* utf8, int len ) { if ( !utf8 ) return QString::null; - if ( len < 0 ) len = qstrlen( utf8 ); + if ( len < 0 ) + len = strlen( utf8 ); QString result; result.setLength( len ); // worst case QChar *qch = (QChar *)result.unicode(); ushort uc = 0; int need = 0; for (int i=0; i<len; i++) { uchar ch = utf8[i]; if (need) { if ( (ch&0xc0) == 0x80 ) { uc = (uc << 6) | (ch & 0x3f); need--; if ( !need ) { *qch = uc; qch++; } } else { // error *qch = QChar::replacement; qch++; need = 0; } } else { if ( ch < 128 ) { *qch = ch; qch++; } else if ( (ch&0xe0) == 0xc0 ) { uc = ch &0x1f; need = 1; } else if ( (ch&0xf0) == 0xe0 ) { uc = ch &0x0f; need = 2; } } } result.truncate( qch - result.unicode() ); return result; } /*! Returns the Unicode string decoded from the first \a len - characters of \a chars, ignoring the rest of \a chars. If \a len - is -1 then the length of \a chars is used. If \a len is bigger - than the length of \a chars then it will use the length of \a - chars. + characters of \a ascii, ignoring the rest of \a ascii. If \a len + is -1 then the length of \a ascii is used. If \a len is bigger + than the length of \a ascii then it will use the length of \a + ascii. + + If a codec has been set using QTextCodec::codecForCStrings(), + it is used to convert Unicode to 8-bit char. Otherwise, this function + does the same as fromLatin1(). This is the same as the QString(const char*) constructor, but you can make that constructor invisible if you compile with the define \c QT_NO_CAST_ASCII, in which case you can explicitly create a - QString from Latin-1 text using this function. + QString from 8-bit ASCII text using this function. \code - QString str = QString::fromLatin1( "123456789", 5 ); + QString str = QString::fromAscii( "123456789", 5 ); // str == "12345" \endcode + */ +QString QString::fromAscii( const char* ascii, int len ) +{ +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + if ( !ascii ) + return QString::null; + if ( len < 0 ) + len = strlen( ascii ); + if ( len == 0 || *ascii == '\0' ) + return QString::fromLatin1( "" ); + return QTextCodec::codecForCStrings()->toUnicode( ascii, len ); + } +#endif + return fromLatin1( ascii, len ); +} + + +/*! + Returns the Unicode string decoded from the first \a len + characters of \a chars, ignoring the rest of \a chars. If \a len + is -1 then the length of \a chars is used. If \a len is bigger + than the length of \a chars then it will use the length of \a + chars. + + \sa fromAscii() */ QString QString::fromLatin1( const char* chars, int len ) { uint l; QChar *uc; if ( len < 0 ) len = -1; - uc = internalAsciiToUnicode( chars, &l, len ); + uc = internalLatin1ToUnicode( chars, &l, len ); return QString( new QStringData(uc, l, l), TRUE ); } /*! \fn const QChar* QString::unicode() const Returns the Unicode representation of the string. The result remains valid until the string is modified. */ /*! Returns the string encoded in a locale-specific format. On X11, this is the QTextCodec::codecForLocale(). On Windows, it is a - system-defined encoding. On Mac OS X, this always uses utf8 as the - encoding. + system-defined encoding. On Mac OS X, this always uses UTF-8 as + the encoding. See QTextCodec for more diverse coding/decoding of Unicode strings. - \sa QString::fromLocal8Bit(), latin1(), utf8() + \sa fromLocal8Bit(), ascii(), latin1(), utf8() */ - QCString QString::local8Bit() const { #ifdef QT_NO_TEXTCODEC return latin1(); #else #ifdef Q_WS_X11 QTextCodec* codec = QTextCodec::codecForLocale(); return codec ? codec->fromUnicode(*this) : QCString(latin1()); #endif #if defined( Q_WS_MACX ) return utf8(); #endif #if defined( Q_WS_MAC9 ) return QCString(latin1()); //I'm evil.. #endif #ifdef Q_WS_WIN return qt_winQString2MB( *this ); #endif #ifdef Q_WS_QWS - return utf8(); // ##### if there is ANY 8 bit format supported? + return utf8(); // ### if there is any 8 bit format supported? #endif #endif } /*! Returns the Unicode string decoded from the first \a len characters of \a local8Bit, ignoring the rest of \a local8Bit. If \a len is -1 then the length of \a local8Bit is used. If \a len is bigger than the length of \a local8Bit then it will use the length of \a local8Bit. \code QString str = QString::fromLocal8Bit( "123456789", 5 ); // str == "12345" \endcode \a local8Bit is assumed to be encoded in a locale-specific format. See QTextCodec for more diverse coding/decoding of Unicode strings. */ QString QString::fromLocal8Bit( const char* local8Bit, int len ) { #ifdef QT_NO_TEXTCODEC return fromLatin1( local8Bit, len ); #else if ( !local8Bit ) return QString::null; #ifdef Q_WS_X11 QTextCodec* codec = QTextCodec::codecForLocale(); - if ( len < 0 ) len = qstrlen(local8Bit); + if ( len < 0 ) + len = strlen( local8Bit ); return codec ? codec->toUnicode( local8Bit, len ) : fromLatin1( local8Bit, len ); #endif #if defined( Q_WS_MAC ) return fromUtf8(local8Bit,len); #endif // Should this be OS_WIN32? #ifdef Q_WS_WIN if ( len >= 0 ) { QCString s(local8Bit,len+1); return qt_winMB2QString(s); } return qt_winMB2QString( local8Bit ); #endif #ifdef Q_WS_QWS return fromUtf8(local8Bit,len); #endif #endif // QT_NO_TEXTCODEC } /*! \fn QString::operator const char *() const Returns latin1(). Be sure to see the warnings documented in the latin1() function. Note that for new code which you wish to be strictly Unicode-clean, you can define the macro \c QT_NO_ASCII_CAST when compiling your code to hide this function so that automatic casts are not done. This has the added advantage that you catch the programming error described in operator!(). */ +/*! + \fn QString::operator std::string() const + + Returns ascii(). +*/ + /*! Returns the QString as a zero terminated array of unsigned shorts if the string is not null; otherwise returns zero. The result remains valid so long as one unmodified copy of the source string exists. */ const unsigned short *QString::ucs2() const { if ( ! d->unicode ) return 0; unsigned int len = d->len; if ( d->maxl < len + 1 ) { // detach, grow or shrink - Q2HELPER(stat_copy_on_write++) - Q2HELPER(stat_copy_on_write_size += len) uint newMax = computeNewMax( len + 1 ); QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); if ( nd ) { if ( d->unicode ) memcpy( nd, d->unicode, sizeof(QChar)*len ); ((QString *)this)->deref(); ((QString *)this)->d = new QStringData( nd, len, newMax ); } } d->unicode[len] = 0; return (unsigned short *) d->unicode; } /*! Constructs a string that is a deep copy of \a str, interpreted as a UCS2 encoded, zero terminated, Unicode string. If \a str is 0, then a null string is created. \sa isNull() */ QString QString::fromUcs2( const unsigned short *str ) { if ( !str ) { return QString::null; } else { int length = 0; while( str[length] != 0 ) length++; QChar* uc = QT_ALLOC_QCHAR_VEC( length ); memcpy( uc, str, length*sizeof(QChar) ); return QString( new QStringData( uc, length, length ), TRUE ); } } /*! \fn QChar QString::at( uint ) const Returns the character at index \a i, or 0 if \a i is beyond the length of the string. \code const QString string( "abcdefgh" ); QChar ch = string.at( 4 ); // ch == 'e' \endcode If the QString is not const (i.e. const QString) or const& (i.e. const QString &), then the non-const overload of at() will be used instead. */ /*! \fn QChar QString::constref(uint i) const Returns the QChar at index \a i by value. Equivalent to at(\a i). \sa ref() */ /*! \fn QChar& QString::ref(uint i) @@ -16922,206 +17048,226 @@ QString QString::fromUcs2( const unsigned short *str ) If \a i is beyond the length of the string then the string is expanded with QChar::nulls, so that the QCharRef references a valid (null) character in the string. The QCharRef internal class can be used much like a constant QChar, but if you assign to it, you change the original string (which will detach itself because of QString's copy-on-write semantics). You will get compilation errors if you try to use the result as anything but a QChar. */ /*! \fn QCharRef QString::at( uint i ) \overload The function returns a reference to the character at index \a i. The resulting reference can then be assigned to, or used immediately, but it will become invalid once further modifications are made to the original string. If \a i is beyond the length of the string then the string is expanded with QChar::null. */ /* Internal chunk of code to handle the uncommon cases of at() above. */ void QString::subat( uint i ) { uint olen = d->len; if ( i >= olen ) { setLength( i+1 ); // i is index; i+1 is needed length for ( uint j=olen; j<=i; j++ ) d->unicode[j] = QChar::null; } else { // Just be sure to detach real_detach(); } } /*! Resizes the string to \a len characters and copies \a unicode into the string. If \a unicode is 0, nothing is copied, but the string is still resized to \a len. If \a len is zero, then the string becomes a \link isNull() null\endlink string. \sa setLatin1(), isNull() */ QString& QString::setUnicode( const QChar *unicode, uint len ) { if ( len == 0 ) { // set to null string if ( d != shared_null ) { // beware of nullstring being set to nullstring deref(); d = shared_null ? shared_null : makeSharedNull(); d->ref(); } } else if ( d->count != 1 || len > d->maxl || ( len * 4 < d->maxl && d->maxl > 4 ) ) { // detach, grown or shrink - Q2HELPER(stat_copy_on_write++) - Q2HELPER(stat_copy_on_write_size+=d->len) uint newMax = computeNewMax( len ); QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); if ( unicode ) memcpy( nd, unicode, sizeof(QChar)*len ); deref(); d = new QStringData( nd, len, newMax ); } else { d->len = len; d->setDirty(); if ( unicode ) memcpy( d->unicode, unicode, sizeof(QChar)*len ); } return *this; } /*! Resizes the string to \a len characters and copies \a unicode_as_ushorts into the string (on some X11 client platforms this will involve a byte-swapping pass). If \a unicode_as_ushorts is 0, nothing is copied, but the string is still resized to \a len. If \a len is zero, the string becomes a \link isNull() null\endlink string. \sa setLatin1(), isNull() */ QString& QString::setUnicodeCodes( const ushort* unicode_as_ushorts, uint len ) { return setUnicode((const QChar*)unicode_as_ushorts, len); } /*! + Sets this string to \a str, interpreted as a classic 8-bit ASCII C + string. If \a len is -1 (the default), then it is set to + strlen(str). + + If \a str is 0 a null string is created. If \a str is "", an empty + string is created. + + \sa isNull(), isEmpty() +*/ + +QString &QString::setAscii( const char *str, int len ) +{ +#ifndef QT_NO_TEXTCODEC + if ( QTextCodec::codecForCStrings() ) { + *this = QString::fromAscii( str, len ); + return *this; + } +#endif // QT_NO_TEXTCODEC + return setLatin1( str, len ); +} + +/*! Sets this string to \a str, interpreted as a classic Latin1 C string. If \a len is -1 (the default), then it is set to strlen(str). If \a str is 0 a null string is created. If \a str is "", an empty string is created. \sa isNull(), isEmpty() */ QString &QString::setLatin1( const char *str, int len ) { if ( str == 0 ) return setUnicode(0,0); if ( len < 0 ) - len = qstrlen(str); + len = strlen( str ); if ( len == 0 ) { // won't make a null string *this = QString::fromLatin1( "" ); } else { setUnicode( 0, len ); // resize but not copy QChar *p = d->unicode; while ( len-- ) *p++ = *str++; } return *this; } /*! \internal */ void QString::checkSimpleText() const { QChar *p = d->unicode; QChar *end = p + d->len; - d->simpletext = 1; while( p < end ) { ushort uc = p->unicode(); // sort out regions of complex text formatting if ( uc > 0x058f && ( uc < 0x1100 || uc > 0xfb0f ) ) { - d->simpletext = 0; + d->issimpletext = FALSE; return; } p++; } + d->issimpletext = TRUE; } /*! \fn bool QString::simpleText() const \internal */ /*! \internal */ bool QString::isRightToLeft() const { int len = length(); QChar *p = d->unicode; while( len-- ) { switch( ::direction( *p ) ) { case QChar::DirL: case QChar::DirLRO: case QChar::DirLRE: return FALSE; case QChar::DirR: case QChar::DirAL: case QChar::DirRLO: case QChar::DirRLE: return TRUE; default: break; } ++p; } return FALSE; } /*! \fn int QString::compare( const QString & s1, const QString & s2 ) Lexically compares \a s1 with \a s2 and returns an integer less than, equal to, or greater than zero if \a s1 is less than, equal to, or greater than \a s2. The comparison is based exclusively on the numeric Unicode values of the characters and is very fast, but is not what a human would expect. Consider sorting user-interface strings with QString::localeAwareCompare(). \code int a = QString::compare( "def", "abc" ); // a > 0 int b = QString::compare( "abc", "def" ); // b < 0 int c = QString::compare(" abc", "abc" ); // c == 0 \endcode */ /*! \overload Lexically compares this string with \a s and returns an integer less than, equal to, or greater than zero if it is less than, equal to, or greater than \a s. */ int QString::compare( const QString& s ) const { return ucstrcmp( *this, s ); } diff --git a/qmake/tools/qtextstream.cpp b/qmake/tools/qtextstream.cpp index 75c6531..ddca5bd 100644 --- a/qmake/tools/qtextstream.cpp +++ b/qmake/tools/qtextstream.cpp @@ -1028,129 +1028,129 @@ void QTextStream::ts_ungetc( QChar c ) \warning The behavior of this function is undefined unless the stream's encoding is set to Unicode or Latin1. \sa QIODevice::readBlock() */ QTextStream &QTextStream::readRawBytes( char *s, uint len ) { dev->readBlock( s, len ); return *this; } /*! Writes the \a len bytes from \a s to the stream and returns a reference to the stream. Note that no encoding is done by this function. \sa QIODevice::writeBlock() */ QTextStream &QTextStream::writeRawBytes( const char* s, uint len ) { dev->writeBlock( s, len ); return *this; } QTextStream &QTextStream::writeBlock( const char* p, uint len ) { if ( doUnicodeHeader ) { doUnicodeHeader = FALSE; if ( !mapper && !latin1 ) ts_putc( QChar::byteOrderMark ); } // QCString and const char * are treated as Latin-1 if ( !mapper && latin1 ) { dev->writeBlock( p, len ); } else if ( !mapper && internalOrder ) { QChar *u = new QChar[len]; for ( uint i = 0; i < len; i++ ) u[i] = p[i]; dev->writeBlock( (char*)u, len * sizeof(QChar) ); delete [] u; } else { for ( uint i = 0; i < len; i++ ) ts_putc( (uchar)p[i] ); } return *this; } QTextStream &QTextStream::writeBlock( const QChar* p, uint len ) { #ifndef QT_NO_TEXTCODEC if ( mapper ) { if ( !d->encoder ) d->encoder = mapper->makeEncoder(); QConstString s( p, len ); int l = len; QCString block = d->encoder->fromUnicode( s.string(), l ); dev->writeBlock( block, l ); } else #endif if ( latin1 ) { - char *str = QString::unicodeToAscii( p, len ); + char *str = QString::unicodeToLatin1( p, len ); dev->writeBlock( str, len ); delete [] str; } else if ( internalOrder ) { if ( doUnicodeHeader ) { doUnicodeHeader = FALSE; ts_putc( QChar::byteOrderMark ); } dev->writeBlock( (char*)p, sizeof(QChar)*len ); } else { for (uint i=0; i<len; i++) ts_putc( p[i] ); } return *this; } /*! Resets the text stream. \list \i All flags are set to 0. \i The field width is set to 0. \i The fill character is set to ' ' (Space). \i The precision is set to 6. \endlist \sa setf(), width(), fill(), precision() */ void QTextStream::reset() { fflags = 0; fwidth = 0; fillchar = ' '; fprec = 6; } /*! \fn QIODevice *QTextStream::device() const Returns the IO device currently set. \sa setDevice(), unsetDevice() */ /*! Sets the IO device to \a iod. \sa device(), unsetDevice() */ void QTextStream::setDevice( QIODevice *iod ) { if ( owndev ) { delete dev; owndev = FALSE; } dev = iod; d->sourceType = QTextStreamPrivate::IODevice; } /*! Unsets the IO device. Equivalent to setDevice( 0 ). \sa device(), setDevice() diff --git a/qmake/tools/qucom.cpp b/qmake/tools/qucom.cpp index 6086a79..658da97 100644 --- a/qmake/tools/qucom.cpp +++ b/qmake/tools/qucom.cpp @@ -235,434 +235,310 @@ int QUType_idisp::serializeTo( QUObject *, QUBuffer * ) return 0; } int QUType_idisp::serializeFrom( QUObject *, QUBuffer * ) { return 0; } // {CA42115D-13D0-456c-82B5-FC10187F313E} const QUuid TID_QUType_bool( 0xca42115d, 0x13d0, 0x456c, 0x82, 0xb5, 0xfc, 0x10, 0x18, 0x7f, 0x31, 0x3e ); QUType_bool static_QUType_bool; const QUuid *QUType_bool::uuid() const { return &TID_QUType_bool; } const char *QUType_bool::desc() const { return "bool"; } void QUType_bool::set( QUObject *o, bool v ) { o->payload.b = v; o->type = this; } bool QUType_bool::canConvertFrom( QUObject *o, QUType *t ) { return t->canConvertTo( o, this ); } bool QUType_bool::canConvertTo( QUObject *, QUType * ) { return FALSE; } bool QUType_bool::convertFrom( QUObject *o, QUType *t ) { return t->convertTo( o, this ); } bool QUType_bool::convertTo( QUObject *, QUType * ) { return FALSE; } int QUType_bool::serializeTo( QUObject *, QUBuffer * ) { return 0; } int QUType_bool::serializeFrom( QUObject *, QUBuffer * ) { return 0; } // {53C1F3BE-73C3-4c7d-9E05-CCF09EB676B5} const QUuid TID_QUType_int( 0x53c1f3be, 0x73c3, 0x4c7d, 0x9e, 0x5, 0xcc, 0xf0, 0x9e, 0xb6, 0x76, 0xb5 ); QUType_int static_QUType_int; const QUuid *QUType_int::uuid() const { return &TID_QUType_int; } const char *QUType_int::desc() const { return "int"; } void QUType_int::set( QUObject *o, int v ) { o->payload.i = v; o->type = this; } bool QUType_int::canConvertFrom( QUObject *o, QUType *t ) { - if ( isEqual( t, &static_QUType_double ) || - isEqual( t, &static_QUType_float ) ) + if ( isEqual( t, &static_QUType_double ) ) return TRUE; return t->canConvertTo( o, this ); } bool QUType_int::canConvertTo( QUObject * /*o*/, QUType *t ) { - return isEqual( t, &static_QUType_double ) || - isEqual( t, &static_QUType_float ); + return isEqual( t, &static_QUType_double ); } bool QUType_int::convertFrom( QUObject *o, QUType *t ) { if ( isEqual( t, &static_QUType_double ) ) o->payload.i = (long)o->payload.d; - else if ( isEqual( t, &static_QUType_float ) ) - o->payload.i = (long)o->payload.f; else return t->convertTo( o, this ); o->type = this; return TRUE; } bool QUType_int::convertTo( QUObject *o, QUType *t ) { if ( isEqual( t, &static_QUType_double ) ) { o->payload.d = (double)o->payload.i; o->type = &static_QUType_double; - } else if ( isEqual( t, &static_QUType_float ) ) { - o->payload.f = (float)o->payload.i; - o->type = &static_QUType_float; } else return FALSE; return TRUE; } int QUType_int::serializeTo( QUObject *, QUBuffer * ) { return 0; } int QUType_int::serializeFrom( QUObject *, QUBuffer * ) { return 0; } -// {5938712A-C496-11D5-8CB2-00C0F03BC0F3} -const QUuid TID_QUType_uint( 0x5938712a, 0xc496, 0x11d5, 0x8c, 0xb2, 0x00, 0xc0, 0xf0, 0x3b, 0xc0, 0xf3); -QUType_uint static_QUType_uint; -const QUuid *QUType_uint::uuid() const { return &TID_QUType_uint; } -const char *QUType_uint::desc() const { return "uint"; } - -void QUType_uint::set( QUObject *o, uint v ) -{ - o->payload.ui = v; - o->type = this; -} - -bool QUType_uint::canConvertFrom( QUObject *o, QUType *t ) -{ - return t->canConvertTo( o, this ); -} - -bool QUType_uint::canConvertTo( QUObject * /*o*/, QUType * /*t*/ ) -{ - return FALSE; -} - -bool QUType_uint::convertFrom( QUObject *o, QUType *t ) -{ - return t->convertTo( o, this ); -} - -bool QUType_uint::convertTo( QUObject * /*o*/, QUType * /*t*/ ) -{ - return FALSE; -} - -int QUType_uint::serializeTo( QUObject *, QUBuffer * ) -{ - return 0; -} - -int QUType_uint::serializeFrom( QUObject *, QUBuffer * ) -{ - return 0; -} - // {2D0974E5-0BA6-4ec2-8837-C198972CB48C} const QUuid TID_QUType_double( 0x2d0974e5, 0xba6, 0x4ec2, 0x88, 0x37, 0xc1, 0x98, 0x97, 0x2c, 0xb4, 0x8c ); QUType_double static_QUType_double; const QUuid *QUType_double::uuid() const { return &TID_QUType_double; } const char *QUType_double::desc() const {return "double"; } void QUType_double::set( QUObject *o, double v ) { o->payload.d = v; o->type = this; } bool QUType_double::canConvertFrom( QUObject *o, QUType *t ) { - if ( isEqual( t, &static_QUType_int ) || - isEqual( t, &static_QUType_float) ) + if ( isEqual( t, &static_QUType_int ) ) return TRUE; return t->canConvertTo( o, this ); } bool QUType_double::canConvertTo( QUObject * /*o*/, QUType *t ) { - return isEqual( t, &static_QUType_int ) || - isEqual( t, &static_QUType_float ); + return isEqual( t, &static_QUType_int ); } bool QUType_double::convertFrom( QUObject *o, QUType *t ) { if ( isEqual( t, &static_QUType_int ) ) o->payload.d = (double)o->payload.i; - else if ( isEqual( t, &static_QUType_float ) ) - o->payload.d = (double)o->payload.f; - else + else return t->convertTo( o, this ); o->type = this; return TRUE; } bool QUType_double::convertTo( QUObject *o, QUType *t ) { if ( isEqual( t, &static_QUType_int ) ) { o->payload.i = (int) o->payload.d; o->type = &static_QUType_int; } else if ( isEqual( t, &static_QUType_double ) ) { o->payload.d = (double) o->payload.f; o->type = &static_QUType_double; } else return FALSE; return TRUE; } int QUType_double::serializeTo( QUObject *, QUBuffer * ) { return 0; } int QUType_double::serializeFrom( QUObject *, QUBuffer * ) { return 0; } - -// {544C5175-6993-4486-B04D-CEC4D21BF4B9 } -const QUuid TID_QUType_float( 0x544c5175, 0x6993, 0x4486, 0xb0, 0x4d, 0xce, 0xc4, 0xd2, 0x1b, 0xf4, 0xb9 ); -QUType_float static_QUType_float; -const QUuid *QUType_float::uuid() const { return &TID_QUType_float; } -const char *QUType_float::desc() const {return "float"; } - -void QUType_float::set( QUObject *o, float v ) -{ - o->payload.f = v; - o->type = this; -} - -bool QUType_float::canConvertFrom( QUObject *o, QUType *t ) -{ - if ( isEqual( t, &static_QUType_int ) || - isEqual( t, &static_QUType_double ) ) - return TRUE; - - return t->canConvertTo( o, this ); -} - -bool QUType_float::canConvertTo( QUObject * /*o*/, QUType *t ) -{ - return isEqual( t, &static_QUType_int ) || - isEqual( t, &static_QUType_double ); -} - -bool QUType_float::convertFrom( QUObject *o, QUType *t ) -{ - if ( isEqual( t, &static_QUType_int ) ) - o->payload.f = (float)o->payload.i; - else if ( isEqual( t, &static_QUType_double ) ) - o->payload.f = (float)o->payload.d; - else - return t->convertTo( o, this ); - - o->type = this; - return TRUE; -} - -bool QUType_float::convertTo( QUObject *o, QUType *t ) -{ - if ( isEqual( t, &static_QUType_int ) ) { - o->payload.i = (int) o->payload.f; - o->type = &static_QUType_int; - } else if ( isEqual( t, &static_QUType_double ) ) { - o->payload.d = (double) o->payload.f; - o->type = &static_QUType_double; - } else - return FALSE; - return TRUE; -} - -int QUType_float::serializeTo( QUObject *, QUBuffer * ) -{ - return 0; -} - -int QUType_float::serializeFrom( QUObject *, QUBuffer * ) -{ - return 0; -} - // {EFCDD1D4-77A3-4b8e-8D46-DC14B8D393E9} const QUuid TID_QUType_charstar( 0xefcdd1d4, 0x77a3, 0x4b8e, 0x8d, 0x46, 0xdc, 0x14, 0xb8, 0xd3, 0x93, 0xe9 ); QUType_charstar static_QUType_charstar; const QUuid *QUType_charstar::uuid() const { return &TID_QUType_charstar; } const char *QUType_charstar::desc() const { return "char*"; } void QUType_charstar::set( QUObject *o, const char* v, bool take ) { if ( take ) { if ( v ) { o->payload.charstar.ptr = new char[ strlen(v) + 1 ]; strcpy( o->payload.charstar.ptr, v ); } else { o->payload.charstar.ptr = 0; } o->payload.charstar.owner = TRUE; } else { o->payload.charstar.ptr = (char*) v; o->payload.charstar.owner = FALSE; } o->type = this; } bool QUType_charstar::canConvertFrom( QUObject *o, QUType *t ) { return t->canConvertTo( o, this ); } bool QUType_charstar::canConvertTo( QUObject *, QUType * ) { return FALSE; } bool QUType_charstar::convertFrom( QUObject *o, QUType *t ) { return t->convertTo( o, this ); } bool QUType_charstar::convertTo( QUObject *, QUType * ) { return FALSE; } void QUType_charstar::clear( QUObject *o ) { if ( o->payload.charstar.owner ) delete [] o->payload.charstar.ptr; o->payload.charstar.ptr = 0; } int QUType_charstar::serializeTo( QUObject *, QUBuffer * ) { return 0; } int QUType_charstar::serializeFrom( QUObject *, QUBuffer * ) { return 0; } // Qt specific types // {44C2A547-01E7-4e56-8559-35AF9D2F42B7} const QUuid TID_QUType_QString( 0x44c2a547, 0x1e7, 0x4e56, 0x85, 0x59, 0x35, 0xaf, 0x9d, 0x2f, 0x42, 0xb7 ); QUType_QString static_QUType_QString; const QUuid *QUType_QString::uuid() const { return &TID_QUType_QString; } const char *QUType_QString::desc() const { return "QString"; } void QUType_QString::set( QUObject *o, const QString& v ) { o->payload.ptr = new QString( v ); o->type = this; } bool QUType_QString::canConvertFrom( QUObject *o, QUType *t ) { if ( isEqual( t, &static_QUType_charstar ) || isEqual( t, &static_QUType_double ) || - isEqual( t, &static_QUType_float ) || isEqual( t, &static_QUType_int ) ) return TRUE; return t->canConvertTo( o, this ); } bool QUType_QString::canConvertTo( QUObject * /*o*/, QUType *t ) { return isEqual( t, &static_QUType_charstar ) || isEqual( t, &static_QUType_int ) || - isEqual( t, &static_QUType_double ) || - isEqual( t, &static_QUType_float ); + isEqual( t, &static_QUType_double ); } bool QUType_QString::convertFrom( QUObject *o, QUType *t ) { QString *str = 0; if ( isEqual( t, &static_QUType_charstar ) ) str = new QString( o->payload.charstar.ptr ); else if ( isEqual( t, &static_QUType_double ) ) str = new QString( QString::number( o->payload.d ) ); - else if ( isEqual( t, &static_QUType_float ) ) - str = new QString( QString::number( o->payload.f ) ); else if ( isEqual( t, &static_QUType_int ) ) str = new QString( QString::number( o->payload.i ) ); else return t->convertTo( o, this ); o->type->clear( o ); o->payload.ptr = str; o->type = this; return TRUE; } bool QUType_QString::convertTo( QUObject *o, QUType *t ) { QString *str = (QString *)o->payload.ptr; if ( isEqual( t, &static_QUType_charstar ) ) { o->payload.charstar.ptr = qstrdup( str->local8Bit().data() ); o->payload.charstar.owner = TRUE; o->type = &static_QUType_charstar; } else if ( isEqual( t, &static_QUType_int ) ) { o->payload.l = str->toLong(); o->type = &static_QUType_int; } else if ( isEqual( t, &static_QUType_double ) ) { o->payload.d = str->toDouble(); o->type = &static_QUType_double; - } else if ( isEqual( t, &static_QUType_float ) ) { - o->payload.d = str->toFloat(); - o->type = &static_QUType_float; } else { return FALSE; } delete str; return TRUE; } int QUType_QString::serializeTo( QUObject *, QUBuffer * ) { return 0; } int QUType_QString::serializeFrom( QUObject *, QUBuffer * ) { return 0; } void QUType_QString::clear( QUObject *o ) { delete (QString*)o->payload.ptr; o->payload.ptr = 0; } diff --git a/qmake/tools/qwaitcondition_unix.cpp b/qmake/tools/qwaitcondition_unix.cpp index 99c1014..6684617 100644 --- a/qmake/tools/qwaitcondition_unix.cpp +++ b/qmake/tools/qwaitcondition_unix.cpp @@ -63,248 +63,253 @@ struct QWaitConditionPrivate { \ingroup environment QWaitConditions allow a thread to tell other threads that some sort of condition has been met; one or many threads can block waiting for a QWaitCondition to set a condition with wakeOne() or wakeAll(). Use wakeOne() to wake one randomly selected event or wakeAll() to wake them all. For example, say we have three tasks that should be performed every time the user presses a key; each task could be split into a thread, each of which would have a run() body like this: \code QWaitCondition key_pressed; for (;;) { key_pressed.wait(); // This is a QWaitCondition global variable // Key was pressed, do something interesting do_something(); } \endcode A fourth thread would read key presses and wake the other three threads up every time it receives one, like this: \code QWaitCondition key_pressed; for (;;) { getchar(); // Causes any thread in key_pressed.wait() to return from // that method and continue processing key_pressed.wakeAll(); } \endcode Note that the order the three threads are woken up in is undefined, and that if some or all of the threads are still in do_something() when the key is pressed, they won't be woken up (since they're not waiting on the condition variable) and so the task will not be performed for that key press. This can be avoided by, for example, doing something like this: \code QMutex mymutex; QWaitCondition key_pressed; int mycount=0; // Worker thread code for (;;) { key_pressed.wait(); // This is a QWaitCondition global variable mymutex.lock(); mycount++; mymutex.unlock(); do_something(); mymutex.lock(); mycount--; mymutex.unlock(); } // Key reading thread code for (;;) { getchar(); mymutex.lock(); // Sleep until there are no busy worker threads - while( count > 0 ) { + while( mycount > 0 ) { mymutex.unlock(); sleep( 1 ); mymutex.lock(); } mymutex.unlock(); key_pressed.wakeAll(); } \endcode The mutexes are necessary because the results of two threads attempting to change the value of the same variable simultaneously are unpredictable. */ /*! Constructs a new event signalling, i.e. wait condition, object. */ QWaitCondition::QWaitCondition() { d = new QWaitConditionPrivate; int ret = pthread_cond_init(&d->cond, NULL); #ifdef QT_CHECK_RANGE if (ret) qWarning( "Wait condition init failure: %s", strerror( ret ) ); #endif } /*! Deletes the event signalling, i.e. wait condition, object. */ QWaitCondition::~QWaitCondition() { int ret = pthread_cond_destroy(&d->cond); if (ret) { #ifdef QT_CHECK_RANGE qWarning( "Wait condition destroy failure: %s", strerror( ret ) ); #endif // seems we have threads waiting on us, lets wake them up pthread_cond_broadcast(&d->cond); } delete d; } /*! This wakes one thread waiting on the QWaitCondition. The thread that is woken up depends on the operating system's scheduling policies, and cannot be controlled or predicted. \sa wakeAll() */ void QWaitCondition::wakeOne() { int ret = pthread_cond_signal(&d->cond); #ifdef QT_CHECK_RANGE if (ret) qWarning("Wait condition wakeOne failure: %s", strerror(ret)); #endif } /*! This wakes all threads waiting on the QWaitCondition. The order in which the threads are woken up depends on the operating system's scheduling policies, and cannot be controlled or predicted. \sa wakeOne() */ void QWaitCondition::wakeAll() { int ret = pthread_cond_broadcast(&d->cond); #ifdef QT_CHECK_RANGE if (ret) qWarning("Wait condition wakeAll failure: %s", strerror(ret)); #endif } /*! Wait on the thread event object. The thread calling this will block until either of these conditions is met: \list \i Another thread signals it using wakeOne() or wakeAll(). This function will return TRUE in this case. \i \a time milliseconds has elapsed. If \a time is ULONG_MAX (the default), then the wait will never timeout (the event must be signalled). This function will return FALSE if the wait timed out. \endlist \sa wakeOne(), wakeAll() */ bool QWaitCondition::wait(unsigned long time) { - pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t mutex; + pthread_mutex_init( &mutex, 0 ); + pthread_mutex_lock( &mutex ); int ret; if (time != ULONG_MAX) { struct timeval tv; gettimeofday(&tv, 0); timespec ti; - ti.tv_nsec = (tv.tv_usec * 1000) + (time % 1000) * 1000; + ti.tv_nsec = ( tv.tv_usec + ( time % 1000 ) * 1000 ) * 1000; ti.tv_sec = tv.tv_sec + (time / 1000) + ( ti.tv_nsec / 1000000000 ); ti.tv_nsec %= 1000000000; ret = pthread_cond_timedwait(&d->cond, &mutex, &ti); } else ret = pthread_cond_wait(&d->cond, &mutex); #ifdef QT_CHECK_RANGE if (ret && ret != ETIMEDOUT) qWarning("Wait condition wait failure: %s",strerror(ret)); #endif + pthread_mutex_unlock( &mutex ); + pthread_mutex_destroy( &mutex ); + return (ret == 0); } /*! \overload Release the locked \a mutex and wait on the thread event object. The \a mutex must be initially locked by the calling thread. If \a mutex is not in a locked state, this function returns immediately. If \a mutex is a recursive mutex, this function returns immediately. The \a mutex will be unlocked, and the calling thread will block until either of these conditions is met: \list \i Another thread signals it using wakeOne() or wakeAll(). This function will return TRUE in this case. \i \a time milliseconds has elapsed. If \a time is ULONG_MAX (the default), then the wait will never timeout (the event must be signalled). This function will return FALSE if the wait timed out. \endlist The mutex will be returned to the same locked state. This function is provided to allow the atomic transition from the locked state to the wait state. \sa wakeOne(), wakeAll() */ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (! mutex) return FALSE; if (mutex->d->type() == Q_MUTEX_RECURSIVE) { #ifdef QT_CHECK_RANGE qWarning("Wait condition warning: using recursive mutexes with\n" " wait conditions is undefined!"); #endif return FALSE; } int ret; if (time != ULONG_MAX) { struct timeval tv; gettimeofday(&tv, 0); timespec ti; - ti.tv_nsec = (tv.tv_usec * 1000) + (time % 1000) * 1000; + ti.tv_nsec = ( tv.tv_usec + ( time % 1000 ) * 1000 ) * 1000; ti.tv_sec = tv.tv_sec + (time / 1000) + ( ti.tv_nsec / 1000000000 ); ti.tv_nsec %= 1000000000; ret = pthread_cond_timedwait(&d->cond, &mutex->d->handle, &ti); } else ret = pthread_cond_wait(&d->cond, &mutex->d->handle); #ifdef QT_CHECK_RANGE if (ret && ret != ETIMEDOUT) qWarning("Wait condition wait failure: %s",strerror(ret)); #endif return (ret == 0); } #endif // QT_THREAD_SUPPORT |