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 @@ -104,193 +104,194 @@ Example: \code QBitArray a(3); a.setBit( 0 ); a.clearBit( 1 ); a.setBit( 2 ); // a = [1 0 1] QBitArray b(3); b[0] = 1; b[1] = 1; b[2] = 0; // b = [1 1 0] QBitArray c; c = ~a & b; // c = [0 1 0] \endcode When a QBitArray is constructed the bits are uninitialized. Use fill() to set all the bits to 0 or 1. The array can be resized with resize() and copied with copy(). Bits can be set with setBit() and cleared with clearBit(). Bits can be toggled with toggleBit(). A bit's value can be obtained with testBit() and with at(). QBitArray supports the \& (AND), | (OR), ^ (XOR) and ~ (NOT) operators. */ /*! \class QBitArray::bitarr_data \brief The QBitArray::bitarr_data class is internal. \internal */ /*! 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; this->duplicate( *this ); SHBLOCK->nbits = nbits; } /*! Returns a deep copy of the bit array. \sa detach() */ QBitArray QBitArray::copy() const { QBitArray tmp; tmp.duplicate( *this ); ((bitarr_data*)(tmp.sharedBlock()))->nbits = SHBLOCK->nbits; return tmp; } /*! Returns TRUE if the bit at position \a index is set, i.e. is 1; otherwise returns FALSE. \sa setBit(), clearBit() */ bool QBitArray::testBit( uint index ) const { #if defined(QT_CHECK_RANGE) if ( index >= size() ) { qWarning( "QBitArray::testBit: Index %d out of range", index ); return FALSE; 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 @@ -103,194 +103,194 @@ QBuffer::QBuffer() QCString str = "abc"; QBuffer b( str ); b.open( IO_WriteOnly ); b.at( 3 ); // position at the 4th character (the terminating \0) b.writeBlock( "def", 4 ); // write "def" including the terminating \0 b.close(); // Now, str == "abcdef" with a terminating \0 \endcode \sa setBuffer() */ QBuffer::QBuffer( QByteArray buf ) : a(buf) { setFlags( IO_Direct ); a_len = a.size(); a_inc = (a_len > 512) ? 512 : a_len; // initial increment if ( a_inc < 16 ) a_inc = 16; ioIndex = 0; } /*! Destroys the buffer. */ 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; } #endif if ( pos > a_len ) { #if defined(QT_CHECK_RANGE) #if defined(QT_LARGEFILE_SUPPORT) && defined(QT_ABI_64BITOFFSET) qWarning( "QBuffer::at: Index %llu out of range", pos ); #else qWarning( "QBuffer::at: Index %lu out of range", pos ); #endif #endif return FALSE; } ioIndex = pos; return TRUE; } /*! \reimp */ Q_LONG QBuffer::readBlock( char *p, Q_ULONG len ) { #if defined(QT_CHECK_STATE) if ( !p ) { qWarning( "QBuffer::readBlock: Null pointer error" ); return -1; } if ( !isOpen() ) { // buffer not open qWarning( "QBuffer::readBlock: Buffer not open" ); return -1; } if ( !isReadable() ) { // reading not permitted 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 @@ -1,161 +1,165 @@ /**************************************************************************** ** $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 ) { results.fill( 0 ); lengths.fill( 0 ); } const char *fields; const ulong field_count; QMemArray<const char *> results; QMemArray<ulong> lengths; }; /* return values: 1 parse ok 0 eos -1 parse error */ static int qt_tokenize( const char *s, ulong s_len, ulong *advance, const qt_token_info &token_info ) { ulong pos = 0, field = 0, fieldlen = 0; char current; int ret = -1; *advance = 0; for (;;) { current = s[ pos ]; // next char ++pos; ++fieldlen; ++*advance; @@ -298,241 +302,234 @@ static long qt_find_pattern( const char *s, ulong s_len, break; --i; hs -= s[i + p_len]; hs += s[i]; } return -1; } /* This opens the specified library, mmaps it into memory, and searches for the QT_UCM_VERIFICATION_DATA. The advantage of this approach is that we can get the verification data without have to actually load the library. This lets us detect mismatches more safely. Returns FALSE if version/flags/key information is not present, or if the information could not be read. Returns TRUE if version/flags/key information is present and succesfully read. */ static bool qt_unix_query( const QString &library, uint *version, uint *flags, QCString *key ) { QFile file( library ); if (! file.open( IO_ReadOnly ) ) { qWarning( "%s: %s", (const char*) QFile::encodeName(library), strerror( errno ) ); return FALSE; } QByteArray data; char *filedata = 0; ulong fdlen = 0; #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 ) createInstanceInternal(); return entry ? qt_version : 0; } #endif // QT_NO_COMPONENT 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,75 +1,73 @@ /**************************************************************************** ** $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() { LeaveCriticalSection( &d->section ); } #endif 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 @@ -48,444 +48,474 @@ #include <stdarg.h> #include <stdlib.h> #include <ctype.h> #include <limits.h> #ifndef QT_NO_COMPRESS #include "../3rdparty/zlib/zlib.h" #endif /***************************************************************************** Safe and portable C string functions; extensions to standard string.h *****************************************************************************/ /*! \relates QCString This function is normally part of the C library. Qt implements memmove() for platforms that do not provide it. memmove() copies \a len bytes from \a src into \a dst. The data is copied correctly even if \a src and \a dst overlap. */ void *qmemmove( void *dst, const void *src, uint len ) { register char *d; register char *s; if ( dst > src ) { d = (char *)dst + len - 1; s = (char *)src + len - 1; while ( len-- ) *d-- = *s--; } else if ( dst < src ) { d = (char *)dst; s = (char *)src; while ( len-- ) *d++ = *s++; } return dst; } /*! \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; register const uchar *s2 = (const uchar *)str2; int res; uchar c; if ( !s1 || !s2 ) return s1 ? 1 : ( s2 ? -1 : 0 ); for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) if ( !c ) // strings are equal break; return res; } /*! \relates QCString A safe strnicmp() function. Compares at most \a len bytes of \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() qstricmp() \link #asciinotion Note on character comparisons \endlink */ 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. \ingroup collection \ingroup tools The QByteArray class provides an explicitly shared array of bytes. It is useful for manipulating memory areas with custom data. QByteArray is implemented as a QMemArray\<char\>. See the \l QMemArray documentation for further information. */ /*! \fn QByteArray::QByteArray() Constructs an empty QByteArray. */ /*! \fn QByteArray::QByteArray( int size ) Constructs a QByteArray of size \a size. */ /***************************************************************************** QByteArray stream functions *****************************************************************************/ /*! \relates QMemArray Writes byte array \a a to the stream \a s and returns a reference to the stream. \sa \link datastreamformat.html Format of the QDataStream operators \endlink @@ -843,199 +873,203 @@ QCString &QCString::sprintf( const char *format, ... ) { detach(); va_list ap; va_start( ap, format ); if ( size() < 256 ) QByteArray::resize( 256 ); // make string big enough vsprintf( data(), format, ap ); resize( qstrlen(data()) + 1 ); // truncate va_end( ap ); return *this; } /*! Fills the string with \a len bytes of character \a c, followed by a '\0'-terminator. If \a len is negative, then the current string length is used. Returns FALSE is \a len is nonnegative and there is not enough memory to resize the string; otherwise returns TRUE. */ bool QCString::fill( char c, int len ) { detach(); if ( len < 0 ) len = length(); if ( !QByteArray::fill(c,len+1) ) return FALSE; *(data()+len) = '\0'; return TRUE; } /*! \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. \sa \link #asciinotion Note on character comparisons \endlink */ int QCString::findRev( char c, int index, bool cs ) const { register const char *b = data(); register const char *d; if ( index < 0 ) index = length(); if ( (uint)index >= size() ) return -1; d = b + index; if ( cs ) { while ( d >= b && *d != c ) d--; } else { c = tolower( (uchar) c ); while ( d >= b && tolower((uchar) *d) != c ) d--; } return d >= b ? (int)(d - b) : -1; } /*! \overload Finds the first occurrence of the string \a str, 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. @@ -1059,214 +1093,214 @@ int QCString::findRev( const char *str, int index, bool cs ) const return -1; if ( index > delta ) index = delta; if ( sl == 1 ) return findRev( *str, index, cs ); const char* needle = str; const char* haystack = data() + index; const char* end = data(); const uint sl_minus_1 = sl-1; const char* n = needle+sl_minus_1; const char* h = haystack+sl_minus_1; uint hashNeedle = 0, hashHaystack = 0, i; if ( cs ) { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + *(n-i) ); hashHaystack = ((hashHaystack<<1) + *(h-i) ); } hashHaystack -= *haystack; while ( haystack >= end ) { hashHaystack += *haystack; if ( hashHaystack == hashNeedle && qstrncmp( needle, haystack, sl ) == 0 ) return haystack-data(); --haystack; REHASH( *(haystack+sl) ); } } else { for ( i = 0; i < sl; ++i ) { hashNeedle = ((hashNeedle<<1) + tolower( *(n-i) ) ); hashHaystack = ((hashHaystack<<1) + tolower( *(h-i) ) ); } 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 { uint slen = qstrlen( data() ); if ( isEmpty() || index >= slen ) { QCString empty; return empty; } else { if ( len > slen-index ) len = slen - index; register char *p = data()+index; QCString s( len+1 ); strncpy( s.data(), p, len ); *(s.data()+len) = '\0'; return s; } } /*! Returns a string of length \a width (plus one for the terminating '\0') that contains this string padded with the \a fill character. If the length of the string exceeds \a width and \a truncate is FALSE (the default), then the returned string is a copy of the string. If the length of the string exceeds \a width and \a truncate is TRUE, then the returned string is a left(\a width). Example: \code QCString s("apple"); QCString t = s.leftJustify(8, '.'); // t == "apple..." \endcode \sa rightJustify() @@ -1404,535 +1438,538 @@ QCString QCString::stripWhiteSpace() const if ( isEmpty() ) // nothing to do return copy(); register char *s = data(); QCString result = s; int reslen = result.length(); if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) ) return result; // returns a copy s = result.data(); int start = 0; int end = reslen - 1; while ( isspace((uchar) s[start]) ) // skip white space from start start++; if ( s[start] == '\0' ) { // only white space result.resize( 1 ); return result; } while ( end && isspace((uchar) s[end]) ) // skip white space from end end--; end -= start - 1; memmove( result.data(), &s[start], end ); result.resize( end + 1 ); return result; } /*! Returns a new string that has white space removed from the start and the end, plus any sequence of internal white space replaced with a single space (ASCII 32). 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; if ( !p ) goto bye; while ( isspace((uchar) *p) ) // skip leading space p++; if ( *p == '+' ) p++; if ( !isdigit((uchar) *p) ) goto bye; while ( isdigit((uchar) *p) ) { if ( val > max_mult || (val == max_mult && (*p-'0') > 5) ) goto bye; val = 10*val + (*p++ - '0'); } 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 a \c{short} value. If \a ok is not 0: \a *ok is set to FALSE if the string is not a number, is out of range, or if it has trailing garbage; otherwise \a *ok is set to TRUE. */ short QCString::toShort( bool *ok ) const @@ -2106,209 +2143,209 @@ QCString &QCString::setNum( ulong n ) /*! \overload QCString &QCString::setNum( ushort n ) Sets the string to the string representation of the number \a n and returns a reference to the string. */ /*! Sets the string to the string representation of the number \a n and returns a reference to the string. The format of the string representation is specified by the format character \a f, and the precision (number of digits after the decimal point) is specified with \a prec. The valid formats for \a f are 'e', 'E', 'f', 'g' and 'G'. The formats are the same as for sprintf(); they are explained in \l QString::arg(). */ QCString &QCString::setNum( double n, char f, int prec ) { #if defined(QT_CHECK_RANGE) if ( !(f=='f' || f=='F' || f=='e' || f=='E' || f=='g' || f=='G') ) qWarning( "QCString::setNum: Invalid format char '%c'", f ); #endif char format[20]; register char *fs = format; // generate format string *fs++ = '%'; // "%.<prec>l<f>" if ( prec > 99 ) prec = 99; *fs++ = '.'; 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. */ /*! \overload bool operator==( const QCString &s1, const char *s2 ) \relates QCString Returns TRUE if \a s1 and \a s2 are equal; otherwise returns FALSE. Equivalent to qstrcmp(\a s1, \a s2) == 0. */ /*! \overload bool operator==( const char *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. */ /*! \fn bool operator!=( const QCString &s1, const QCString &s2 ) \relates QCString Returns TRUE if \a s1 and \a s2 are different; 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 @@ -657,194 +657,202 @@ QDataStream &QDataStream::operator>>( float &f ) Reads a 64-bit floating point number from the stream into \a f, using the standard IEEE754 format. Returns a reference to the stream. */ QDataStream &QDataStream::operator>>( double &f ) { CHECK_STREAM_PRECOND if ( printable ) { // printable data f = read_double_ascii( this ); } else if ( noswap ) { // no conversion needed dev->readBlock( (char *)&f, sizeof(double) ); } else { // swap bytes register uchar *p = (uchar *)(&f); char b[8]; dev->readBlock( b, 8 ); *p++ = b[7]; *p++ = b[6]; *p++ = b[5]; *p++ = b[4]; *p++ = b[3]; *p++ = b[2]; *p++ = b[1]; *p = b[0]; } return *this; } /*! \overload 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 dev->writeBlock( (char *)&i, sizeof(Q_INT16) ); } else { // swap bytes register uchar *p = (uchar *)(&i); char b[2]; b[1] = *p++; b[0] = *p; dev->writeBlock( b, 2 ); } return *this; } /*! \overload Writes a signed 32-bit integer, \a i, to the stream and returns a reference to the stream. */ QDataStream &QDataStream::operator<<( Q_INT32 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 dev->writeBlock( (char *)&i, sizeof(Q_INT32) ); } else { // swap bytes register uchar *p = (uchar *)(&i); char b[4]; b[3] = *p++; b[2] = *p++; @@ -919,106 +927,112 @@ QDataStream &QDataStream::operator<<( float f ) b[3] = *p++; b[2] = *p++; b[1] = *p++; b[0] = *p; dev->writeBlock( b, 4 ); } } return *this; } /*! \overload Writes a 64-bit floating point number, \a f, to the stream using the standard IEEE754 format. Returns a reference to the stream. */ QDataStream &QDataStream::operator<<( double f ) { CHECK_STREAM_PRECOND if ( printable ) { // printable data char buf[32]; sprintf( buf, "%g\n", f ); dev->writeBlock( buf, strlen(buf) ); } else if ( noswap ) { // no conversion needed dev->writeBlock( (char *)&f, sizeof(double) ); } else { // swap bytes register uchar *p = (uchar *)(&f); char b[8]; b[7] = *p++; b[6] = *p++; 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,134 +1,133 @@ /**************************************************************************** ** $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" ) { buf = QString::number( dt->second() ); } else if ( f == "ss" ) { buf = QString::number( dt->second() ).rightJustify( 2, '0', TRUE ); } else if ( f == "z" ) { buf = QString::number( dt->msec() ); } else if ( f == "zzz" ) { buf = QString::number( dt->msec() ).rightJustify( 3, '0', TRUE ); } else if ( f == "ap" ) { buf = dt->hour() < 12 ? "am" : "pm"; } else if ( f == "AP" ) { buf = dt->hour() < 12 ? "AM" : "PM"; } } if ( dd ) { if ( f == "d" ) { buf = QString::number( dd->day() ); } else if ( f == "dd" ) { buf = QString::number( dd->day() ).rightJustify( 2, '0', TRUE ); } else if ( f == "M" ) { buf = QString::number( dd->month() ); } else if ( f == "MM" ) { buf = QString::number( dd->month() ).rightJustify( 2, '0', TRUE ); #ifndef QT_NO_TEXTDATE } else if ( f == "ddd" ) { buf = dd->shortDayName( dd->dayOfWeek() ); } else if ( f == "dddd" ) { buf = dd->longDayName( dd->dayOfWeek() ); } else if ( f == "MMM" ) { buf = dd->shortMonthName( dd->month() ); } else if ( f == "MMMM" ) { buf = dd->longMonthName( dd->month() ); @@ -802,294 +801,312 @@ QString QDate::toString( const QString& format ) const \warning If \a y is in the range 0..99, it is interpreted as 1900..1999. Returns TRUE if the date is valid; otherwise returns FALSE. */ bool QDate::setYMD( int y, int m, int d ) { if ( year() == y && month() == m && day() == d ) return isValid(); if ( !isValid(y,m,d) ) { #if defined(QT_CHECK_RANGE) qWarning( "QDate::setYMD: Invalid date %04d-%02d-%02d", y, m, d ); #endif return FALSE; } jd = gregorianToJulian( y, m, d ); return TRUE; } /*! Returns a QDate object containing a date \a ndays later than the date of this object (or earlier if \a ndays is negative). \sa addMonths() addYears() daysTo() */ QDate QDate::addDays( int ndays ) const { QDate d; d.jd = jd + ndays; 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; } } } #if defined(QT_CHECK_RANGE) if ( month < 1 || month > 12 ) { qWarning( "QDate::fromString: Parameter out of range." ); month = 1; } #endif int day = s.mid( dayPos, 2 ).stripWhiteSpace().toInt(); int year = s.right( 4 ).toInt(); return QDate( year, month, day ); } #else break; #endif } return QDate(); } #endif //QT_NO_DATESTRING /*! \overload Returns TRUE if the specified date (year \a y, month \a m and day \a d) is valid; otherwise returns FALSE. Example: \code QDate::isValid( 2002, 5, 17 ); // TRUE May 17th 2002 is valid QDate::isValid( 2002, 2, 30 ); // FALSE Feb 30th does not exist QDate::isValid( 2004, 2, 29 ); // TRUE 2004 is a leap year QDate::isValid( 1202, 6, 6 ); // FALSE 1202 is pre-Gregorian \endcode @@ -1462,346 +1479,357 @@ QTime QTime::addSecs( int nsecs ) const /*! Returns the number of seconds 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 86400. \sa addSecs() QDateTime::secsTo() */ int QTime::secsTo( const QTime &t ) const { return ((int)t.ds - (int)ds)/1000; } /*! Returns a QTime object containing a time \a ms milliseconds later than the time of this object (or earlier if \a ms is negative). Note that the time will wrap if it passes midnight. See addSecs() for an example. \sa addSecs(), msecsTo() */ QTime QTime::addMSecs( int ms ) const { QTime t; if ( ms < 0 ) { // % not well-defined for -ve, but / is. int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY; 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; } /***************************************************************************** QDateTime member functions *****************************************************************************/ /*! \class QDateTime qdatetime.h \reentrant \brief The QDateTime class provides date and time functions. \ingroup time \mainclass A QDateTime object contains a calendar date and a clock time (a "datetime"). It is a combination of the QDate and QTime classes. It can read the current datetime from the system clock. It provides functions for comparing datetimes and for manipulating a datetime by adding a number of seconds, days, months or years. A QDateTime object is typically created either by giving a date and time explicitly in the constructor, or by using the static function currentDateTime(), which returns a QDateTime object set to the system clock's time. The date and time can be changed with setDate() and setTime(). A datetime can also be set using the setTime_t() function, which takes a POSIX-standard "number of seconds since 00:00:00 on January 1, 1970" value. The fromString() function returns a QDateTime given a string and a date format which is used to interpret the date within the string. The date() and time() functions provide access to the date and @@ -1867,202 +1895,220 @@ QDateTime::QDateTime( const QDate &date, const QTime &time ) /*! \fn bool QDateTime::isValid() const Returns TRUE if both the date and the time are valid; otherwise returns FALSE. \sa QDate::isValid(), QTime::isValid() */ /*! \fn QDate QDateTime::date() const Returns the date part of the datetime. \sa setDate(), time() */ /*! \fn QTime QDateTime::time() const Returns the time part of the datetime. \sa setTime(), date() */ /*! \fn void QDateTime::setDate( const QDate &date ) Sets the date part of this datetime to \a date. \sa date(), setTime() */ /*! \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() ) + " "; break; } #endif buf += t.toString(); buf += ' '; buf += QString().setNum( d.year() ); return buf; } #endif else if ( f == Qt::LocalDate ) { return d.toString( Qt::LocalDate ) + " " + t.toString( Qt::LocalDate ); } return QString::null; } #endif /*! Returns the datetime as a string. The \a format parameter determines the format of the result string. These expressions may be used for the date: \table \header \i Expression \i Output \row \i d \i the day as number without a leading zero (1-31) \row \i dd \i the day as number with a leading zero (01-31) \row \i ddd \i the abbreviated localized day name (e.g. 'Mon'..'Sun'). Uses QDate::shortDayName(). \row \i dddd \i the long localized day name (e.g. 'Monday'..'Sunday'). Uses QDate::longDayName(). @@ -2207,193 +2253,193 @@ int QDateTime::daysTo( const QDateTime &dt ) const return d.daysTo( dt.d ); } /*! Returns the number of seconds from this datetime to \a dt (which is negative if \a dt is earlier than this datetime). Example: \code QDateTime dt = QDateTime::currentDateTime(); QDateTime xmas( QDate(dt.year(),12,24), QTime(17,00) ); qDebug( "There are %d seconds to Christmas", dt.secsTo(xmas) ); \endcode \sa addSecs(), daysTo(), QTime::secsTo() */ int QDateTime::secsTo( const QDateTime &dt ) const { return t.secsTo(dt.t) + d.daysTo(dt.d)*SECS_PER_DAY; } /*! Returns TRUE if this datetime is equal to \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 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 ) { for ( int i = 1; i <= 12; ++i ) { if ( monthName == QDate::shortMonthName( i ) ) { month = i; break; } } } #if defined(QT_CHECK_RANGE) if ( month < 1 || month > 12 ) { qWarning( "QDateTime::fromString: Parameter out of range." ); month = 1; } #endif int day = s.mid( 8, 2 ).simplifyWhiteSpace().toInt(); int year = s.right( 4 ).toInt(); QDate date( year, month, day ); QTime time; int hour, minute, second; int pivot = s.find( QRegExp("[0-9][0-9]:[0-9][0-9]:[0-9][0-9]") ); if ( pivot != -1 ) { hour = s.mid( pivot, 2 ).toInt(); minute = s.mid( pivot+3, 2 ).toInt(); second = s.mid( pivot+6, 2 ).toInt(); time.setHMS( hour, minute, second ); } return QDateTime( date, time ); } #endif //QT_NO_REGEXP return QDateTime(); } #endif //QT_NO_DATESTRING 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,484 +1,523 @@ /**************************************************************************** ** $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: See if a directory exists. \code QDir d( "example" ); // "./example" if ( !d.exists() ) qWarning( "Cannot find the example directory" ); \endcode Traversing directories and reading a file. \code QDir d = QDir::root(); // "/" if ( !d.cd("tmp") ) { // "/tmp" qWarning( "Cannot find the \"/tmp\" directory" ); } else { QFile f( d.filePath("ex1.txt") ); // "/tmp/ex1.txt" if ( !f.open(IO_ReadWrite) ) qWarning( "Cannot create the file %s", f.name() ); } \endcode A program that lists all the files in the current directory (excluding symbolic links), sorted by size, smallest first: \code #include <stdio.h> #include <qdir.h> int main( int argc, char **argv ) { QDir d; d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); d.setSorting( QDir::Size | QDir::Reversed ); const QFileInfoList *list = d.entryInfoList(); QFileInfoListIterator it( *list ); QFileInfo *fi; printf( " Bytes Filename\n" ); while ( (fi = it.current()) != 0 ) { printf( "%10li %s\n", fi->size(), fi->fileName().latin1() ); ++it; } return 0; } \endcode */ /*! Constructs a QDir pointing to the current directory. \sa currentDirPath() */ 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. \sa setPath(), canonicalPath(), exists(), cleanDirPath(), dirName(), absFilePath() */ QString QDir::absPath() const { if ( QDir::isRelativePath(dPath) ) { QString tmp = currentDirPath(); if ( tmp.right(1) != QString::fromLatin1("/") ) tmp += '/'; tmp += dPath; return cleanDirPath( tmp ); } else { return cleanDirPath( dPath ); } } /*! Returns the name of the directory; this is \e not the same as the path, e.g. a directory with the name "mail", might have the path "/var/spool/mail". If the directory has no name (e.g. it is the root directory) QString::null is returned. 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() ) { dPath += '/'; } else if ( dirName == ".." ) { dPath = old; return FALSE; } dPath += dirName; if ( dirName.find('/') >= 0 || old == QString::fromLatin1(".") || dirName == QString::fromLatin1("..") ) dPath = cleanDirPath( dPath ); } if ( !exists() ) { dPath = old; // regret return FALSE; } dirty = TRUE; return TRUE; } /*! Changes directory by moving one directory up from the QDir's current directory. Returns TRUE if the new directory exists and is readable; otherwise returns FALSE. Note that the logical cdUp() operation is not performed if the new directory does not exist. \sa cd(), isReadable(), exists(), path() */ bool QDir::cdUp() { @@ -841,407 +880,416 @@ const QFileInfoList *QDir::entryInfoList( const QString &nameFilter, filterSpec = filtS; if ( sortSpec == (int)DefaultSort ) sortSpec = sortS; QDir *that = (QDir*)this; // mutable function if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) return that->fiList; else return 0; } /*! \overload Returns TRUE if the \e directory exists; otherwise returns FALSE. (If a file with the same name is found this function will return FALSE). \sa QFileInfo::exists(), QFile::exists() */ bool QDir::exists() const { QFileInfo fi( dPath ); return fi.exists() && fi.isDir(); } /*! Returns TRUE if the directory path is relative to the current directory and returns FALSE if the path is absolute (e.g. under UNIX a path is relative if it does not start with a "/"). \sa convertToAbs() */ 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 Mac OS X) and "\" under Windows. You do not need to use this function to build file paths. If you always use "/", Qt will translate your paths to conform to the underlying operating system. */ 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() ) newPath = QString::fromLatin1("/"); #if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) if ( name[0] == '/' ) { if ( name[1] == '/' ) // "\\machine\x\ ..." newPath.insert( 0, '/' ); } else { newPath = name.left(2) + newPath; } #endif } return newPath; } int qt_cmp_si_sortSpec; #if defined(Q_C_CALLBACKS) extern "C" { #endif #ifdef Q_OS_TEMP int __cdecl qt_cmp_si( const void *n1, const void *n2 ) #else int qt_cmp_si( const void *n1, const void *n2 ) #endif { if ( !n1 || !n2 ) return 0; QDirSortItem* f1 = (QDirSortItem*)n1; QDirSortItem* f2 = (QDirSortItem*)n2; if ( qt_cmp_si_sortSpec & QDir::DirsFirst ) 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 @@ -1,187 +1,187 @@ /**************************************************************************** ** $Id$ ** ** Implementation of QFile class ** ** Created : 930812 ** ** 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. ** **********************************************************************/ #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(); } /*! Destroys a QFile. Calls close(). */ QFile::~QFile() { close(); } /*! \internal Initialize internal data. */ void QFile::init() { setFlags( IO_Direct ); setStatus( IO_Ok ); fh = 0; fd = 0; length = 0; ioIndex = 0; ext_f = FALSE; // not an external file handle } /*! \fn QString QFile::name() const Returns the name set by setName(). @@ -197,192 +197,193 @@ void QFile::init() If the file name has no path or a relative path, the path used will be whatever the application's current directory path is \e{at the time of the open()} call. Example: \code QFile file; QDir::setCurrent( "/tmp" ); file.setName( "readme.txt" ); QDir::setCurrent( "/home" ); file.open( IO_ReadOnly ); // opens "/home/readme.txt" under Unix \endcode Note that the directory separator "/" works for all operating systems supported by Qt. \sa name(), QFileInfo, QDir */ void QFile::setName( const QString &name ) { if ( isOpen() ) { #if defined(QT_CHECK_STATE) qWarning( "QFile::setName: File is open" ); #endif close(); } fn = name; } /*! \overload 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; } /*! \overload Reads a line of text. Reads bytes from the file into string \a s, 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, e.g. end of file. Any terminating newline is not stripped. This function is only efficient for buffered files. Avoid using readLine() for files that have been opened with the \c IO_Raw flag. Note that the string is read as plain Latin1 bytes, not Unicode. \sa readBlock(), QTextStream::readLine() */ Q_LONG QFile::readLine( QString& s, Q_ULONG maxlen ) { QByteArray ba(maxlen); Q_LONG l = readLine(ba.data(),maxlen); if ( l >= 0 ) { ba.truncate(l); s = QString(ba); } return l; } 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 @@ -342,346 +342,351 @@ bool QFile::open( int m, FILE *f ) struct stat st; ::fstat( fileno(fh), &st ); #if defined(QT_LARGEFILE_SUPPORT) ioIndex = (Offset)ftello( fh ); #else ioIndex = (Offset)ftell( fh ); #endif if ( (st.st_mode & S_IFMT) != S_IFREG || f == stdin ) { //stdin is non seekable // non-seekable setType( IO_Sequential ); length = INT_MAX; ioIndex = 0; } else { length = (Offset)st.st_size; if ( !(flags()&IO_Truncate) && 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; } } } return TRUE; } /*! \overload Opens a file in the mode \a m using an existing file descriptor \a 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 @@ -542,118 +542,120 @@ bool QFileInfo::convertToAbs() if the size is 0 or if the size cannot be fetched. */ #if defined(QT_ABI_QT4) QIODevice::Offset QFileInfo::size() const #else uint QFileInfo::size() const #endif { if ( !fic || !cache ) doStat(); if ( fic ) #if defined(QT_ABI_QT4) return (QIODevice::Offset)fic->st.st_size; #elif defined(QT_LARGEFILE_SUPPORT) return (uint)fic->st.st_size > UINT_MAX ? UINT_MAX : (uint)fic->st.st_size; #else return (uint)fic->st.st_size; #endif else return 0; } /*! Returns the date and time when the file was created. On platforms where this information is not available, returns the same as lastModified(). \sa created() lastModified() lastRead() */ 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 @@ -121,195 +121,195 @@ QString QFileInfo::readLink() const r = QFile::decodeName(s); } #endif return r; } static const uint nobodyID = (uint) -2; /*! Returns the owner of the file. On Windows, on systems where files do not have owners, or if an error occurs, QString::null is returned. This function can be time consuming under Unix (in the order of milliseconds). \sa ownerId(), group(), groupId() */ QString QFileInfo::owner() const { passwd *pw = getpwuid( ownerId() ); if ( pw ) return QFile::decodeName( pw->pw_name ); return QString::null; } /*! Returns the id of the owner of the file. On Windows and on systems where files do not have owners this 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; } } /*! Returns the file's path. If \a absPath is TRUE an absolute path is returned. \sa dir(), filePath(), fileName(), isRelative() */ #ifndef QT_NO_DIR QString QFileInfo::dirPath( bool absPath ) const { QString s; if ( absPath ) s = absFilePath(); else s = fn; int pos = s.findRev( '/' ); if ( pos == -1 ) { return QString::fromLatin1( "." ); } else { if ( pos == 0 ) return QString::fromLatin1( "/" ); return s.left( pos ); } } #endif /*! Returns the name of the file, excluding the path. Example: \code 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,501 +1,562 @@ /**************************************************************************** ** $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 Example of misuse (do not do this): \code static uchar bindata[] = { 231, 1, 44, ... }; QByteArray a, b; a.setRawData( bindata, sizeof(bindata) ); // a points to bindata a.resize( 8 ); // will crash b = a; // will crash a[2] = 123; // might crash // forget to resetRawData - will crash \endcode \warning If you do not call resetRawData(), QGArray will attempt to deallocate or reallocate the raw data, which might not be too good. Be careful. */ QGArray &QGArray::setRawData( const char *d, uint len ) { duplicate( 0, 0 ); // set null data shd->data = (char *)d; shd->len = len; return *this; } /*! Resets raw data. The arguments must be the data, \a d, and length \a len, that were passed to setRawData(). This is for consistency checking. */ @@ -566,189 +627,191 @@ int QGArray::find( const char *d, uint index, uint sz ) const default: { // any size elements for ( i=index; i<shd->len; i+=sz ) { if ( memcmp( d, &shd->data[i], sz ) == 0 ) break; } ii = i/sz; } break; } return i<shd->len ? (int)ii : -1; } /*! Returns the number of occurrences of \a d in the array, where \a sz is the size of the \a d element. This function only compares whole cells, not bytes. */ int QGArray::contains( const char *d, uint sz ) const { register uint i = shd->len; int count = 0; switch ( sz ) { case 1: { // 8 bit elements register char *x = data(); char v = *d; while ( i-- ) { if ( *x++ == v ) count++; } } 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; } /*! Deletes the shared array block, \a p. */ void QGArray::deleteData( array_data *p ) { delete p; p = 0; } 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 @@ -111,193 +111,196 @@ int QGDict::hashKeyString( const QString &key ) } } int index = h; if ( index < 0 ) // adjust index to table size index = -index; return index; } /*! Returns the hash key for \a key, which is a C string. */ int QGDict::hashKeyAscii( const char *key ) { #if defined(QT_CHECK_NULL) if ( key == 0 ) qWarning( "QGDict::hashAsciiKey: Invalid null key" ); #endif register const char *k = key; register uint h=0; uint g; if ( cases ) { // case sensitive while ( *k ) { h = (h<<4) + *k++; if ( (g = h & 0xf0000000) ) h ^= g >> 24; h &= ~g; } } else { // case insensitive while ( *k ) { h = (h<<4) + tolower((uchar) *k); if ( (g = h & 0xf0000000) ) 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 i->dict = 0; // this dict is deleted i = iterators->next(); } delete iterators; } /*! Assigns \a dict to this dictionary. */ QGDict &QGDict::operator=( const QGDict &dict ) { if ( &dict == this ) return *this; clear(); 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; } 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 @@ -236,198 +236,194 @@ QGList::QGList( const QGList & list ) curIndex = -1; iterators = 0; // initialize iterator list QLNode *n = list.firstNode; while ( n ) { // copy all items from list append( n->data ); n = n->next; } } /*! Removes all items from the list and destroys the list. */ QGList::~QGList() { clear(); delete iterators; // Workaround for GCC 2.7.* bug. Compiler constructs 'static' QGList // instances twice on the same address and therefore tries to destruct // twice on the same address! This is insane but let's try not to crash // here. iterators = 0; } /*! Assigns \a list to this list. */ QGList& QGList::operator=( const QGList &list ) { if ( &list == this ) 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; } /*! Inserts item \a d at the end of the list. */ void QGList::append( QPtrCollection::Item d ) { register QLNode *n = new QLNode( newItem(d) ); Q_CHECK_PTR( n ); n->next = 0; if ( (n->prev = lastNode) ) // list is not empty lastNode->next = n; else // initialize list firstNode = n; lastNode = curNode = n; // curNode affected curIndex = numNodes; numNodes++; } /*! Inserts item \a d at position \a index in the list. */ bool QGList::insertAt( uint index, QPtrCollection::Item d ) { if ( index == 0 ) { prepend( d ); return TRUE; } else if ( index == numNodes ) { append( d ); return TRUE; } 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 @@ -56,381 +56,414 @@ 3.0.5's \c QT_VERSION is 0x030005. */ const char *qVersion() { return QT_VERSION_STR; } /***************************************************************************** System detection routines *****************************************************************************/ static bool si_alreadyDone = FALSE; static int si_wordSize; static bool si_bigEndian; /*! \relates QApplication Obtains information about the system. The system's word size in bits (typically 32) is returned in \a *wordSize. The \a *bigEndian is set to TRUE if this is a big-endian machine, or to FALSE if this is a little-endian machine. In debug mode, this function calls qFatal() with a message if the computer is truly weird (i.e. different endianness for 16 bit and 32 bit integers); in release mode it returns FALSE. */ 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 /***************************************************************************** Debug output routines *****************************************************************************/ /*! \fn void qDebug( const char *msg, ... ) \relates QApplication Prints a debug message \a msg, 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 qDebug( "my window handle = %x", myWidget->id() ); \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 qDebug might lead to crashes on certain platforms due to the platforms printf implementation. \sa qWarning(), qFatal(), qInstallMsgHandler(), \link debug.html Debugging\endlink */ /*! \fn void qWarning( const char *msg, ... ) \relates QApplication Prints a warning message \a msg, 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 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]; 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 { #ifdef 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 } } void qWarning( 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 @@ -548,204 +581,204 @@ void fatal( const char *msg, ... ) Prints the message \a msg and uses \a code to get a system specific error message. When \a code is -1 (the default), the system's last error code will be used if possible. Use this method to handle failures in platform specific API calls. This function does nothing when Qt is built with \c QT_NO_DEBUG defined. */ void qSystemWarning( const char* msg, int code ) { #ifndef QT_NO_DEBUG #if defined(Q_OS_WIN32) if ( code == -1 ) code = GetLastError(); if ( !code ) return; #ifdef Q_OS_TEMP unsigned short *string; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&string, 0, NULL ); qWarning( "%s\n\tError code %d - %s (###may need fixing in qglobal.h)", msg, code, (const char *)string ); #else char* string; 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.", oldfunc, newfunc ); } void qObsolete( const char *obj, const char *oldfunc ) { if ( suppressObsolete ) return; if ( !firstObsoleteWarning(obj, oldfunc) ) return; if ( obj ) qDebug( "%s::%s: This function is obsolete.", obj, oldfunc ); else qDebug( "%s: This function is obsolete.", oldfunc ); } void qObsolete( const char *message ) { if ( suppressObsolete ) return; if ( !firstObsoleteWarning( "Qt", message) ) return; qDebug( "%s", message ); } /*! \relates QApplication Installs a Qt message handler \a h. Returns a pointer to the message handler previously defined. The message handler is a function that prints out debug messages, 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,102 +1,102 @@ /**************************************************************************** ** $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 co-occurrence matrix requires only 20 * 20 = 400 bits, not 256 * 256 = 65536 bits or even more if we want the whole Unicode. Which character falls in which bucket is arbitrary. The second half of the table is a replica of the first half, because of laziness. */ static const char indexOf[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ! " # $ % & ' ( ) * + , - . / 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, // @ A B C D E F G H I J K L M N O 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, // P Q R S T U V W X Y Z [ \ ] ^ _ 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, // ` a b c d e f g h i j k l m n o 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, // p q r s t u v w x y z { | } ~ 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 7, 10, 12, 15, 19, 2, 6, 7, 10, 12, 15, 19, 0, 1, 3, 4, 5, 8, 9, 11, 13, 14, 16, 2, 6, 7, 10, 12, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 10, 11, 12, 13, 14, 15, 12, 16, 17, 18, 19, 2, 10, 15, 7, 19, 2, 6, 7, 10, 0 }; @@ -382,163 +382,163 @@ const QLibrary* QGPluginManager::library( const QString& feature ) const ++git; } if ( sameBasename.isEmpty() ) { that->addLibrary( new QComLibrary( lib ) ); } else { QPtrList<QComLibrary> same; same.setAutoDelete( TRUE ); for ( QStringList::ConstIterator bit = sameBasename.begin(); bit != sameBasename.end(); ++bit ) same.append( new QComLibrary( *bit ) ); QComLibrary* bestMatch = 0; for ( QComLibrary* candidate = same.first(); candidate; candidate = same.next() ) if ( candidate->qtVersion() && candidate->qtVersion() <= QT_VERSION && ( !bestMatch || candidate->qtVersion() > bestMatch->qtVersion() ) ) bestMatch = candidate; if ( bestMatch ) { same.find( bestMatch ); that->addLibrary( same.take() ); } } if ( ( library = that->plugDict[feature] ) ) return library; } } return 0; } QStringList QGPluginManager::featureList() const { QStringList features; 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; } #endif //QT_NO_COMPONENT 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,133 +1,139 @@ /**************************************************************************** ** $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: <ul> <li> 0 if \a d1 == \a d2 <li> \> 0 (positive integer) if \a d1 \> \a d2 <li> \< 0 (negative integer) if \a d1 \< \a d2 </ul> The QPtrVector::sort() and QPtrVector::bsearch() functions require that compareItems() is implemented as described here. This function should not modify the vector because some const functions call compareItems(). */ int QGVector::compareItems( Item d1, Item d2 ) { return d1 != d2; // compare pointers } #ifndef QT_NO_DATASTREAM /*! Reads a collection/vector item from the stream \a s and returns a reference to the stream. The default implementation sets \a d to 0. \sa write() */ QDataStream &QGVector::read( QDataStream &s, Item &d ) { // read item from stream d = 0; return s; @@ -300,193 +306,194 @@ bool QGVector::resize( uint newsize ) // resize array while ( i < len ) { // delete lost items if ( vec[i] ) { deleteItem( vec[i] ); numItems--; } i++; } } if ( newsize == 0 ) { // vector becomes empty DELETE(vec); vec = 0; len = numItems = 0; return TRUE; } #if defined(DONT_USE_REALLOC) if ( newsize == 0 ) { DELETE(vec); vec = 0; return FALSE; } Item *newvec = NEW(Item,newsize); // manual realloc memcpy( newvec, vec, (len < newsize ? len : newsize)*sizeof(Item) ); DELETE(vec); vec = newvec; #else vec = (Item*)realloc( (char *)vec, newsize*sizeof(Item) ); #endif } else { // create new vector vec = NEW(Item,newsize); len = numItems = 0; } Q_CHECK_PTR( vec ); 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 qWarning( "QGVector::find: Index %d out of range", index ); return -1; } #endif for ( uint i=index; i<len; i++ ) { if ( vec[i] == 0 && d == 0 ) // found null item return i; if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) return i; } return -1; } uint QGVector::containsRef( Item d ) const // get number of exact matches { uint count = 0; for ( uint i=0; i<len; i++ ) { if ( vec[i] == d ) count++; } return count; } uint QGVector::contains( Item d ) const // get number of equal matches { uint count = 0; for ( uint i=0; i<len; i++ ) { if ( vec[i] == 0 && d == 0 ) // count null items count++; if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) count++; } 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,170 +1,170 @@ /**************************************************************************** ** $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 ) { libfile.replace( '\\', '/' ); d = new QLibraryPrivate( this ); } /*! Deletes the QLibrary object. The library will be unloaded if autoUnload() is TRUE (the default), otherwise it stays in memory until the application exits. \sa unload(), setAutoUnload() */ QLibrary::~QLibrary() { if ( autoUnload() ) unload(); delete d; } /*! Returns the address of the exported symbol \a symb. The library is loaded if necessary. The function returns 0 if the symbol could not be resolved or the library could not be loaded. \code typedef int (*avgProc)( int, int ); avgProc avg = (avgProc) library->resolve( "avg" ); if ( avg ) @@ -233,111 +233,112 @@ void *QLibrary::resolve( const QString &filename, const char *symb ) bool QLibrary::isLoaded() const { return d->pHnd != 0; } /*! Loads the library. Since resolve() always calls this function before resolving any symbols it is not necessary to call it explicitly. In some situations you might want the library loaded in advance, in which case you would use this function. */ bool QLibrary::load() { return d->loadLibrary(); } /*! Unloads the library and returns TRUE if the library could be unloaded; otherwise returns FALSE. This function is called by the destructor if autoUnload() is enabled. \sa resolve() */ bool QLibrary::unload() { if ( !d->pHnd ) return TRUE; #if !defined(QT_NO_LIBRARY_UNLOAD) if ( !d->freeLibrary() ) { # 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,152 +1,169 @@ /**************************************************************************** ** $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; } bool QLibraryPrivate::freeLibrary() { if ( !pHnd ) return TRUE; if ( dlclose( pHnd ) ) { #if defined(QT_DEBUG) || defined(QT_DEBUG_COMPONENT) qWarning( "%s", dlerror() ); #endif return FALSE; } pHnd = 0; return TRUE; } void* QLibraryPrivate::resolveSymbol( const char* symbol ) { if ( !pHnd ) return 0; #if defined(QT_AOUT_UNDERSCORE) // older a.out systems add an underscore in front of symbols char* undrscr_symbol = new char[strlen(symbol)+2]; undrscr_symbol[0] = '_'; strcpy(undrscr_symbol+1, symbol); void* address = dlsym( pHnd, undrscr_symbol ); delete [] undrscr_symbol; #else void* address = dlsym( pHnd, symbol ); #endif 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,143 +1,144 @@ /**************************************************************************** ** $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 QMutexPrivate::~QMutexPrivate() { int ret = pthread_mutex_destroy(&handle); #ifdef QT_CHECK_RANGE if ( ret ) qWarning( "Mutex destroy failure: %s", strerror( ret ) ); #endif } // real mutex class QRealMutexPrivate::QRealMutexPrivate(bool recurs) : recursive(recurs) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); Q_MUTEX_SET_TYPE(&attr, recursive ? Q_RECURSIVE_MUTEX_TYPE : Q_NORMAL_MUTEX_TYPE); Q_UNUSED(recursive); int ret = pthread_mutex_init(&handle, &attr); pthread_mutexattr_destroy(&attr); #ifdef QT_CHECK_RANGE if( ret ) qWarning( "Mutex init failure: %s", strerror( ret ) ); #endif // QT_CHECK_RANGE } void QRealMutexPrivate::lock() { int ret = pthread_mutex_lock(&handle); #ifdef QT_CHECK_RANGE @@ -568,120 +569,121 @@ bool QMutex::tryLock() mutex.unlock(); return return_value; } \endcode This example function will get more complicated as it is developed, which increases the likelihood that errors will occur. Using QMutexLocker greatly simplifies the code, and makes it more readable: \code int complexFunction( int flag ) { QMutexLocker locker( &mutex ); int return_value = 0; switch ( flag ) { case 0: case 1: { return moreComplexFunction( flag ); } case 2: { int status = anotherFunction(); if ( status < 0 ) return -2; return_value = status + flag; 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 @@ -170,201 +170,201 @@ <b>\d</b>. The quantifier to match exactly one occurrence, <b>{1,1}</b>, can be replaced with the expression itself. This means that <b>x{1,1}</b> is exactly the same as <b>x</b> alone. So our 0 to 99 matcher could be written <b>^\d{1,2}$</b>. Another way of writing it would be <b>^\d\d{0,1}$</b>, i.e. from the start of the string match a digit followed by zero or one digits. In practice most people would write it <b>^\d\d?$</b>. The <b>?</b> is a shorthand for the quantifier <b>{0,1}</b>, i.e. a minimum of no occurrences a maximum of one occurrence. This is used to make an expression optional. The regexp <b>^\d\d?$</b> means "from the beginning of the string match one digit followed by zero or one digits and then the end of the string". Our second example is matching the words 'mail', 'letter' or 'correspondence' but without matching 'email', 'mailman', 'mailer', 'letterbox' etc. We'll start by just matching 'mail'. In full the regexp is, <b>m{1,1}a{1,1}i{1,1}l{1,1}</b>, but since each expression itself is automatically quantified by <b>{1,1}</b> we can simply write this as <b>mail</b>; an 'm' followed by an 'a' followed by an 'i' followed by an 'l'. The symbol '|' (bar) is used for \e alternation, so our regexp now becomes <b>mail|letter|correspondence</b> which means match 'mail' \e or 'letter' \e or 'correspondence'. Whilst this regexp will find the words we want it will also find words we don't want such as 'email'. We will start by putting our regexp in parentheses, <b>(mail|letter|correspondence)</b>. Parentheses have two effects, firstly they group expressions together and secondly they identify parts of the regexp that we wish to \link #capturing-text capture \endlink. Our regexp still matches any of the three words but now they are grouped together as a unit. This is useful for building up more complex regexps. It is also useful because it allows us to examine which of the words actually matched. We need to use 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> \i Matches zero or more occurrences of \e E. This is the same as <b>\e {E}{0,MAXINT}</b>. The <b>*</b> quantifier is often used by a mistake. Since it matches \e zero or more occurrences it will match no occurrences at all. For example if we want to match strings that end in whitespace and use the regexp <b>\s*$</b> we would get a match on every string. This is because we have said find zero or more whitespace followed by the end of string, so even strings that don't end in whitespace will match. The regexp we want in this case is <b>\s+$</b> to match strings that have at least one whitespace at the end. \row \i <b>\e {E}{n}</b> \i Matches exactly \e n occurrences of the expression. This is the same as repeating the expression \e n times. For example, <b>x{5}</b> is the same as <b>xxxxx</b>. It is also the same as <b>\e {E}{n,n}</b>, e.g. <b>x{5,5}</b>. \row \i <b>\e {E}{n,}</b> \i Matches at least \e n occurrences of the expression. This is the same as <b>\e {E}{n,MAXINT}</b>. \row \i <b>\e {E}{,m}</b> \i Matches at most \e m occurrences of the expression. This is the same as <b>\e {E}{0,m}</b>. \row \i <b>\e {E}{n,m}</b> \i Matches at least \e n occurrences of the expression and at most \e m occurrences of the expression. \endtable (MAXINT is implementation dependent but will not be smaller than @@ -454,360 +454,372 @@ and end of string aren't non-word boundaries), but it would match in "t<u>on</u>ne". \row \i <b>(?=\e E)</b> \i Positive lookahead. This assertion is true if the expression matches at this point in the regexp. For example, <b>const(?=\\s+char)</b> matches 'const' whenever it is followed by 'char', as in 'static <u>const</u> char *'. (Compare with <b>const\\s+char</b>, which matches 'static <u>const char</u> *'.) \row \i <b>(?!\e E)</b> \i Negative lookahead. This assertion is true if the expression does not match at this point in the regexp. For example, <b>const(?!\\s+char)</b> matches 'const' \e except when it is followed by 'char'. \endtable \target wildcard-matching \section1 Wildcard Matching (globbing) Most command shells such as \e bash or \e cmd.exe support "file globbing", the ability to identify a group of files by using wildcards. The setWildcard() function is used to switch between regexp and wildcard mode. Wildcard matching is much simpler than full regexps and has only four features: \table \row \i <b>c</b> \i Any character represents itself apart from those mentioned below. Thus <b>c</b> matches the character \e c. \row \i <b>?</b> \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"; line1.replace( rx, "&" ); // 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; } #ifndef QT_NO_REGEXP_WILDCARD /* Translates a wildcard pattern to an equivalent regular expression pattern (e.g., *.cpp to .*\.cpp). */ static QString wc2rx( const QString& wc_str ) { int wclen = wc_str.length(); QString rx = QString::fromLatin1( "" ); int i = 0; const QChar *wc = wc_str.unicode(); while ( i < wclen ) { QChar c = wc[i++]; switch ( c.unicode() ) { case '*': rx += QString::fromLatin1( ".*" ); break; case '?': rx += QChar( '.' ); break; case '$': case '(': case ')': case '+': case '.': case '\\': case '^': case '{': case '|': case '}': rx += QChar( '\\' ); @@ -1587,195 +1599,195 @@ void QRegExpEngine::setup( bool caseSensitive ) mmCapturedNoMatch.fill( -1, 2 ); } int QRegExpEngine::setupState( int match ) { if ( (ns & (ns + 1)) == 0 && ns + 1 >= (int) s.size() ) s.resize( (ns + 1) << 1 ); #ifndef QT_NO_REGEXP_CAPTURE s.insert( ns, new State(cf, match) ); #else s.insert( ns, new State(match) ); #endif return ns++; } #ifndef QT_NO_REGEXP_CAPTURE /* Functions startAtom() and finishAtom() should be called to delimit atoms. When a state is created, it is assigned to the current atom. The information is later used for capturing. */ int QRegExpEngine::startAtom( bool capture ) { if ( (nf & (nf + 1)) == 0 && nf + 1 >= (int) f.size() ) f.resize( (nf + 1) << 1 ); f[nf].parent = cf; cf = nf++; f[cf].capture = capture ? ncap++ : -1; return cf; } #endif #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() { int slideHead = 0; int slideNext = 0; int i; int lastPos = mmLen - minl; memset( mmSlideTab, 0, mmSlideTabSize * sizeof(int) ); /* Set up the slide table, used for the bad-character heuristic, using the table of first occurrence of each character. */ for ( i = 0; i < minl; i++ ) { int sk = occ1[BadChar(mmIn[mmPos + i])]; if ( sk == NoOccurrence ) sk = i + 1; if ( sk > 0 ) { int k = i + 1 - sk; if ( k < 0 ) { sk = i + 1; k = 0; } if ( sk > mmSlideTab[k] ) mmSlideTab[k] = sk; } } if ( mmPos > lastPos ) return FALSE; for ( ;; ) { if ( ++slideNext >= mmSlideTabSize ) slideNext = 0; if ( mmSlideTab[slideHead] > 0 ) { @@ -2539,212 +2551,220 @@ void QRegExpEngine::Box::setupHeuristics() #if defined(QT_DEBUG) void QRegExpEngine::Box::dump() const { int i; qDebug( "Box of at least %d character%s", minl, minl == 1 ? "" : "s" ); qDebug( " Left states:" ); for ( i = 0; i < (int) ls.size(); i++ ) { if ( at(lanchors, ls[i]) == 0 ) qDebug( " %d", ls[i] ); else qDebug( " %d [anchors 0x%.8x]", ls[i], lanchors[ls[i]] ); } qDebug( " Right states:" ); for ( i = 0; i < (int) rs.size(); i++ ) { if ( at(ranchors, rs[i]) == 0 ) qDebug( " %d", rs[i] ); else qDebug( " %d [anchors 0x%.8x]", rs[i], ranchors[rs[i]] ); } qDebug( " Skip anchors: 0x%.8x", skipanchors ); } #endif void QRegExpEngine::Box::addAnchorsToEngine( const Box& to ) const { for ( int i = 0; i < (int) to.ls.size(); i++ ) { for ( int j = 0; j < (int) rs.size(); j++ ) { int a = eng->anchorConcatenation( at(ranchors, rs[j]), at(to.lanchors, to.ls[i]) ); eng->addAnchors( rs[j], to.ls[i], a ); } } } 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 void QRegExpEngine::error( const char *msg ) { if ( yyError.isEmpty() ) yyError = QString::fromLatin1( msg ); } void QRegExpEngine::startTokenizer( const QChar *rx, int len ) { yyIn = rx; yyPos0 = 0; yyPos = 0; yyLen = len; yyCh = getChar(); yyCharClass = new CharClass; yyMinRep = 0; yyMaxRep = 0; yyError = QString(); } int QRegExpEngine::getToken() { #ifndef QT_NO_REGEXP_CCLASS ushort pendingCh = 0; bool charPending; bool rangePending; int tok; #endif int prevCh = yyCh; yyPos0 = yyPos - 1; #ifndef QT_NO_REGEXP_CCLASS yyCharClass->clear(); @@ -3090,213 +3110,215 @@ void QRegExpEngine::parseFactor( Box *box ) #endif } if ( yyMinRep == 0 ) box->opt(); #ifndef QT_NO_REGEXP_INTERVAL yyMayCapture = FALSE; int alpha = ( yyMinRep == 0 ) ? 0 : yyMinRep - 1; int beta = ( yyMaxRep == InftyRep ) ? 0 : yyMaxRep - ( alpha + 1 ); Box rightBox( this ); int i; for ( i = 0; i < beta; i++ ) { YYREDO(); Box leftBox( this ); parseAtom( &leftBox ); leftBox.cat( rightBox ); leftBox.opt(); rightBox = leftBox; } for ( i = 0; i < alpha; i++ ) { YYREDO(); Box leftBox( this ); parseAtom( &leftBox ); leftBox.cat( rightBox ); rightBox = leftBox; } rightBox.cat( *box ); *box = rightBox; #endif yyTok = getToken(); #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 priv->min = FALSE; compile( caseSensitive ); } /*! Constructs a regular expression as a copy of \a rx. \sa operator=() */ QRegExp::QRegExp( const QRegExp& rx ) { eng = 0; priv = new QRegExpPrivate; operator=( rx ); } /*! Destroys the regular expression and cleans up its internal data. */ QRegExp::~QRegExp() { derefEngine( eng, priv->rxpattern ); delete priv; } /*! Copies the regular expression \a rx and returns a reference to the copy. The case sensitivity, wildcard and minimal matching options are also copied. */ QRegExp& QRegExp::operator=( const QRegExp& rx ) { @@ -3472,322 +3494,308 @@ void QRegExp::setWildcard( bool wildcard ) otherwise returns FALSE. \sa setMinimal() */ bool QRegExp::minimal() const { return priv->min; } /*! Enables or disables minimal matching. If \a minimal is FALSE, matching is greedy (maximal) which is the default. For example, suppose we have the input string "We must be \<b>bold\</b>, very \<b>bold\</b>!" and the pattern <b>\<b>.*\</b></b>. With the default greedy (maximal) matching, the match is "We must be <u>\<b>bold\</b>, very \<b>bold\</b></u>!". But with minimal (non-greedy) matching the first match is: "We must be <u>\<b>bold\</b></u>, very \<b>bold\</b>!" and the second match is "We must be \<b>bold\</b>, very <u>\<b>bold\</b></u>!". In practice we might use the pattern <b>\<b>[^\<]+\</b></b> instead, although this will still fail for nested tags. \sa minimal() */ void QRegExp::setMinimal( bool minimal ) { priv->min = 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() */ QStringList QRegExp::capturedTexts() { if ( priv->capturedCache.isEmpty() ) { for ( int i = 0; i < (int) priv->captured.size(); i += 2 ) { QString m; if ( priv->captured[i + 1] == 0 ) m = QString::fromLatin1( "" ); else if ( priv->captured[i] >= 0 ) m = priv->t.mid( priv->captured[i], priv->captured[i + 1] ); priv->capturedCache.append( m ); } priv->t = QString::null; } return priv->capturedCache; } /*! Returns the text captured by the \a nth subexpression. The entire match has index 0 and the parenthesized subexpressions have indices starting from 1 (excluding non-capturing parentheses). \code QRegExp rxlen( "(\\d+)(?:\\s*)(cm|inch)" ); int pos = rxlen.search( "Length: 189cm" ); if ( pos > -1 ) { QString value = rxlen.cap( 1 ); // "189" QString unit = rxlen.cap( 2 ); // "cm" // ... } \endcode 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 @@ -90,203 +90,201 @@ public: QMutex mutex; QWaitCondition cond; int value, max; }; QSemaphorePrivate::QSemaphorePrivate(int m) : mutex(FALSE), value(0), max(m) { } /*! Creates a new semaphore. The semaphore can be concurrently accessed at most \a maxcount times. */ QSemaphore::QSemaphore(int maxcount) { d = new QSemaphorePrivate(maxcount); } /*! Destroys the semaphore. \warning If you destroy a semaphore that has accesses in use the resultant behavior is undefined. */ 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(); return TRUE; } #endif // QT_THREAD_SUPPORT 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,1955 +1,2060 @@ /**************************************************************************** ** $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 #define Q_LOCKWRITE F_WRLCK /* Locks the file specified by name. The lockfile is created as a hidden file in the same directory as the target file, with .lock appended to the name. For example, "/etc/settings/onerc" uses a lockfile named "/etc/settings/.onerc.lock". The type argument controls the type of the lock, it can be either F_RDLCK for a read lock, or F_WRLCK for a write lock. A file descriptor for the lock file is returned, and should be closed with closelock() when the lock is no longer needed. */ static HANDLE openlock( const QString &name, int type ) { QFileInfo info( name ); // lockfile should be hidden, and never removed QString lockfile = info.dirPath() + "/." + info.fileName() + ".lock"; // open the lockfile 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); git = find(gname); if (git == end()) git = replace(gname, QSettingsGroup()); } else { if (git == end()) { #if defined(QT_CHECK_STATE) qWarning("QSettings: line '%s' out of group", line.latin1()); #endif return; } int i = line.find('='); 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,157 +1,161 @@ /**************************************************************************** ** $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 @_; $ligature{$start} = $ligature{$start}." ".$code; } # adjust position if($len != 0) { $position += $len + 3; } } # Code to integer mappings... # %category_code = numberize(qw{ EMPTY Mn Mc Me Nd Nl No Zs Zl Zp Cc Cf Cs Co Cn Lu Ll Lt Lm Lo Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So }); %bidi_category_code = numberize(qw{ L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN}); %character_decomposition_tag = numberize(qw{ <single> <canonical> <font> <noBreak> <initial> <medial> <final> <isolated> <circle> <super> <sub> <vertical> <wide> <narrow> <small> <square> <compat> <fraction> }); %mirrored_code = numberize(qw{N Y}); @@ -11694,306 +11698,308 @@ static const Q_INT8 * const decimal_info[256] = { 0, num_09, num_09, num_0B, num_09, num_0D, num_0E, num_0F, num_10, 0, 0, num_13, 0, 0, 0, num_17, num_18, 0, 0, 0, 0, 0, 0, 0, num_20, 0, 0, 0, num_24, 0, 0, num_27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, num_18, }; // 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 decomposed Unicode ("a" followed by "ring above") by using decomposition(). In Unicode, comparison is not necessarily possible and case conversion is very difficult at best. Unicode, covering the "entire" world, also includes most of the world's case and sorting problems. Qt tries, but not very hard: operator==() and friends will do comparison based purely on the numeric Unicode value (code point) of the characters, and upper() and lower() will do case changes when the character has a well-defined upper/lower-case equivalent. There is no provision for locale-dependent case folding rules or comparison; these functions are meant to be fast so they can be used unambiguously in data structures. (See QString::localeAwareCompare() though.) The conversion functions include unicode() (to a scalar), latin1() (to scalar, but converts all non-Latin1 characters to 0), row() (gives the Unicode row), cell() (gives the Unicode cell), digitValue() (gives the integer value of any of the numerous digit characters), and a host of constructors. More information can be found in the document \link unicode.html About Unicode. \endlink \sa QString QCharRef */ /*! \enum QChar::Category This enum maps the Unicode character categories. @@ -12798,846 +12804,850 @@ static inline bool format(QChar::Decomposition tag, QString & str, switch (tag) { case QChar::Medial: return (left & right); case QChar::Initial: return (left && !right); case QChar::Final: return (right);// && !left); case QChar::Isolated: default: return (!right && !left); } } // format() #endif /* QString::compose() and visual() were developed by Gordon Tisher <tisher@uniserve.ca>, with input from Lars Knoll <knoll@mpi-hd.mpg.de>, who developed the unicode data tables. */ /*! \warning This function is not supported in Qt 3.x. It is provided for experimental and illustrative purposes only. It is mainly of interest to those experimenting with Arabic and other composition-rich texts. Applies possible ligatures to a QString. Useful when composition-rich text requires rendering with glyph-poor fonts, but it also makes compositions such as QChar(0x0041) ('A') and QChar(0x0308) (Unicode accent diaresis), giving QChar(0x00c4) (German A Umlaut). */ 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 split a string into a list of strings using QStringList::split(), and join a list of strings into a single string with an optional separator using QStringList::join(). You can obtain a list of strings from a string list that contain a particular substring or that match a particular \link qregexp.html regex\endlink using QStringList::grep(). <b>Note for C programmers</b> Due to C++'s type system and the fact that QString is implicitly shared, QStrings may be treated like ints or other simple base types. For example: \code QString boolToString( bool b ) { QString result; if ( b ) result = "True"; else result = "False"; return result; } \endcode The variable, result, is an auto variable allocated on the stack. When return is called, because we're returning by value, The copy constructor is called and a copy of the string is returned. (No actual copying takes place thanks to the implicit sharing, see below.) Throughout Qt's source code you will encounter QString usages like this: \code 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 ); } /*! \overload \a a is expressed in base \a base, which is 10 by default and must be between 2 and 36. */ QString QString::arg( ulong a, int fieldwidth, int base ) const { return arg( QString::number(a, base), fieldwidth ); } /*! \fn QString QString::arg( int a, int fieldwidth, int base ) const \overload \a a is expressed in base \a base, which is 10 by default and must be between 2 and 36. */ /*! \fn QString QString::arg( uint a, int fieldwidth, int base ) const \overload \a a is expressed in base \a base, which is 10 by default and must be between 2 and 36. */ /*! \fn QString QString::arg( short a, int fieldwidth, int base ) const @@ -13681,332 +13691,332 @@ QString QString::arg( QChar a, int fieldwidth ) const /*! \overload \target arg-formats Argument \a a is formatted according to the \a fmt format specified, which is 'g' by default and can be any of the following: \table \header \i Format \i Meaning \row \i \c e \i format as [-]9.9e[+|-]999 \row \i \c E \i format as [-]9.9E[+|-]999 \row \i \c f \i format as [-]9.9 \row \i \c g \i use \c e or \c f format, whichever is the most concise \row \i \c G \i use \c E or \c f format, whichever is the most concise \endtable With 'e', 'E', and 'f', \a prec is the number of digits after the decimal point. With 'g' and 'G', \a prec is the maximum number of significant digits (trailing zeroes are omitted). \code double d = 12.34; QString ds = QString( "'E' format, precision 3, gives %1" ) .arg( d, 0, 'E', 3 ); // ds == "1.234E+001" \endcode */ QString QString::arg( double a, int fieldwidth, char fmt, int prec ) const { return arg( QString::number( a, fmt, prec ), fieldwidth ); } /* 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 { int ch = va_arg(ap, int); replacement = QChar((ushort)ch); } if ( replacement.length() < width ) { replacement = rightjust ? replacement.rightJustify(width) : replacement.leftJustify(width); } } else if ( format[pos+len] == '%' ) { replacement = '%'; } 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 { const uint l = length(); if ( index < 0 ) index += l; if ( (uint)index >= l ) return -1; register const QChar *uc = unicode()+index; const QChar *end = unicode() + l; if ( cs ) { while ( uc < end && *uc != c ) uc++; } else { c = ::lower( c ); while ( uc < end && ::lower( *uc ) != c ) uc++; } if ( uint(uc - unicode()) >= l ) return -1; return (int)(uc - unicode()); } /* an implementation of the Boyer-Moore search algorithm */ /* initializes the skiptable to know haw far ahead we can skip on a wrong match */ static void bm_init_skiptable( const QString &pattern, uint *skiptable, bool cs ) { int i = 0; register uint *st = skiptable; int l = pattern.length(); while ( i++ < 0x100/8 ) { *(st++) = l; @@ -14031,343 +14041,351 @@ static void bm_init_skiptable( const QString &pattern, uint *skiptable, bool cs } } } static int bm_find( const QString &str, int index, const QString &pattern, uint *skiptable, bool cs ) { const uint l = str.length(); if ( pattern.isEmpty() ) return index > (int)l ? -1 : index; const QChar *uc = str.unicode(); const QChar *puc = pattern.unicode(); const uint pl = pattern.length(); const uint pl_minus_one = pl - 1; register const QChar *current = uc + index + pl_minus_one; const QChar *end = uc + l; if ( cs ) { while( current < end ) { uint skip = skiptable[ current->cell() ]; if ( !skip ) { // possible match while( skip < pl ) { if ( *(current - skip ) != 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[ (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. \value SectionCaseInsensitiveSeps Compare the separator case-insensitively. Any of the last four values can be OR-ed together to form a flag. \sa section() */ /*! \fn QString QString::section( QChar sep, int start, int end = 0xffffffff, int flags = SectionDefault ) const This function returns a section of the string. This string is treated as a sequence of fields separated by the character, \a sep. The returned string consists of the fields from position \a start to position \a end inclusive. If \a end is not specified, all fields from position \a start to the end of the string are included. Fields are numbered 0, 1, 2, etc., counting from the left, and -1, -2, etc., counting from right to left. The \a flags argument can be used to affect some aspects of the function's behaviour, e.g. whether to be case sensitive, whether to skip empty fields and how to deal with leading and trailing separators; see \l{SectionFlags}. \code QString csv( "forename,middlename,surname,phone" ); QString s = csv.section( ',', 2, 2 ); // s == "surname" QString path( "/usr/local/bin/myapp" ); // First field is empty QString s = path.section( '/', 3, 4 ); // s == "bin/myapp" QString s = path.section( '/', 3, 3, SectionSkipEmpty ); // s == "myapp" @@ -14886,464 +14904,484 @@ QString QString::mid( uint index, uint len ) const } } /*! Returns a string of length \a width that contains this string padded by the \a fill character. 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 any characters in a copy of the string after length \a width are removed, and the copy is returned. \code QString s( "apple" ); QString t = s.leftJustify( 8, '.' ); // t == "apple..." \endcode \sa rightJustify() */ QString QString::leftJustify( uint width, QChar fill, bool truncate ) const { QString result; int len = length(); int padlen = width - len; if ( padlen > 0 ) { result.setLength(len+padlen); if ( len ) memcpy( result.d->unicode, unicode(), sizeof(QChar)*len ); QChar* uc = result.d->unicode + len; 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++; } } return *this; } /*! \overload \fn QString &QString::remove( char c ) 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, ""). */ /*! \overload Removes every occurrence of \a str in the string. Returns a reference to the string. This is the same as replace(\a str, ""). */ QString &QString::remove( const QString & str ) { int index = 0; if ( !str.isEmpty() ) { while ( (index = find(str, index)) != -1 ) remove( index, str.length() ); } return *this; } /*! \overload @@ -15755,447 +15793,455 @@ QString &QString::replace( const QRegExp &rx, const QString &str ) Returns the position of the first match of \a rx or -1 if no match was found. \code QString string( "bananas" ); int i = string.find( QRegExp("an"), 0 ); // i == 1 \endcode \sa findRev() replace() contains() */ int QString::find( const QRegExp &rx, int index ) const { return rx.search( *this, index ); } /*! \overload Finds the first match of the regexp \a rx, 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. (See findRev() for searching backwards.) Returns the position of the match or -1 if no match was found. \code QString string( "bananas" ); int i = string.findRev( QRegExp("an") ); // i == 3 \endcode \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 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( short 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( ushort 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. */ /*! \overload Sets the string to the printed value of \a n, formatted in format @@ -16368,792 +16414,892 @@ void QString::setExpand( uint index, QChar c ) d->unicode[--index]=' '; } /*! \fn const char* QString::data() const \obsolete Returns a pointer to a '\0'-terminated classic C string. In Qt 1.x, this returned a char* allowing direct manipulation of the string as a sequence of bytes. In Qt 2.x where QString is a Unicode string, char* conversion constructs a temporary string, and hence direct character operations are meaningless. */ /*! \fn bool QString::operator!() const Returns TRUE if this is a null string; otherwise returns FALSE. \code QString name = getName(); if ( !name ) name = "Rodney"; \endcode Note that if you say \code QString name = getName(); 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) Returns the QChar at index \a i by reference, expanding the string with QChar::null if necessary. The resulting reference can be assigned to, or otherwise used immediately, but becomes invalid once furher modifications are made to the string. \code QString string("ABCDEF"); QChar ch = string.ref( 3 ); // ch == 'D' \endcode \sa constref() */ /*! \fn QChar QString::operator[]( int ) const Returns the character at index \a i, or QChar::null if \a i is beyond the length of the string. If the QString is not const (i.e., const QString) or const\& (i.e., const QString\&), then the non-const overload of operator[] will be used instead. */ /*! \fn QCharRef QString::operator[]( int ) \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::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 ); } /*! \fn int QString::localeAwareCompare( const QString & s1, const QString & s2 ) 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 performed in a locale- and also platform-dependent manner. Use this function to present sorted lists of strings to the user. \sa QString::compare() QTextCodec::locale() */ /*! \overload Compares this string with \a s. */ #if !defined(CSTR_LESS_THAN) #define CSTR_LESS_THAN 1 #define CSTR_EQUAL 2 #define CSTR_GREATER_THAN 3 #endif int QString::localeAwareCompare( const QString& s ) const { // do the right thing for null and empty if ( isEmpty() || s.isEmpty() ) return compare( 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 @@ -996,193 +996,193 @@ void QTextStream::ts_putc( int ch ) { ts_putc( QChar((ushort)ch) ); } bool QTextStream::ts_isdigit( QChar c ) { return c.isDigit(); } bool QTextStream::ts_isspace( QChar c ) { return c.isSpace(); } void QTextStream::ts_ungetc( QChar c ) { if ( c.unicode() == 0xffff ) return; d->ungetcBuf.prepend( c ); } /*! Reads \a len bytes from the stream into \a s and returns a reference to the stream. The buffer \a s must be preallocated. Note that no encoding is done by this function. \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() */ void QTextStream::unsetDevice() { setDevice( 0 ); d->sourceType = QTextStreamPrivate::NotSet; } /*! \fn bool QTextStream::atEnd() const Returns TRUE if the IO device has reached the end position (end of the stream or file) or if there is no IO device set; otherwise returns FALSE. \sa QIODevice::atEnd() */ /*!\fn bool QTextStream::eof() const \obsolete This function has been renamed to atEnd(). \sa QIODevice::atEnd() */ /***************************************************************************** QTextStream read functions *****************************************************************************/ 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 @@ -203,466 +203,342 @@ void QUType_idisp::set( QUObject *o, QDispatchInterface* idisp ) o->type = this; } bool QUType_idisp::canConvertFrom( QUObject *o, QUType *t ) { return t->canConvertTo( o, this ); } bool QUType_idisp::canConvertTo( QUObject * /*o*/, QUType *t ) { return isEqual( t, &static_QUType_iface ); } bool QUType_idisp::convertFrom( QUObject *o, QUType *t ) { return t->convertTo( o, this ); } bool QUType_idisp::convertTo( QUObject *o, QUType *t ) { #ifndef QT_NO_COMPONENT if ( isEqual( t, &static_QUType_iface ) ) { o->payload.iface = (QUnknownInterface*)o->payload.idisp; o->type = &static_QUType_iface; return TRUE; } #endif return FALSE; } 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 @@ -31,280 +31,285 @@ ** 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; #include "qwaitcondition.h" #include "qmutex.h" #include "qmutex_p.h" #include <errno.h> #include <string.h> struct QWaitConditionPrivate { pthread_cond_t cond; }; /*! \class QWaitCondition qwaitcondition.h \threadsafe \brief The QWaitCondition class allows waiting/waking for conditions between threads. \ingroup thread \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 |