summaryrefslogtreecommitdiff
path: root/qmake/tools
Side-by-side diff
Diffstat (limited to 'qmake/tools') (more/less context) (show whitespace changes)
-rw-r--r--qmake/tools/qbitarray.cpp3
-rw-r--r--qmake/tools/qbuffer.cpp4
-rw-r--r--qmake/tools/qcomlibrary.cpp15
-rw-r--r--qmake/tools/qconfig.cpp14
-rw-r--r--qmake/tools/qcriticalsection_p.cpp2
-rw-r--r--qmake/tools/qcstring.cpp91
-rw-r--r--qmake/tools/qdatastream.cpp14
-rw-r--r--qmake/tools/qdatetime.cpp62
-rw-r--r--qmake/tools/qdir.cpp86
-rw-r--r--qmake/tools/qdir_unix.cpp46
-rw-r--r--qmake/tools/qfile.cpp3
-rw-r--r--qmake/tools/qfile_unix.cpp13
-rw-r--r--qmake/tools/qfileinfo.cpp4
-rw-r--r--qmake/tools/qfileinfo_unix.cpp4
-rw-r--r--qmake/tools/qgarray.cpp97
-rw-r--r--qmake/tools/qgdict.cpp5
-rw-r--r--qmake/tools/qglist.cpp6
-rw-r--r--qmake/tools/qglobal.cpp45
-rw-r--r--qmake/tools/qgpluginmanager.cpp4
-rw-r--r--qmake/tools/qgvector.cpp9
-rw-r--r--qmake/tools/qlibrary.cpp13
-rw-r--r--qmake/tools/qlibrary_unix.cpp21
-rw-r--r--qmake/tools/qmutex_unix.cpp6
-rw-r--r--qmake/tools/qmutexpool.cpp78
-rw-r--r--qmake/tools/qregexp.cpp64
-rw-r--r--qmake/tools/qsemaphore_unix.cpp26
-rw-r--r--qmake/tools/qsettings.cpp321
-rw-r--r--qmake/tools/qstring.cpp428
-rw-r--r--qmake/tools/qtextstream.cpp2
-rw-r--r--qmake/tools/qucom.cpp134
-rw-r--r--qmake/tools/qwaitcondition_unix.cpp13
31 files changed, 1035 insertions, 598 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
@@ -1,661 +1,662 @@
/****************************************************************************
** $Id$
**
** Implementation of QBitArray class
**
** Created : 940118
**
** 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 "qbitarray.h"
#include "qdatastream.h"
#define SHBLOCK ((bitarr_data*)(sharedBlock()))
/*!
\class QBitVal qbitarray.h
\reentrant
\brief The QBitVal class is an internal class, used with QBitArray.
\ingroup collection
The QBitVal is required by the indexing [] operator on bit arrays.
It is not for use in any other context.
*/
/*!
\fn QBitVal::QBitVal (QBitArray* a, uint i)
Constructs a reference to element \a i in the QBitArray \a a.
This is what QBitArray::operator[] constructs its return value
with.
*/
/*!
\fn QBitVal::operator int()
Returns the value referenced by the QBitVal.
*/
/*!
\fn QBitVal& QBitVal::operator= (const QBitVal& v)
Sets the value referenced by the QBitVal to that referenced by
QBitVal \a v.
*/
/*!
\overload QBitVal& QBitVal::operator= (bool v)
Sets the value referenced by the QBitVal to \a v.
*/
/*!
\class QBitArray qbitarray.h
\reentrant
\brief The QBitArray class provides an array of bits.
\ingroup collection
\ingroup tools
\ingroup shared
Because QBitArray is a QMemArray, it uses explicit \link
shclass.html sharing\endlink with a reference count.
A QBitArray is a special byte array that can access individual
bits and perform bit-operations (AND, OR, XOR and NOT) on entire
arrays or bits.
Bits can be manipulated by the setBit() and clearBit() functions,
but it is also possible to use the indexing [] operator to test
and set individual bits. The [] operator is a little slower than
setBit() and clearBit() because some tricks are required to
implement single-bit assignments.
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;
}
#endif
return (*(data()+(index>>3)) & (1 << (index & 7))) != 0;
}
/*!
\overload
Sets the bit at position \a index to 1.
\sa clearBit() toggleBit()
*/
void QBitArray::setBit( uint index )
{
#if defined(QT_CHECK_RANGE)
if ( index >= size() ) {
qWarning( "QBitArray::setBit: Index %d out of range", index );
return;
}
#endif
*(data()+(index>>3)) |= (1 << (index & 7));
}
/*!
\fn void QBitArray::setBit( uint index, bool value )
Sets the bit at position \a index to \a value.
Equivalent to:
\code
if ( value )
setBit( index );
else
clearBit( index );
\endcode
\sa clearBit() toggleBit()
*/
/*!
Clears the bit at position \a index, i.e. sets it to 0.
\sa setBit(), toggleBit()
*/
void QBitArray::clearBit( uint index )
{
#if defined(QT_CHECK_RANGE)
if ( index >= size() ) {
qWarning( "QBitArray::clearBit: Index %d out of range", index );
return;
}
#endif
*(data()+(index>>3)) &= ~(1 << (index & 7));
}
/*!
Toggles the bit at position \a index.
If the previous value was 0, the new value will be 1. If the
previous value was 1, the new value will be 0.
\sa setBit(), clearBit()
*/
bool QBitArray::toggleBit( uint index )
{
#if defined(QT_CHECK_RANGE)
if ( index >= size() ) {
qWarning( "QBitArray::toggleBit: Index %d out of range", index );
return FALSE;
}
#endif
register uchar *p = (uchar *)data() + (index>>3);
uchar b = (1 << (index & 7)); // bit position
uchar c = *p & b; // read bit
*p ^= b; // toggle bit
return c;
}
/*!
\fn bool QBitArray::at( uint index ) const
Returns the value (0 or 1) of the bit at position \a index.
\sa operator[]()
*/
/*!
\fn QBitVal QBitArray::operator[]( int index )
Implements the [] operator for bit arrays.
The returned QBitVal is a context object. It makes it possible to
get and set a single bit value by its \a index position.
Example:
\code
QBitArray a( 3 );
a[0] = 0;
a[1] = 1;
a[2] = a[0] ^ a[1];
\endcode
The functions testBit(), setBit() and clearBit() are faster.
\sa at()
*/
/*!
\overload bool QBitArray::operator[]( int index ) const
Implements the [] operator for constant bit arrays.
*/
/*!
Performs the AND operation between all bits in this bit array and
\a a. Returns a reference to this bit array.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\code
QBitArray a( 3 ), b( 2 );
a[0] = 1; a[1] = 0; a[2] = 1; // a = [1 0 1]
b[0] = 1; b[1] = 0; // b = [1 0]
a &= b; // a = [1 0 0]
\endcode
\sa operator|=(), operator^=(), operator~()
*/
QBitArray &QBitArray::operator&=( const QBitArray &a )
{
resize( QMAX(size(), a.size()) );
register uchar *a1 = (uchar *)data();
register uchar *a2 = (uchar *)a.data();
int n = QMIN( QByteArray::size(), a.QByteArray::size() );
int p = QMAX( QByteArray::size(), a.QByteArray::size() ) - n;
while ( n-- > 0 )
*a1++ &= *a2++;
while ( p-- > 0 )
*a1++ = 0;
return *this;
}
/*!
Performs the OR operation between all bits in this bit array and
\a a. Returns a reference to this bit array.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\code
QBitArray a( 3 ), b( 2 );
a[0] = 1; a[1] = 0; a[2] = 1; // a = [1 0 1]
b[0] = 1; b[1] = 0; // b = [1 0]
a |= b; // a = [1 0 1]
\endcode
\sa operator&=(), operator^=(), operator~()
*/
QBitArray &QBitArray::operator|=( const QBitArray &a )
{
resize( QMAX(size(), a.size()) );
register uchar *a1 = (uchar *)data();
register uchar *a2 = (uchar *)a.data();
int n = QMIN( QByteArray::size(), a.QByteArray::size() );
while ( n-- > 0 )
*a1++ |= *a2++;
return *this;
}
/*!
Performs the XOR operation between all bits in this bit array and
\a a. Returns a reference to this bit array.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\code
QBitArray a( 3 ), b( 2 );
a[0] = 1; a[1] = 0; a[2] = 1; // a = [1 0 1]
b[0] = 1; b[1] = 0; // b = [1 0]
a ^= b; // a = [0 0 1]
\endcode
\sa operator&=(), operator|=(), operator~()
*/
QBitArray &QBitArray::operator^=( const QBitArray &a )
{
resize( QMAX(size(), a.size()) );
register uchar *a1 = (uchar *)data();
register uchar *a2 = (uchar *)a.data();
int n = QMIN( QByteArray::size(), a.QByteArray::size() );
while ( n-- > 0 )
*a1++ ^= *a2++;
return *this;
}
/*!
Returns a bit array that contains the inverted bits of this bit array.
Example:
\code
QBitArray a( 3 ), b;
a[0] = 1; a[1] = 0; a[2] = 1; // a = [1 0 1]
b = ~a; // b = [0 1 0]
\endcode
*/
QBitArray QBitArray::operator~() const
{
QBitArray a( size() );
register uchar *a1 = (uchar *)data();
register uchar *a2 = (uchar *)a.data();
int n = QByteArray::size();
while ( n-- )
*a2++ = ~*a1++;
a.pad0();
return a;
}
/*!
\relates QBitArray
Returns the AND result between the bit arrays \a a1 and \a a2.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\sa QBitArray::operator&=()
*/
QBitArray operator&( const QBitArray &a1, const QBitArray &a2 )
{
QBitArray tmp = a1.copy();
tmp &= a2;
return tmp;
}
/*!
\relates QBitArray
Returns the OR result between the bit arrays \a a1 and \a a2.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\sa QBitArray::operator|=()
*/
QBitArray operator|( const QBitArray &a1, const QBitArray &a2 )
{
QBitArray tmp = a1.copy();
tmp |= a2;
return tmp;
}
/*!
\relates QBitArray
Returns the XOR result between the bit arrays \a a1 and \a a2.
The result has the length of the longest of the two bit arrays,
with any missing bits (i.e. if one array is shorter than the
other), taken to be 0.
\sa QBitArray::operator^()
*/
QBitArray operator^( const QBitArray &a1, const QBitArray &a2 )
{
QBitArray tmp = a1.copy();
tmp ^= a2;
return tmp;
}
/* \enum QGArray::array_data
\warning This will be renamed in the next major release of Qt. Until
then it is undocumented and we recommend against its use.
\internal
### 3.0 rename ###
### 3.0 move it to QGArray? ###
*/
/*!
\fn QBitArray::array_data * QBitArray::newData()
\internal
Returns data specific to QBitArray that extends what QGArray provides.
QPtrCollection mechanism for allowing extra/different data.
*/
/*!
\fn void QBitArray::deleteData ( array_data * d )
\internal
Deletes data specific to QBitArray that extended what QGArray provided.
QPtrCollection mechanism for allowing extra/different data.
*/
/*****************************************************************************
QBitArray stream functions
*****************************************************************************/
/*!
\relates QBitArray
Writes bit array \a a to stream \a s.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
#ifndef QT_NO_DATASTREAM
QDataStream &operator<<( QDataStream &s, const QBitArray &a )
{
Q_UINT32 len = a.size();
s << len; // write size of array
if ( len > 0 ) // write data
s.writeRawBytes( a.data(), a.QByteArray::size() );
return s;
}
/*!
\relates QBitArray
Reads a bit array into \a a from stream \a s.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QBitArray &a )
{
Q_UINT32 len;
s >> len; // read size of array
if ( !a.resize( (uint)len ) ) { // resize array
#if defined(QT_CHECK_NULL)
qWarning( "QDataStream: Not enough memory to read QBitArray" );
#endif
len = 0;
}
if ( len > 0 ) // read data
s.readRawBytes( a.data(), a.QByteArray::size() );
return s;
}
#endif // QT_NO_DATASTREAM
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
@@ -1,495 +1,495 @@
/****************************************************************************
** $Id$
**
** Implementation of QBuffer 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 "qbuffer.h"
#include <stdlib.h>
/*!
\class QBuffer qbuffer.h
\reentrant
\brief The QBuffer class is an I/O device that operates on a QByteArray.
\ingroup io
\ingroup collection
QBuffer is used to read and write to a memory buffer. It is
normally used with a QTextStream or a QDataStream. QBuffer has an
associated QByteArray which holds the buffer data. The size() of
the buffer is automatically adjusted as data is written.
The constructor \c QBuffer(QByteArray) creates a QBuffer using an
existing byte array. The byte array can also be set with
setBuffer(). Writing to the QBuffer will modify the original byte
array because QByteArray is \link shclass.html explicitly
shared.\endlink
Use open() to open the buffer before use and to set the mode
(read-only, write-only, etc.). close() closes the buffer. The
buffer must be closed before reopening or calling setBuffer().
A common way to use QBuffer is through \l QDataStream or \l
QTextStream, which have constructors that take a QBuffer
parameter. For convenience, there are also QDataStream and
QTextStream constructors that take a QByteArray parameter. These
constructors create and open an internal QBuffer.
Note that QTextStream can also operate on a QString (a Unicode
string); a QBuffer cannot.
You can also use QBuffer directly through the standard QIODevice
functions readBlock(), writeBlock() readLine(), at(), getch(),
putch() and ungetch().
\sa QFile, QDataStream, QTextStream, QByteArray, \link shclass.html Shared Classes\endlink
*/
/*!
Constructs an empty buffer.
*/
QBuffer::QBuffer()
{
setFlags( IO_Direct );
a_inc = 16; // initial increment
a_len = 0;
ioIndex = 0;
}
/*!
Constructs a buffer that operates on \a buf.
If you open the buffer in write mode (\c IO_WriteOnly or
\c IO_ReadWrite) and write something into the buffer, \a buf
will be modified.
Example:
\code
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
qWarning( "QBuffer::readBlock: Read operation not permitted" );
return -1;
}
#endif
if ( ioIndex + len > a.size() ) { // overflow
if ( ioIndex >= a.size() ) {
return 0;
} else {
len = a.size() - ioIndex;
}
}
memcpy( p, a.data()+ioIndex, len );
ioIndex += len;
return len;
}
/*!
\overload Q_LONG QBuffer::writeBlock( const QByteArray& data )
This convenience function is the same as calling
\c{writeBlock( data.data(), data.size() )} with \a data.
*/
/*!
Writes \a len bytes from \a p into the buffer at the current
index position, overwriting any characters there and extending the
buffer if necessary. Returns the number of bytes actually written.
Returns -1 if an error occurred.
\sa readBlock()
*/
Q_LONG QBuffer::writeBlock( const char *p, Q_ULONG len )
{
if ( len == 0 )
return 0;
#if defined(QT_CHECK_NULL)
if ( p == 0 ) {
qWarning( "QBuffer::writeBlock: Null pointer error" );
return -1;
}
#endif
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QBuffer::writeBlock: Buffer not open" );
return -1;
}
if ( !isWritable() ) { // writing not permitted
qWarning( "QBuffer::writeBlock: Write operation not permitted" );
return -1;
}
#endif
if ( ioIndex + len >= a_len ) { // overflow
Q_ULONG new_len = a_len + a_inc*((ioIndex+len-a_len)/a_inc+1);
if ( !a.resize( new_len ) ) { // could not resize
#if defined(QT_CHECK_NULL)
qWarning( "QBuffer::writeBlock: Memory allocation error" );
#endif
setStatus( IO_ResourceError );
return -1;
}
a_inc *= 2; // double increment
a_len = new_len;
a.shd->len = ioIndex + len;
}
memcpy( a.data()+ioIndex, p, len );
ioIndex += len;
if ( a.shd->len < ioIndex )
a.shd->len = ioIndex; // fake (not alloc'd) length
return len;
}
/*!
\reimp
*/
Q_LONG QBuffer::readLine( char *p, Q_ULONG maxlen )
{
#if defined(QT_CHECK_NULL)
if ( p == 0 ) {
qWarning( "QBuffer::readLine: Null pointer error" );
return -1;
}
#endif
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QBuffer::readLine: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QBuffer::readLine: Read operation not permitted" );
return -1;
}
#endif
if ( maxlen == 0 )
return 0;
Q_ULONG start = ioIndex;
char *d = a.data() + ioIndex;
maxlen--; // make room for 0-terminator
if ( a.size() - ioIndex < maxlen )
maxlen = a.size() - ioIndex;
while ( maxlen-- ) {
if ( (*p++ = *d++) == '\n' )
break;
}
*p = '\0';
ioIndex = d - a.data();
return ioIndex - start;
}
/*!
\reimp
*/
int QBuffer::getch()
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QBuffer::getch: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QBuffer::getch: Read operation not permitted" );
return -1;
}
#endif
if ( ioIndex+1 > a.size() ) { // overflow
setStatus( IO_ReadError );
return -1;
}
return uchar(*(a.data()+ioIndex++));
}
/*!
\reimp
Writes the character \a ch into the buffer at the current index
position, overwriting any existing character and extending the
buffer if necessary.
Returns \a ch, or -1 if an error occurred.
\sa getch(), ungetch()
*/
int QBuffer::putch( int ch )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QBuffer::putch: Buffer not open" );
return -1;
}
if ( !isWritable() ) { // writing not permitted
qWarning( "QBuffer::putch: Write operation not permitted" );
return -1;
}
#endif
if ( ioIndex + 1 >= a_len ) { // overflow
char buf[1];
buf[0] = (char)ch;
if ( writeBlock(buf,1) != 1 )
return -1; // write error
} else {
*(a.data() + ioIndex++) = (char)ch;
if ( a.shd->len < ioIndex )
a.shd->len = ioIndex;
}
return ch;
}
/*!
\reimp
*/
int QBuffer::ungetch( int ch )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QBuffer::ungetch: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QBuffer::ungetch: Read operation not permitted" );
return -1;
}
#endif
if ( ch != -1 ) {
if ( ioIndex )
ioIndex--;
else
ch = -1;
}
return ch;
}
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,538 +1,535 @@
/****************************************************************************
** $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;
if ( ! current || pos == s_len + 1 ) {
// save result
token_info.results[ (int)field ] = s;
token_info.lengths[ (int)field ] = fieldlen - 1;
// end of string
ret = 0;
break;
}
if ( current == token_info.fields[ field ] ) {
// save result
token_info.results[ (int)field ] = s;
token_info.lengths[ (int)field ] = fieldlen - 1;
// end of field
fieldlen = 0;
++field;
if ( field == token_info.field_count - 1 ) {
// parse ok
ret = 1;
}
if ( field == token_info.field_count ) {
// done parsing
break;
}
// reset string and its length
s = s + pos;
s_len -= pos;
pos = 0;
}
}
return ret;
}
/*
returns TRUE if the string s was correctly parsed, FALSE otherwise.
*/
static bool qt_parse_pattern( const char *s, uint *version, uint *flags,
QCString *key )
{
bool ret = TRUE;
qt_token_info pinfo("=\n", 2);
int parse;
ulong at = 0, advance, parselen = qstrlen( s );
do {
parse = qt_tokenize( s + at, parselen, &advance, pinfo );
if ( parse == -1 ) {
ret = FALSE;
break;
}
at += advance;
parselen -= advance;
if ( qstrncmp( "version", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
// parse version string
qt_token_info pinfo2("..-", 3);
if ( qt_tokenize( pinfo.results[ 1 ], pinfo.lengths[ 1 ],
&advance, pinfo2 ) != -1 ) {
QCString m( pinfo2.results[ 0 ], pinfo2.lengths[ 0 ] + 1 );
QCString n( pinfo2.results[ 1 ], pinfo2.lengths[ 1 ] + 1 );
QCString p( pinfo2.results[ 2 ], pinfo2.lengths[ 2 ] + 1 );
*version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt();
} else {
ret = FALSE;
break;
}
} else if ( qstrncmp( "flags", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
// parse flags string
char ch;
*flags = 0;
ulong p = 0, c = 0, bit = 0;
while ( p < pinfo.lengths[ 1 ] ) {
ch = pinfo.results[ 1 ][ p ];
bit = pinfo.lengths[ 1 ] - p - 1;
c = 1 << bit;
if ( ch == '1' ) {
*flags |= c;
} else if ( ch != '0' ) {
ret = FALSE;
break;
}
++p;
}
} else if ( qstrncmp( "buildkey", pinfo.results[ 0 ],
pinfo.lengths[ 0 ] ) == 0 ){
// save buildkey
*key = QCString( pinfo.results[ 1 ], pinfo.lengths[ 1 ] + 1 );
}
} while ( parse == 1 && parselen > 0 );
return ret;
}
#if defined(Q_OS_UNIX)
#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX)
# define USE_MMAP
# include <sys/types.h>
# include <sys/mman.h>
#endif // Q_OS_FREEBSD || Q_OS_LINUX
static long qt_find_pattern( const char *s, ulong s_len,
const char *pattern, ulong p_len )
{
/*
this uses the same algorithm as QString::findRev...
we search from the end of the file because on the supported
systems, the read-only data/text segments are placed at the end
of the file. HOWEVER, when building with debugging enabled, all
the debug symbols are placed AFTER the data/text segments.
what does this mean? when building in release mode, the search
is fast because the data we are looking for is at the end of the
file... when building in debug mode, the search is slower
because we have to skip over all the debugging symbols first
*/
if ( ! s || ! pattern || p_len > s_len ) return -1;
ulong i, hs = 0, hp = 0, delta = s_len - p_len;
for (i = 0; i < p_len; ++i ) {
hs += s[delta + i];
hp += pattern[i];
}
i = delta;
for (;;) {
if ( hs == hp && qstrncmp( s + i, pattern, p_len ) == 0 )
return i;
if ( i == 0 )
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 );
}
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;
}
}
- }
#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
@@ -1,2474 +1,2511 @@
/****************************************************************************
** $Id$
**
** Implementation of extended char array operations, and QByteArray and
** QCString classes
**
** Created : 920722
**
** 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 "qstring.h"
#include "qregexp.h"
#include "qdatastream.h"
#ifdef QT_THREAD_SUPPORT
# include <private/qmutexpool_p.h>
#endif // QT_THREAD_SUPPORT
#include <stdio.h>
#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)
+/*!
+ \fn QByteArray qCompress( const QByteArray& data )
+
\relates QByteArray
- \overload
+
+ Compresses the array \a data and returns the compressed byte
+ array.
+
+ \sa qUncompress()
*/
/*!
\relates QByteArray
+ \overload
+
Compresses the array \a data which is \a nbytes long and returns the
compressed byte array.
-
- \sa qUncompress()
*/
#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 )
+/*!
+ \fn QByteArray qUncompress( const QByteArray& data )
+
\relates QByteArray
- \overload
+
+ 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
+ \overload
+
Uncompresses the array \a data which is \a nbytes long and returns
the uncompressed byte array.
-
- Returns an empty QByteArray if the input data was corrupt.
-
- \sa qCompress()
*/
#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
*/
#ifndef QT_NO_DATASTREAM
QDataStream &operator<<( QDataStream &s, const QByteArray &a )
{
return s.writeBytes( a.data(), a.size() );
}
/*!
\relates QMemArray
Reads a byte array into \a a from the stream \a s and returns a
reference to the stream.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QByteArray &a )
{
Q_UINT32 len;
s >> len; // read size of array
if ( len == 0 || s.eof() ) { // end of file reached
a.resize( 0 );
return s;
}
if ( !a.resize( (uint)len ) ) { // resize array
#if defined(QT_CHECK_NULL)
qWarning( "QDataStream: Not enough memory to read QByteArray" );
#endif
len = 0;
}
if ( len > 0 ) // not null array
s.readRawBytes( a.data(), (uint)len );
return s;
}
#endif //QT_NO_DATASTREAM
/*****************************************************************************
QCString member functions
*****************************************************************************/
/*!
\class QCString qcstring.h
\reentrant
\brief The QCString class provides an abstraction of the classic C
zero-terminated char array (char *).
\ingroup text
\ingroup collection
\ingroup tools
\ingroup shared
QCString inherits QByteArray, which is defined as
QMemArray\<char\>. Since QCString is a QMemArray, it uses \link
shclass.html explicit sharing\endlink with a reference count.
QCString tries to behave like a more convenient \c{const char *}.
The price of doing this is that some algorithms will perform
badly. For example, append() is O(length()) since it scans for a
null terminator. Although you might use QCString for text that is
never exposed to the user, for most purposes, and especially for
user-visible text, you should use QString. QString provides
implicit sharing, Unicode and other internationalization support,
and is well optimized.
Note that for the QCString methods that take a \c{const char *}
parameter the \c{const char *} must either be 0 (null) or not-null
and '\0' (NUL byte) terminated; otherwise the results are
undefined.
A QCString that has not been assigned to anything is \e null, i.e.
both the length and the data pointer is 0. A QCString that
references the empty string ("", a single '\0' char) is \e empty.
Both null and empty QCStrings are legal parameters to the methods.
Assigning \c{const char *} 0 to QCString produces a null QCString.
The length() function returns the length of the string; resize()
resizes the string and truncate() truncates the string. A string
can be filled with a character using fill(). Strings can be left
or right padded with characters using leftJustify() and
rightJustify(). Characters, strings and regular expressions can be
searched for using find() and findRev(), and counted using
contains().
Strings and characters can be inserted with insert() and appended
with append(). A string can be prepended with prepend().
Characters can be removed from the string with remove() and
replaced with replace().
Portions of a string can be extracted using left(), right() and
mid(). Whitespace can be removed using stripWhiteSpace() and
simplifyWhiteSpace(). Strings can be converted to uppercase or
lowercase with upper() and lower() respectively.
Strings that contain numbers can be converted to numbers with
toShort(), toInt(), toLong(), toULong(), toFloat() and toDouble().
Numbers can be converted to strings with setNum().
Many operators are overloaded to work with QCStrings. QCString
also supports some more obscure functions, e.g. sprintf(),
setStr() and setExpand().
\target asciinotion
\sidebar Note on Character Comparisons
In QCString the notion of uppercase and lowercase and of which
character is greater than or less than another character is locale
dependent. This affects functions which support a case insensitive
option or which compare or lowercase or uppercase their arguments.
Case insensitive operations and comparisons will be accurate if
both strings contain only ASCII characters. (If \c $LC_CTYPE is
set, most Unix systems do "the right thing".) Functions that this
affects include contains(), find(), findRev(), \l operator<(), \l
operator<=(), \l operator>(), \l operator>=(), lower() and
upper().
This issue does not apply to \l{QString}s since they represent
characters using Unicode.
\endsidebar
Performance note: The QCString methods for QRegExp searching are
implemented by converting the QCString to a QString and performing
the search on that. This implies a deep copy of the QCString data.
If you are going to perform many QRegExp searches on a large
QCString, you will get better performance by converting the
QCString to a QString yourself, and then searching in the QString.
*/
/*!
\fn QCString::QCString()
Constructs a null string.
\sa isNull()
*/
/*!
\fn QCString::QCString( const QCString &s )
Constructs a shallow copy \a s.
\sa assign()
*/
/*!
Constructs a string with room for \a size characters, including
the '\0'-terminator. Makes a null string if \a size == 0.
If \a size \> 0, then the first and last characters in the string
are initialized to '\0'. All other characters are uninitialized.
\sa resize(), isNull()
*/
QCString::QCString( int size )
: QByteArray( size )
{
if ( size > 0 ) {
*data() = '\0'; // set terminator
*(data()+(size-1)) = '\0';
}
}
/*!
Constructs a string that is a deep copy of \a str.
If \a str is 0 a null string is created.
\sa isNull()
*/
QCString::QCString( const char *str )
{
duplicate( str, qstrlen(str) + 1 );
}
/*!
Constructs a string that is a deep copy of \a str. The copy will
be at most \a maxsize bytes long including the '\0'-terminator.
Example:
\code
QCString str( "helloworld", 6 ); // assigns "hello" to str
\endcode
If \a str contains a 0 byte within the first \a maxsize bytes, the
resulting QCString will be terminated by this 0. If \a str is 0 a
null string is created.
\sa isNull()
*/
QCString::QCString( const char *str, uint maxsize )
{
if ( str == 0 )
return;
uint len; // index of first '\0'
for ( len = 0; len < maxsize - 1; len++ ) {
if ( str[len] == '\0' )
break;
}
QByteArray::resize( len + 1 );
memcpy( data(), str, len );
data()[len] = 0;
}
/*!
\reimp
*/
QCString::~QCString()
{
}
/*!
\fn QCString &QCString::operator=( const QCString &s )
Assigns a shallow copy of \a s to this string and returns a
reference to this string.
*/
/*!
\overload QCString &QCString::operator=( const char *str )
Assigns a deep copy of \a str to this string and returns a
reference to this string.
If \a str is 0 a null string is created.
\sa isNull()
*/
/*!
\fn bool QCString::isNull() const
Returns TRUE if the string is null, i.e. if data() == 0; otherwise
returns FALSE. A null string is also an empty string.
Example:
\code
QCString a; // a.data() == 0, a.size() == 0, a.length() == 0
QCString b == ""; // b.data() == "", b.size() == 1, b.length() == 0
a.isNull(); // TRUE because a.data() == 0
a.isEmpty(); // TRUE because a.length() == 0
b.isNull(); // FALSE because b.data() == ""
b.isEmpty(); // TRUE because b.length() == 0
\endcode
\sa isEmpty(), length(), size()
*/
/*!
\fn bool QCString::isEmpty() const
Returns TRUE if the string is empty, i.e. if length() == 0;
otherwise returns FALSE. An empty string is not always a null
string.
See example in isNull().
\sa isNull(), length(), size()
*/
/*!
\fn uint QCString::length() const
Returns the length of the string, excluding the '\0'-terminator.
Equivalent to calling \c strlen(data()).
Null strings and empty strings have zero length.
\sa size(), isNull(), isEmpty()
*/
/*!
\fn bool QCString::truncate( uint pos )
Truncates the string at position \a pos.
Equivalent to calling \c resize(pos+1).
Example:
\code
QCString s = "truncate this string";
s.truncate( 5 ); // s == "trunc"
\endcode
\sa resize()
*/
/*!
Extends or shrinks the string to \a len bytes, including the
'\0'-terminator.
A '\0'-terminator is set at position \c{len - 1} unless
\c{len == 0}.
Example:
\code
QCString s = "resize this string";
s.resize( 7 ); // s == "resize"
\endcode
\sa truncate()
*/
bool QCString::resize( uint len )
{
detach();
uint wasNull = isNull();
if ( !QByteArray::resize(len) )
return FALSE;
if ( len )
data()[len - 1] = '\0';
if ( len > 0 && wasNull )
data()[0] = '\0';
return TRUE;
}
/*!
Implemented as a call to the native vsprintf() (see the manual for
your C library).
If the string is shorter than 256 characters, this sprintf() calls
resize(256) to decrease the chance of memory corruption. The
string is resized back to its actual length before sprintf()
returns.
Example:
\code
QCString s;
s.sprintf( "%d - %s", 1, "first" ); // result < 256 chars
QCString big( 25000 ); // very long string
big.sprintf( "%d - %s", 2, longString ); // result < 25000 chars
\endcode
\warning All vsprintf() implementations will write past the end of
the target string (*this) if the \a format specification and
arguments happen to be longer than the target string, and some
will also fail if the target string is longer than some arbitrary
implementation limit.
Giving user-supplied arguments to sprintf() is risky: Sooner or
later someone will paste a huge line into your application.
*/
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.
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::findRev( const char *str, int index, bool cs ) const
{
/*
See QString::find() for explanations.
*/
const uint sl = qstrlen( str );
const uint l = length();
int delta = l-sl;
if ( index < 0 )
index = delta;
if ( index < 0 || index > (int)l )
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()
*/
QCString QCString::leftJustify( uint width, char fill, bool truncate ) const
{
QCString result;
int len = qstrlen(data());
int padlen = width - len;
if ( padlen > 0 ) {
result.QByteArray::resize( len+padlen+1 );
memcpy( result.data(), data(), len );
memset( result.data()+len, fill, padlen );
result[len+padlen] = '\0';
} else {
if ( truncate )
result = left( width );
else
result = copy();
}
return result;
}
/*!
Returns a string of length \a width (plus one for the terminating
'\0') that contains zero or more of the \a fill character followed
by this string.
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("pie");
QCString t = s.rightJustify(8, '.'); // t == ".....pie"
\endcode
\sa leftJustify()
*/
QCString QCString::rightJustify( uint width, char fill, bool truncate ) const
{
QCString result;
int len = qstrlen(data());
int padlen = width - len;
if ( padlen > 0 ) {
result.QByteArray::resize( len+padlen+1 );
memset( result.data(), fill, padlen );
memcpy( result.data()+padlen, data(), len );
result[len+padlen] = '\0';
} else {
if ( truncate )
result = left( width );
else
result = copy();
}
return result;
}
/*!
Returns a new string that is a copy of this string converted to lower
case.
Example:
\code
QCString s("Credit");
QCString t = s.lower(); // t == "credit"
\endcode
\sa upper()
\link #asciinotion Note on character comparisons \endlink
*/
QCString QCString::lower() const
{
QCString s( data() );
register char *p = s.data();
if ( p ) {
while ( *p ) {
*p = tolower( (uchar) *p );
p++;
}
}
return s;
}
/*!
Returns a new string that is a copy of this string converted to upper case.
Example:
\code
QCString s( "Debit" );
QCString t = s.upper(); // t == "DEBIT"
\endcode
\sa lower()
\link #asciinotion Note on character comparisons \endlink
*/
QCString QCString::upper() const
{
QCString s( data() );
register char *p = s.data();
if ( p ) {
while ( *p ) {
*p = toupper(*p);
p++;
}
}
return s;
}
/*!
Returns a new string that has white space removed from the start
and the end.
White space means the decimal ASCII codes 9, 10, 11, 12, 13 and
32.
Example:
\code
QCString s = " space ";
QCString t = s.stripWhiteSpace(); // t == "space"
\endcode
\sa simplifyWhiteSpace()
*/
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();
+ 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
{
long v = toLong( ok );
if ( ok && *ok && (v < -32768 || v > 32767) )
*ok = FALSE;
return (short)v;
}
/*!
Returns the string converted to an \c{unsigned 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.
*/
ushort QCString::toUShort( bool *ok ) const
{
ulong v = toULong( ok );
if ( ok && *ok && (v > 65535) )
*ok = FALSE;
return (ushort)v;
}
/*!
Returns the string converted to a \c{int} 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.
*/
int QCString::toInt( bool *ok ) const
{
return (int)toLong( ok );
}
/*!
Returns the string converted to an \c{unsigned int} 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.
*/
uint QCString::toUInt( bool *ok ) const
{
return (uint)toULong( ok );
}
/*!
Returns the string converted to a \c{double} 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.
*/
double QCString::toDouble( bool *ok ) const
{
char *end;
double val = strtod( data() ? data() : "", &end );
if ( ok )
*ok = ( data() && *data() && ( end == 0 || *end == '\0' ) );
return val;
}
/*!
Returns the string converted to a \c{float} 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.
*/
float QCString::toFloat( bool *ok ) const
{
return (float)toDouble( ok );
}
/*!
Makes a deep copy of \a str. Returns a reference to the string.
*/
QCString &QCString::setStr( const char *str )
{
detach();
if ( str ) // valid string
store( str, qstrlen(str)+1 );
else // empty
resize( 0 );
return *this;
}
/*!
\overload
Sets the string to the string representation of the number \a n
and returns a reference to the string.
*/
QCString &QCString::setNum( long n )
{
detach();
char buf[20];
register char *p = &buf[19];
bool neg;
if ( n < 0 ) {
neg = TRUE;
n = -n;
} else {
neg = FALSE;
}
*p = '\0';
do {
*--p = ((int)(n%10)) + '0';
n /= 10;
} while ( n );
if ( neg )
*--p = '-';
store( p, qstrlen(p)+1 );
return *this;
}
/*!
\overload
Sets the string to the string representation of the number \a n
and returns a reference to the string.
*/
QCString &QCString::setNum( ulong n )
{
detach();
char buf[20];
register char *p = &buf[19];
*p = '\0';
do {
*--p = ((int)(n%10)) + '0';
n /= 10;
} while ( n );
store( p, qstrlen(p)+1 );
return *this;
}
/*!
\overload QCString &QCString::setNum( int n )
Sets the string to the string representation of the number \a n
and returns a reference to the string.
*/
/*!
\overload QCString &QCString::setNum( uint n )
Sets the string to the string representation of the number \a n
and returns a reference to the string.
*/
/*!
\overload QCString &QCString::setNum( short n )
Sets the string to the string representation of the number \a n
and returns a reference to the string.
*/
/*!
\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.
*/
/*!
\overload bool operator!=( const QCString &s1, const char *s2 )
\relates QCString
Returns TRUE if \a s1 and \a s2 are different; 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 different; otherwise returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) != 0.
*/
/*!
\fn bool operator<( const QCString &s1, const char *s2 )
\relates QCString
Returns TRUE if \a s1 is less than \a s2; otherwise returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \< 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\overload bool operator<( const char *s1, const QCString &s2 )
\relates QCString
Returns TRUE if \a s1 is less than \a s2; otherwise returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \< 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\fn bool operator<=( const QCString &s1, const char *s2 )
\relates QCString
Returns TRUE if \a s1 is less than or equal to \a s2; otherwise
returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \<= 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\overload bool operator<=( const char *s1, const QCString &s2 )
\relates QCString
Returns TRUE if \a s1 is less than or equal to \a s2; otherwise
returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \<= 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\fn bool operator>( const QCString &s1, const char *s2 )
\relates QCString
Returns TRUE if \a s1 is greater than \a s2; otherwise returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \> 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\overload bool operator>( const char *s1, const QCString &s2 )
\relates QCString
Returns TRUE if \a s1 is greater than \a s2; otherwise returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \> 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\fn bool operator>=( const QCString &s1, const char *s2 )
\relates QCString
Returns TRUE if \a s1 is greater than or equal to \a s2; otherwise
returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \>= 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\overload bool operator>=( const char *s1, const QCString &s2 )
\relates QCString
Returns TRUE if \a s1 is greater than or equal to \a s2; otherwise
returns FALSE.
Equivalent to qstrcmp(\a s1, \a s2) \>= 0.
\sa \link #asciinotion Note on character comparisons \endlink
*/
/*!
\fn const QCString operator+( const QCString &s1, const QCString &s2 )
\relates QCString
Returns a string which consists of the concatenation of \a s1 and
\a s2.
*/
/*!
\overload const QCString operator+( const QCString &s1, const char *s2 )
\relates QCString
Returns a string which consists of the concatenation of \a s1 and \a s2.
*/
/*!
\overload const QCString operator+( const char *s1, const QCString &s2 )
\relates QCString
Returns a string which consists of the concatenation of \a s1 and \a s2.
*/
/*!
\overload const QCString operator+( const QCString &s, char c )
\relates QCString
Returns a string which consists of the concatenation of \a s and \a c.
*/
/*!
\overload const QCString operator+( char c, const QCString &s )
\relates QCString
Returns a string which consists of the concatenation of \a c and \a s.
*/
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
@@ -1,1024 +1,1038 @@
/****************************************************************************
** $Id$
**
** Implementation of QDataStream class
**
** Created : 930831
**
** 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 "qdatastream.h"
#ifndef QT_NO_DATASTREAM
#include "qbuffer.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
/*!
\class QDataStream qdatastream.h
\reentrant
\brief The QDataStream class provides serialization of binary data
to a QIODevice.
\ingroup io
A data stream is a binary stream of encoded information which is
100% independent of the host computer's operating system, CPU or
byte order. For example, a data stream that is written by a PC
under Windows can be read by a Sun SPARC running Solaris.
You can also use a data stream to read/write \link #raw raw
unencoded binary data\endlink. If you want a "parsing" input
stream, see QTextStream.
The QDataStream class implements serialization of primitive types,
like \c char, \c short, \c int, \c char* etc. Serialization of
more complex data is accomplished by breaking up the data into
primitive units.
A data stream cooperates closely with a QIODevice. A QIODevice
represents an input/output medium one can read data from and write
data to. The QFile class is an example of an IO device.
Example (write binary data to a stream):
\code
QFile file( "file.dat" );
file.open( IO_WriteOnly );
QDataStream stream( &file ); // we will serialize the data into the file
stream << "the answer is"; // serialize a string
stream << (Q_INT32)42; // serialize an integer
\endcode
Example (read binary data from a stream):
\code
QFile file( "file.dat" );
file.open( IO_ReadOnly );
QDataStream stream( &file ); // read the data serialized from the file
QString str;
Q_INT32 a;
stream >> str >> a; // extract "the answer is" and 42
\endcode
Each item written to the stream is written in a predefined binary
format that varies depending on the item's type. Supported Qt
types include QBrush, QColor, QDateTime, QFont, QPixmap, QString,
QVariant and many others. For the complete list of all Qt types
supporting data streaming see the \link datastreamformat.html
Format of the QDataStream operators \endlink.
To take one example, a \c char* string is written as a 32-bit
integer equal to the length of the string including the NUL byte
('\0'), followed by all the characters of the string including the
NUL byte. When reading a \c char* string, 4 bytes are read to
create the 32-bit length value, then that many characters for the
\c char* string including the NUL are read.
The initial IODevice is usually set in the constructor, but can be
changed with setDevice(). If you've reached the end of the data
(or if there is no IODevice set) atEnd() will return TRUE.
If you want the data to be compatible with an earlier version of
Qt use setVersion().
If you want the data to be human-readable, e.g. for debugging, you
can set the data stream into printable data mode with
setPrintableData(). The data is then written slower, in a bloated
but human readable format.
If you are producing a new binary data format, such as a file
format for documents created by your application, you could use a
QDataStream to write the data in a portable format. Typically, you
would write a brief header containing a magic string and a version
number to give yourself room for future expansion. For example:
\code
QFile file( "file.xxx" );
file.open( IO_WriteOnly );
QDataStream stream( &file );
// Write a header with a "magic number" and a version
stream << (Q_UINT32)0xA0B0C0D0;
stream << (Q_INT32)123;
// Write the data
stream << [lots of interesting data]
\endcode
Then read it in with:
\code
QFile file( "file.xxx" );
file.open( IO_ReadOnly );
QDataStream stream( &file );
// Read and check the header
Q_UINT32 magic;
stream >> magic;
if ( magic != 0xA0B0C0D0 )
return XXX_BAD_FILE_FORMAT;
// Read the version
Q_INT32 version;
stream >> version;
if ( version < 100 )
return XXX_BAD_FILE_TOO_OLD;
if ( version > 123 )
return XXX_BAD_FILE_TOO_NEW;
if ( version <= 110 )
stream.setVersion(1);
// Read the data
stream >> [lots of interesting data];
if ( version > 120 )
stream >> [data new in XXX version 1.2];
stream >> [other interesting data];
\endcode
You can select which byte order to use when serializing data. The
default setting is big endian (MSB first). Changing it to little
endian breaks the portability (unless the reader also changes to
little endian). We recommend keeping this setting unless you have
special requirements.
\target raw
\section1 Reading and writing raw binary data
You may wish to read/write your own raw binary data to/from the
data stream directly. Data may be read from the stream into a
preallocated char* using readRawBytes(). Similarly data can be
written to the stream using writeRawBytes(). Notice that any
encoding/decoding of the data must be done by you.
A similar pair of functions is readBytes() and writeBytes(). These
differ from their \e raw counterparts as follows: readBytes()
reads a Q_UINT32 which is taken to be the length of the data to be
read, then that number of bytes is read into the preallocated
char*; writeBytes() writes a Q_UINT32 containing the length of the
data, followed by the data. Notice that any encoding/decoding of
the data (apart from the length Q_UINT32) must be done by you.
\sa QTextStream QVariant
*/
/*!
\enum QDataStream::ByteOrder
The byte order used for reading/writing the data.
\value BigEndian the default
\value LittleEndian
*/
/*****************************************************************************
QDataStream member functions
*****************************************************************************/
#if defined(QT_CHECK_STATE)
#undef CHECK_STREAM_PRECOND
#define CHECK_STREAM_PRECOND if ( !dev ) { \
qWarning( "QDataStream: No device" ); \
return *this; }
#else
#define CHECK_STREAM_PRECOND
#endif
static int systemWordSize = 0;
static bool systemBigEndian;
static const int DefaultStreamVersion = 5;
// 5 is default in Qt 3.1
// 4 is default in Qt 3.0
// 3 is default in Qt 2.1
// 2 is the Qt 2.0.x format
// 1 is the Qt 1.x format
/*!
Constructs a data stream that has no IO device.
\sa setDevice()
*/
QDataStream::QDataStream()
{
if ( systemWordSize == 0 ) // get system features
qSysInfo( &systemWordSize, &systemBigEndian );
dev = 0; // no device set
owndev = FALSE;
byteorder = BigEndian; // default byte order
printable = FALSE;
ver = DefaultStreamVersion;
noswap = systemBigEndian;
}
/*!
Constructs a data stream that uses the IO device \a d.
\warning If you use QSocket or QSocketDevice as the IO device \a d
for reading data, you must make sure that enough data is available
on the socket for the operation to successfully proceed;
QDataStream does not have any means to handle or recover from
short-reads.
\sa setDevice(), device()
*/
QDataStream::QDataStream( QIODevice *d )
{
if ( systemWordSize == 0 ) // get system features
qSysInfo( &systemWordSize, &systemBigEndian );
dev = d; // set device
owndev = FALSE;
byteorder = BigEndian; // default byte order
printable = FALSE;
ver = DefaultStreamVersion;
noswap = systemBigEndian;
}
/*!
Constructs a data stream that operates on a byte array, \a a,
through an internal QBuffer device. The \a mode is a
QIODevice::mode(), usually either \c IO_ReadOnly or \c
IO_WriteOnly.
Example:
\code
static char bindata[] = { 231, 1, 44, ... };
QByteArray a;
a.setRawData( bindata, sizeof(bindata) ); // a points to bindata
QDataStream stream( a, IO_ReadOnly ); // open on a's data
stream >> [something]; // read raw bindata
a.resetRawData( bindata, sizeof(bindata) ); // finished
\endcode
The QByteArray::setRawData() function is not for the inexperienced.
*/
QDataStream::QDataStream( QByteArray a, int mode )
{
if ( systemWordSize == 0 ) // get system features
qSysInfo( &systemWordSize, &systemBigEndian );
dev = new QBuffer( a ); // create device
((QBuffer *)dev)->open( mode ); // open device
owndev = TRUE;
byteorder = BigEndian; // default byte order
printable = FALSE;
ver = DefaultStreamVersion;
noswap = systemBigEndian;
}
/*!
Destroys the data stream.
The destructor will not affect the current IO device, unless it is
an internal IO device processing a QByteArray passed in the \e
constructor, in which case the internal IO device is destroyed.
*/
QDataStream::~QDataStream()
{
if ( owndev )
delete dev;
}
/*!
\fn QIODevice *QDataStream::device() const
Returns the IO device currently set.
\sa setDevice(), unsetDevice()
*/
/*!
void QDataStream::setDevice(QIODevice *d )
Sets the IO device to \a d.
\sa device(), unsetDevice()
*/
void QDataStream::setDevice(QIODevice *d )
{
if ( owndev ) {
delete dev;
owndev = FALSE;
}
dev = d;
}
/*!
Unsets the IO device. This is the same as calling setDevice( 0 ).
\sa device(), setDevice()
*/
void QDataStream::unsetDevice()
{
setDevice( 0 );
}
/*!
\fn bool QDataStream::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, i.e. if the current position of the IO device is
before the end position.
\sa QIODevice::atEnd()
*/
/*!\fn bool QDataStream::eof() const
\obsolete
Returns TRUE if the IO device has reached the end position (end of
stream or file) or if there is no IO device set.
Returns FALSE if the current position of the read/write head of the IO
device is somewhere before the end position.
\sa QIODevice::atEnd()
*/
/*!
\fn int QDataStream::byteOrder() const
Returns the current byte order setting -- either \c BigEndian or
\c LittleEndian.
\sa setByteOrder()
*/
/*!
Sets the serialization byte order to \a bo.
The \a bo parameter can be \c QDataStream::BigEndian or \c
QDataStream::LittleEndian.
The default setting is big endian. We recommend leaving this
setting unless you have special requirements.
\sa byteOrder()
*/
void QDataStream::setByteOrder( int bo )
{
byteorder = bo;
if ( systemBigEndian )
noswap = byteorder == BigEndian;
else
noswap = byteorder == LittleEndian;
}
/*!
\fn bool QDataStream::isPrintableData() const
Returns TRUE if the printable data flag has been set; otherwise
returns FALSE.
\sa setPrintableData()
*/
/*!
\fn void QDataStream::setPrintableData( bool enable )
If \a enable is TRUE, data will be output in a human readable
format. If \a enable is FALSE, data will be output in a binary
format.
If \a enable is TRUE, the write functions will generate output
that consists of printable characters (7 bit ASCII). This output
will typically be a lot larger than the default binary output, and
consequently slower to write.
We recommend only enabling printable data for debugging purposes.
*/
/*!
\fn int QDataStream::version() const
Returns the version number of the data serialization format. In Qt
3.1, this number is 5.
\sa setVersion()
*/
/*!
\fn void QDataStream::setVersion( int v )
Sets the version number of the data serialization format to \a v.
You don't need to set a version if you are using the current
version of Qt.
In order to accommodate new functionality, the datastream
serialization format of some Qt classes has changed in some
versions of Qt. If you want to read data that was created by an
earlier version of Qt, or write data that can be read by a program
that was compiled with an earlier version of Qt, use this function
to modify the serialization format of QDataStream.
\table
\header \i Qt Version \i QDataStream Version
\row \i Qt 3.1 \i11 5
\row \i Qt 3.0 \i11 4
\row \i Qt 2.1.x and Qt 2.2.x \i11 3
\row \i Qt 2.0.x \i11 2
\row \i Qt 1.x \i11 1
\endtable
\sa version()
*/
/*****************************************************************************
QDataStream read functions
*****************************************************************************/
static Q_INT32 read_int_ascii( QDataStream *s )
{
register int n = 0;
char buf[40];
for ( ;; ) {
buf[n] = s->device()->getch();
if ( buf[n] == '\n' || n > 38 ) // $-terminator
break;
n++;
}
buf[n] = '\0';
return atol( buf );
}
/*!
\overload QDataStream &QDataStream::operator>>( Q_UINT8 &i )
Reads an unsigned byte from the stream into \a i, and returns a
reference to the stream.
*/
/*!
Reads a signed byte from the stream into \a i, and returns a
reference to the stream.
*/
QDataStream &QDataStream::operator>>( Q_INT8 &i )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
i = (Q_INT8)dev->getch();
if ( i == '\\' ) { // read octal code
char buf[4];
dev->readBlock( buf, 3 );
i = (buf[2] & 0x07)+((buf[1] & 0x07) << 3)+((buf[0] & 0x07) << 6);
}
} else { // data or text
i = (Q_INT8)dev->getch();
}
return *this;
}
/*!
\overload QDataStream &QDataStream::operator>>( Q_UINT16 &i )
Reads an unsigned 16-bit integer from the stream into \a i, and
returns a reference to the stream.
*/
/*!
\overload
Reads a signed 16-bit integer from the stream into \a i, and
returns a reference to the stream.
*/
QDataStream &QDataStream::operator>>( Q_INT16 &i )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
i = (Q_INT16)read_int_ascii( this );
} else if ( noswap ) { // no conversion needed
dev->readBlock( (char *)&i, sizeof(Q_INT16) );
} else { // swap bytes
register uchar *p = (uchar *)(&i);
char b[2];
dev->readBlock( b, 2 );
*p++ = b[1];
*p = b[0];
}
return *this;
}
/*!
\overload QDataStream &QDataStream::operator>>( Q_UINT32 &i )
Reads an unsigned 32-bit integer from the stream into \a i, and
returns a reference to the stream.
*/
/*!
\overload
Reads a signed 32-bit integer from the stream into \a i, and
returns a reference to the stream.
*/
QDataStream &QDataStream::operator>>( Q_INT32 &i )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
i = read_int_ascii( this );
} else if ( noswap ) { // no conversion needed
dev->readBlock( (char *)&i, sizeof(Q_INT32) );
} else { // swap bytes
uchar *p = (uchar *)(&i);
char b[4];
dev->readBlock( b, 4 );
*p++ = b[3];
*p++ = b[2];
*p++ = b[1];
*p = b[0];
}
return *this;
}
/*!
\overload QDataStream &QDataStream::operator>>( Q_ULONG &i )
Reads an unsigned integer of the system's word length from the
stream, into \a i, and returns a reference to the stream.
*/
/*!
\overload
Reads a signed integer of the system's word length from the stream
into \a i, and returns a reference to the stream.
*/
QDataStream &QDataStream::operator>>( Q_LONG &i )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
i = read_int_ascii( this );
} else if ( noswap ) { // no conversion needed
dev->readBlock( (char *)&i, sizeof(Q_LONG) );
} else { // swap bytes
register uchar *p = (uchar *)(&i);
char b[sizeof(Q_LONG)];
dev->readBlock( b, sizeof(Q_LONG) );
for ( int j = sizeof(Q_LONG); j; )
*p++ = b[--j];
}
return *this;
}
static double read_double_ascii( QDataStream *s )
{
register int n = 0;
char buf[80];
for ( ;; ) {
buf[n] = s->device()->getch();
if ( buf[n] == '\n' || n > 78 ) // $-terminator
break;
n++;
}
buf[n] = '\0';
return atof( buf );
}
/*!
\overload
Reads a 32-bit floating point number from the stream into \a f,
using the standard IEEE754 format. Returns a reference to the
stream.
*/
QDataStream &QDataStream::operator>>( float &f )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
f = (float)read_double_ascii( this );
} else if ( noswap ) { // no conversion needed
dev->readBlock( (char *)&f, sizeof(float) );
} else { // swap bytes
uchar *p = (uchar *)(&f);
char b[4];
dev->readBlock( b, 4 );
*p++ = b[3];
*p++ = b[2];
*p++ = b[1];
*p = b[0];
}
return *this;
}
/*!
\overload
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;
+ 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++;
b[1] = *p++;
b[0] = *p;
dev->writeBlock( b, 4 );
}
return *this;
}
/*!
\overload QDataStream &QDataStream::operator<<( Q_ULONG i )
Writes an unsigned integer \a i, of the system's word length, to
the stream and returns a reference to the stream.
*/
/*!
\overload
Writes a signed integer \a i, of the system's word length, to the
stream and returns a reference to the stream.
*/
QDataStream &QDataStream::operator<<( Q_LONG i )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
char buf[20];
sprintf( buf, "%ld\n", i );
dev->writeBlock( buf, strlen(buf) );
} else if ( noswap ) { // no conversion needed
dev->writeBlock( (char *)&i, sizeof(Q_LONG) );
} else { // swap bytes
register uchar *p = (uchar *)(&i);
char b[sizeof(Q_LONG)];
for ( int j = sizeof(Q_LONG); j; )
b[--j] = *p++;
dev->writeBlock( b, sizeof(Q_LONG) );
}
return *this;
}
/*!
\overload QDataStream &QDataStream::operator<<( Q_UINT32 i )
Writes an unsigned integer, \a i, to the stream as a 32-bit
unsigned integer (Q_UINT32). Returns a reference to the stream.
*/
/*!
\overload
Writes a 32-bit floating point number, \a f, to the stream using
the standard IEEE754 format. Returns a reference to the stream.
*/
QDataStream &QDataStream::operator<<( float f )
{
CHECK_STREAM_PRECOND
if ( printable ) { // printable data
char buf[32];
sprintf( buf, "%g\n", (double)f );
dev->writeBlock( buf, strlen(buf) );
} else {
float g = f; // fixes float-on-stack problem
if ( noswap ) { // no conversion needed
dev->writeBlock( (char *)&g, sizeof(float) );
} else { // swap bytes
register uchar *p = (uchar *)(&g);
char b[4];
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
+ 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,2490 +1,2536 @@
/****************************************************************************
** $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() );
#endif
} else if ( f == "yy" ) {
buf = QString::number( dd->year() ).right( 2 );
} else if ( f == "yyyy" ) {
buf = QString::number( dd->year() );
}
}
return buf;
}
// Parses the format string and uses getFmtString to get the values for the tokens. Ret
static QString fmtDateTime( const QString& f, const QTime* dt = 0, const QDate* dd = 0 )
{
if ( f.isEmpty() ) {
return QString::null;
}
bool ap = ( f.contains( "AP" ) || f.contains( "ap" ) );
QString buf;
QString frm;
QChar status = '0';
for ( int i = 0; i < (int)f.length(); ++i ) {
if ( f[ i ] == status ) {
if ( ( ap ) && ( ( f[ i ] == 'P' ) || ( f[ i ] == 'p' ) ) )
status = '0';
frm += f[ i ];
} else {
buf += getFmtString( frm, dt, dd, ap );
frm = QString::null;
if ( ( f[ i ] == 'h' ) || ( f[ i ] == 'm' ) || ( f[ i ] == 's' ) || ( f[ i ] == 'z' ) ) {
status = f[ i ];
frm += f[ i ];
} else if ( ( f[ i ] == 'd' ) || ( f[ i ] == 'M' ) || ( f[ i ] == 'y' ) ) {
status = f[ i ];
frm += f[ i ];
} else if ( ( ap ) && ( f[ i ] == 'A' ) ) {
status = 'P';
frm += f[ i ];
} else if( ( ap ) && ( f[ i ] == 'a' ) ) {
status = 'p';
frm += f[ i ];
} else {
buf += f[ i ];
status = '0';
}
}
}
buf += getFmtString( frm, dt, dd, ap );
return buf;
}
#endif // QT_NO_DATESTRING
/*****************************************************************************
QDate member functions
*****************************************************************************/
/*!
\class QDate qdatetime.h
\reentrant
\brief The QDate class provides date functions.
\ingroup time
\mainclass
A QDate object contains a calendar date, i.e. year, month, and day
numbers, in the modern Western (Gregorian) calendar. It can read
the current date from the system clock. It provides functions for
comparing dates and for manipulating dates, e.g. by adding a
number of days or months or years.
A QDate object is typically created either by giving the year,
month and day numbers explicitly, or by using the static function
currentDate(), which creates a QDate object containing the system
clock's date. An explicit date can also be set using setYMD(). The
fromString() function returns a QDate given a string and a date
format which is used to interpret the date within the string.
The year(), month(), and day() functions provide access to the
year, month, and day numbers. Also, dayOfWeek() and dayOfYear()
functions are provided. The same information is provided in
textual format by the toString(), shortDayName(), longDayName(),
shortMonthName() and longMonthName() functions.
QDate provides a full set of operators to compare two QDate
objects where smaller means earlier and larger means later.
You can increment (or decrement) a date by a given number of days
using addDays(). Similarly you can use addMonths() and addYears().
The daysTo() function returns the number of days between two
dates.
The daysInMonth() and daysInYear() functions return how many days
there are in this date's month and year, respectively. The
leapYear() function indicates whether this date is in a leap year.
Note that QDate should not be used for date calculations for dates
prior to the introduction of the Gregorian calendar. This calendar
was adopted by England from the 14<sup><small>th</small></sup>
September 1752 (hence this is the earliest valid QDate), and
subsequently by most other Western countries, until 1923.
The end of time is reached around the year 8000, by which time we
expect Qt to be obsolete.
\sa QTime QDateTime QDateEdit QDateTimeEdit
*/
/*!
\enum Qt::DateFormat
\value TextDate (default) Qt format
\value ISODate ISO 8601 extended format (YYYY-MM-DD, or with time,
YYYY-MM-DDTHH:MM:SS)
\value LocalDate locale dependent format
*/
/*!
\enum Qt::TimeSpec
\value LocalTime Locale dependent time (Timezones and Daylight Savings Time)
\value UTC Coordinated Universal Time, replaces Greenwich Time
*/
/*!
\fn QDate::QDate()
Constructs a null date. Null dates are invalid.
\sa isNull(), isValid()
*/
/*!
Constructs a date with year \a y, month \a m and day \a d.
\a y must be in the range 1752..8000, \a m must be in the range
1..12, and \a d must be in the range 1..31.
\warning If \a y is in the range 0..99, it is interpreted as
1900..1999.
\sa isValid()
*/
QDate::QDate( int y, int m, int d )
{
jd = 0;
setYMD( y, m, d );
}
/*!
\fn bool QDate::isNull() const
Returns TRUE if the date is null; otherwise returns FALSE. A null
date is invalid.
\sa isValid()
*/
/*!
Returns TRUE if this date is valid; otherwise returns FALSE.
\sa isNull()
*/
bool QDate::isValid() const
{
return jd >= FIRST_DAY;
}
/*!
Returns the year (1752..8000) of this date.
\sa month(), day()
*/
int QDate::year() const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
return y;
}
/*!
Returns the month (January=1..December=12) of this date.
\sa year(), day()
*/
int QDate::month() const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
return m;
}
/*!
Returns the day of the month (1..31) of this date.
\sa year(), month(), dayOfWeek()
*/
int QDate::day() const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
return d;
}
/*!
Returns the weekday (Monday=1..Sunday=7) for this date.
\sa day(), dayOfYear()
*/
int QDate::dayOfWeek() const
{
return ( jd % 7 ) + 1;
}
/*!
Returns the day of the year (1..365) for this date.
\sa day(), dayOfWeek()
*/
int QDate::dayOfYear() const
{
return jd - gregorianToJulian(year(), 1, 1) + 1;
}
/*!
Returns the number of days in the month (28..31) for this date.
\sa day(), daysInYear()
*/
int QDate::daysInMonth() const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
if ( m == 2 && leapYear(y) )
return 29;
else
return monthDays[m];
}
/*!
Returns the number of days in the year (365 or 366) for this date.
\sa day(), daysInMonth()
*/
int QDate::daysInYear() const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
return leapYear( y ) ? 366 : 365;
}
/*!
Returns the week number (1 to 53), and stores the year in \a
*yearNumber unless \a yearNumber is null (the default).
Returns 0 if the date is invalid.
In accordance with ISO 8601, weeks start on Monday and the first
Thursday of a year is always in week 1 of that year. Most years
have 52 weeks, but some have 53.
\a *yearNumber is not always the same as year(). For example, 1
January 2000 has week number 52 in the year 1999, and 31 December
2002 has week number 1 in the year 2003.
\sa isValid()
*/
int QDate::weekNumber( int *yearNumber ) const
{
if ( !isValid() )
return 0;
int dow = dayOfWeek();
int doy = dayOfYear();
int currYear = year();
int jan1WeekDay = QDate( currYear, 1, 1 ).dayOfWeek();
int yearNum;
int weekNum;
if ( doy <= (8 - jan1WeekDay) && jan1WeekDay > 4 ) {
yearNum = currYear - 1;
weekNum = 52;
if ( jan1WeekDay == 5 ||
(jan1WeekDay == 6 && QDate::leapYear(yearNum)) )
weekNum++;
} else {
int totalDays = 365;
if ( QDate::leapYear(currYear) )
totalDays++;
if ( (totalDays - doy < 4 - dow)
|| (jan1WeekDay == 7 && totalDays - doy < 3) ) {
yearNum = currYear + 1;
weekNum = 1;
} else {
int j = doy + ( 7 - dow ) + ( jan1WeekDay - 1 );
yearNum = currYear;
weekNum = j / 7;
if ( jan1WeekDay > 4 )
weekNum--;
}
}
if ( yearNumber )
*yearNumber = yearNum;
return weekNum;
}
/*!
\fn QString QDate::monthName( int month )
\obsolete
Use shortMonthName() instead.
*/
#ifndef QT_NO_TEXTDATE
/*!
Returns the name of the \a month.
1 = "Jan", 2 = "Feb", ... 12 = "Dec"
The month names will be localized according to the system's locale
settings.
\sa toString(), longMonthName(), shortDayName(), longDayName()
*/
QString QDate::shortMonthName( int month )
{
#if defined(QT_CHECK_RANGE)
if ( month < 1 || month > 12 ) {
qWarning( "QDate::shortMonthName: Parameter out ouf range." );
month = 1;
}
#endif
#ifndef Q_WS_WIN
char buffer[255];
tm tt;
memset( &tt, 0, sizeof( tm ) );
tt.tm_mon = month - 1;
if ( strftime( buffer, sizeof( buffer ), "%b", &tt ) )
return QString::fromLocal8Bit( buffer );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wYear = 2000;
st.wMonth = month;
st.wDay = 1;
const wchar_t mmm_t[] = L"MMM"; // workaround for Borland
QT_WA( {
TCHAR buf[255];
if ( GetDateFormat( LOCALE_USER_DEFAULT, 0, &st, mmm_t, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetDateFormatA( LOCALE_USER_DEFAULT, 0, &st, "MMM", (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} );
#endif
return QString::null;
}
/*!
Returns the long name of the \a month.
1 = "January", 2 = "February", ... 12 = "December"
The month names will be localized according to the system's locale
settings.
\sa toString(), shortMonthName(), shortDayName(), longDayName()
*/
QString QDate::longMonthName( int month )
{
#if defined(QT_CHECK_RANGE)
if ( month < 1 || month > 12 ) {
qWarning( "QDate::longMonthName: Parameter out ouf range." );
month = 1;
}
#endif
#ifndef Q_WS_WIN
char buffer[255];
tm tt;
memset( &tt, 0, sizeof( tm ) );
tt.tm_mon = month - 1;
if ( strftime( buffer, sizeof( buffer ), "%B", &tt ) )
return QString::fromLocal8Bit( buffer );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wYear = 2000;
st.wMonth = month;
st.wDay = 1 ;
const wchar_t mmmm_t[] = L"MMMM"; // workaround for Borland
QT_WA( {
TCHAR buf[255];
if ( GetDateFormat( LOCALE_USER_DEFAULT, 0, &st, mmmm_t, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetDateFormatA( LOCALE_USER_DEFAULT, 0, &st, "MMMM", (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} )
#endif
return QString::null;
}
/*!
\fn QString QDate::dayName( int weekday )
\obsolete
Use shortDayName() instead.
*/
/*!
Returns the name of the \a weekday.
1 = "Mon", 2 = "Tue", ... 7 = "Sun"
The day names will be localized according to the system's locale
settings.
\sa toString(), shortMonthName(), longMonthName(), longDayName()
*/
QString QDate::shortDayName( int weekday )
{
#if defined(QT_CHECK_RANGE)
if ( weekday < 1 || weekday > 7 ) {
qWarning( "QDate::shortDayName: Parameter out of range." );
weekday = 1;
}
#endif
#ifndef Q_WS_WIN
char buffer[255];
tm tt;
memset( &tt, 0, sizeof( tm ) );
tt.tm_wday = ( weekday == 7 ) ? 0 : weekday;
if ( strftime( buffer, sizeof( buffer ), "%a", &tt ) )
return QString::fromLocal8Bit( buffer );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wYear = 2001;
st.wMonth = 10;
st.wDayOfWeek = ( weekday == 7 ) ? 0 : weekday;
st.wDay = 21 + st.wDayOfWeek;
const wchar_t ddd_t[] = L"ddd"; // workaround for Borland
QT_WA( {
TCHAR buf[255];
if ( GetDateFormat( LOCALE_USER_DEFAULT, 0, &st, ddd_t, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetDateFormatA( LOCALE_USER_DEFAULT, 0, &st, "ddd", (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} );
#endif
return QString::null;
}
/*!
Returns the long name of the \a weekday.
1 = "Monday", 2 = "Tuesday", ... 7 = "Sunday"
The day names will be localized according to the system's locale
settings.
\sa toString(), shortDayName(), shortMonthName(), longMonthName()
*/
QString QDate::longDayName( int weekday )
{
#if defined(QT_CHECK_RANGE)
if ( weekday < 1 || weekday > 7 ) {
qWarning( "QDate::longDayName: Parameter out of range." );
weekday = 1;
}
#endif
#ifndef Q_WS_WIN
char buffer[255];
tm tt;
memset( &tt, 0, sizeof( tm ) );
tt.tm_wday = ( weekday == 7 ) ? 0 : weekday;
if ( strftime( buffer, sizeof( buffer ), "%A", &tt ) )
return QString::fromLocal8Bit( buffer );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wYear = 2001;
st.wMonth = 10;
st.wDayOfWeek = ( weekday == 7 ) ? 0 : weekday;
st.wDay = 21 + st.wDayOfWeek;
const wchar_t dddd_t[] = L"dddd"; // workaround for Borland
QT_WA( {
TCHAR buf[255];
if ( GetDateFormat( LOCALE_USER_DEFAULT, 0, &st, dddd_t, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetDateFormatA( LOCALE_USER_DEFAULT, 0, &st, "dddd", (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} );
#endif
return QString::null;
}
#endif //QT_NO_TEXTDATE
#ifndef QT_NO_DATESTRING
#if !defined(QT_NO_SPRINTF)
/*!
\overload
Returns the date as a string. The \a f parameter determines the
format of the string.
If \a f is \c Qt::TextDate, the string format is "Sat May 20 1995"
(using the shortDayName() and shortMonthName() functions to
generate the string, so the day and month names are locale
specific).
If \a f is \c Qt::ISODate, the string format corresponds to the
ISO 8601 specification for representations of dates, which is
YYYY-MM-DD where YYYY is the year, MM is the month of the year
(between 01 and 12), and DD is the day of the month between 01 and
31.
If \a f is \c Qt::LocalDate, the string format depends on the
locale settings of the system.
\sa shortDayName(), shortMonthName()
*/
QString QDate::toString( Qt::DateFormat f ) const
{
int y, m, d;
julianToGregorian( jd, y, m, d );
switch ( f ) {
case Qt::LocalDate:
{
#ifndef Q_WS_WIN
tm tt;
memset( &tt, 0, sizeof( tm ) );
char buf[255];
tt.tm_mday = day();
tt.tm_mon = month() - 1;
tt.tm_year = year() - 1900;
static const char * avoidEgcsWarning = "%x";
if ( strftime( buf, sizeof(buf), avoidEgcsWarning, &tt ) )
return QString::fromLocal8Bit( buf );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wYear = year();
st.wMonth = month();
st.wDay = day();
QT_WA( {
TCHAR buf[255];
if ( GetDateFormat( LOCALE_USER_DEFAULT, 0, &st, 0, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetDateFormatA( LOCALE_USER_DEFAULT, 0, &st, 0, (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} );
#endif
return QString::null;
}
default:
#ifndef QT_NO_TEXTDATE
case Qt::TextDate:
{
QString buf = shortDayName( dayOfWeek() );
buf += ' ';
buf += shortMonthName( m );
QString t;
t.sprintf( " %d %d", d, y );
buf += t;
return buf;
}
#endif
case Qt::ISODate:
{
QString month( QString::number( m ).rightJustify( 2, '0' ) );
QString day( QString::number( d ).rightJustify( 2, '0' ) );
return QString::number( y ) + "-" + month + "-" + day;
}
}
}
#endif //QT_NO_SPRINTF
/*!
Returns the date as a string. The \a format parameter determines
the format of the result string.
These expressions may be used:
\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().
\row \i M \i the month as number without a leading zero (1-12)
\row \i MM \i the month as number with a leading zero (01-12)
\row \i MMM
\i the abbreviated localized month name (e.g. 'Jan'..'Dec').
Uses QDate::shortMonthName().
\row \i MMMM
\i the long localized month name (e.g. 'January'..'December').
Uses QDate::longMonthName().
\row \i yy \i the year as two digit number (00-99)
\row \i yyyy \i the year as four digit number (1752-8000)
\endtable
All other input characters will be ignored.
Example format strings (assuming that the QDate is the
20<sup><small>th</small></sup> July 1969):
\table
\header \i Format \i Result
\row \i dd.MM.yyyy \i11 20.07.1969
\row \i ddd MMMM d yy \i11 Sun July 20 69
\endtable
\sa QDate::toString() QTime::toString()
*/
QString QDate::toString( const QString& format ) const
{
return fmtDateTime( format, 0, this );
}
#endif //QT_NO_DATESTRING
/*!
Sets the date's year \a y, month \a m and day \a d.
\a y must be in the range 1752..8000, \a m must be in the range
1..12, and \a d must be in the range 1..31.
\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( &ltime );
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( &ltime, &res );
+ else
+ t = gmtime_r( &ltime, &res );
+# else
if ( ts == Qt::LocalTime )
t = localtime( &ltime );
else
t = gmtime( &ltime );
+# 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
\warning A \a y value in the range 00..99 is interpreted as
1900..1999.
\sa isNull(), setYMD()
*/
bool QDate::isValid( int y, int m, int d )
{
if ( y >= 0 && y <= 99 )
y += 1900;
else if ( y < FIRST_YEAR || (y == FIRST_YEAR && (m < 9 ||
(m == 9 && d < 14))) )
return FALSE;
return (d > 0 && m > 0 && m <= 12) &&
(d <= monthDays[m] || (d == 29 && m == 2 && leapYear(y)));
}
/*!
Returns TRUE if the specified year \a y is a leap year; otherwise
returns FALSE.
*/
bool QDate::leapYear( int y )
{
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
/*!
\internal
Converts a Gregorian date to a Julian day.
This algorithm is taken from Communications of the ACM, Vol 6, No 8.
\sa julianToGregorian()
*/
uint QDate::gregorianToJulian( int y, int m, int d )
{
uint c, ya;
if ( y <= 99 )
y += 1900;
if ( m > 2 ) {
m -= 3;
} else {
m += 9;
y--;
}
c = y; // NOTE: Sym C++ 6.0 bug
c /= 100;
ya = y - 100*c;
return 1721119 + d + (146097*c)/4 + (1461*ya)/4 + (153*m+2)/5;
}
/*!
\internal
Converts a Julian day to a Gregorian date.
This algorithm is taken from Communications of the ACM, Vol 6, No 8.
\sa gregorianToJulian()
*/
void QDate::julianToGregorian( uint jd, int &y, int &m, int &d )
{
uint x;
uint j = jd - 1721119;
y = (j*4 - 1)/146097;
j = j*4 - 146097*y - 1;
x = j/4;
j = (x*4 + 3) / 1461;
y = 100*y + j;
x = (x*4) + 3 - 1461*j;
x = (x + 4)/4;
m = (5*x - 3)/153;
x = 5*x - 3 - 153*m;
d = (x + 5)/5;
if ( m < 10 ) {
m += 3;
} else {
m -= 9;
y++;
}
}
/*****************************************************************************
QTime member functions
*****************************************************************************/
/*!
\class QTime qdatetime.h
\reentrant
\brief The QTime class provides clock time functions.
\ingroup time
\mainclass
A QTime object contains a clock time, i.e. the number of hours,
minutes, seconds, and milliseconds since midnight. It can read the
current time from the system clock and measure a span of elapsed
time. It provides functions for comparing times and for
manipulating a time by adding a number of (milli)seconds.
QTime uses the 24-hour clock format; it has no concept of AM/PM.
It operates in local time; it knows nothing about time zones or
daylight savings time.
A QTime object is typically created either by giving the number of
hours, minutes, seconds, and milliseconds explicitly, or by using
the static function currentTime(), which creates a QTime object
that contains the system's clock time. Note that the accuracy
depends on the accuracy of the underlying operating system; not
all systems provide 1-millisecond accuracy.
The hour(), minute(), second(), and msec() functions provide
access to the number of hours, minutes, seconds, and milliseconds
of the time. The same information is provided in textual format by
the toString() function.
QTime provides a full set of operators to compare two QTime
objects. One time is considered smaller than another if it is
earlier than the other.
The time a given number of seconds or milliseconds later than a
given time can be found using the addSecs() or addMSecs()
functions. Correspondingly, the number of (milli)seconds between
two times can be found using the secsTo() or msecsTo() functions.
QTime can be used to measure a span of elapsed time using the
start(), restart(), and elapsed() functions.
\sa QDate, QDateTime
*/
/*!
\fn QTime::QTime()
Constructs the time 0 hours, minutes, seconds and milliseconds,
i.e. 00:00:00.000 (midnight). This is a valid time.
\sa isValid()
*/
/*!
Constructs a time with hour \a h, minute \a m, seconds \a s and
milliseconds \a ms.
\a h must be in the range 0..23, \a m and \a s must be in the
range 0..59, and \a ms must be in the range 0..999.
\sa isValid()
*/
QTime::QTime( int h, int m, int s, int ms )
{
setHMS( h, m, s, ms );
}
/*!
\fn bool QTime::isNull() const
Returns TRUE if the time is equal to 00:00:00.000; otherwise
returns FALSE. A null time is valid.
\sa isValid()
*/
/*!
Returns TRUE if the time is valid; otherwise returns FALSE. The
time 23:30:55.746 is valid, whereas 24:12:30 is invalid.
\sa isNull()
*/
bool QTime::isValid() const
{
return ds < MSECS_PER_DAY;
}
/*!
Returns the hour part (0..23) of the time.
*/
int QTime::hour() const
{
return ds / MSECS_PER_HOUR;
}
/*!
Returns the minute part (0..59) of the time.
*/
int QTime::minute() const
{
return (ds % MSECS_PER_HOUR)/MSECS_PER_MIN;
}
/*!
Returns the second part (0..59) of the time.
*/
int QTime::second() const
{
return (ds / 1000)%SECS_PER_MIN;
}
/*!
Returns the millisecond part (0..999) of the time.
*/
int QTime::msec() const
{
return ds % 1000;
}
#ifndef QT_NO_DATESTRING
#ifndef QT_NO_SPRINTF
/*!
\overload
Returns the time as a string. Milliseconds are not included. The
\a f parameter determines the format of the string.
If \a f is \c Qt::TextDate, the string format is HH:MM:SS; e.g. 1
second before midnight would be "23:59:59".
If \a f is \c Qt::ISODate, the string format corresponds to the
ISO 8601 extended specification for representations of dates,
which is also HH:MM:SS.
If \a f is Qt::LocalDate, the string format depends on the locale
settings of the system.
*/
QString QTime::toString( Qt::DateFormat f ) const
{
switch ( f ) {
case Qt::LocalDate:
{
#ifndef Q_WS_WIN
tm tt;
memset( &tt, 0, sizeof( tm ) );
char buf[255];
tt.tm_sec = second();
tt.tm_min = minute();
tt.tm_hour = hour();
if ( strftime( buf, sizeof(buf), "%X", &tt ) )
return QString::fromLocal8Bit( buf );
#else
SYSTEMTIME st;
memset( &st, 0, sizeof(SYSTEMTIME) );
st.wHour = hour();
st.wMinute = minute();
st.wSecond = second();
st.wMilliseconds = 0;
QT_WA( {
TCHAR buf[255];
if ( GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, 0, buf, 255 ) )
return QString::fromUcs2( (ushort*)buf );
} , {
char buf[255];
if ( GetTimeFormatA( LOCALE_USER_DEFAULT, 0, &st, 0, (char*)&buf, 255 ) )
return QString::fromLocal8Bit( buf );
} );
#endif
return QString::null;
}
default:
case Qt::ISODate:
case Qt::TextDate:
QString buf;
buf.sprintf( "%.2d:%.2d:%.2d", hour(), minute(), second() );
return buf;
}
}
#endif
/*!
Returns the time as a string. The \a format parameter determines
the format of the result string.
These expressions may be used:
\table
\header \i Expression \i Output
\row \i h
\i the hour without a leading zero (0..23 or 1..12 if AM/PM display)
\row \i hh
\i the hour with a leading zero (00..23 or 01..12 if AM/PM display)
\row \i m \i the minute without a leading zero (0..59)
\row \i mm \i the minute with a leading zero (00..59)
\row \i s \i the second whithout a leading zero (0..59)
\row \i ss \i the second whith a leading zero (00..59)
\row \i z \i the milliseconds without leading zeroes (0..999)
\row \i zzz \i the milliseconds with leading zeroes (000..999)
\row \i AP
\i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
\row \i ap
\i use am/pm display. \e ap will be replaced by either "am" or "pm".
\endtable
All other input characters will be ignored.
Example format strings (assuming that the QTime is 14:13:09.042)
\table
\header \i Format \i Result
\row \i hh:mm:ss.zzz \i11 14:13:09.042
\row \i h:m:s ap \i11 2:13:9 pm
\endtable
\sa QDate::toString() QTime::toString()
*/
QString QTime::toString( const QString& format ) const
{
return fmtDateTime( format, this, 0 );
}
#endif //QT_NO_DATESTRING
/*!
Sets the time to hour \a h, minute \a m, seconds \a s and
milliseconds \a ms.
\a h must be in the range 0..23, \a m and \a s must be in the
range 0..59, and \a ms must be in the range 0..999. Returns TRUE
if the set time is valid; otherwise returns FALSE.
\sa isValid()
*/
bool QTime::setHMS( int h, int m, int s, int ms )
{
if ( !isValid(h,m,s,ms) ) {
#if defined(QT_CHECK_RANGE)
qWarning( "QTime::setHMS Invalid time %02d:%02d:%02d.%03d", h, m, s,
ms );
#endif
ds = MSECS_PER_DAY; // make this invalid
return FALSE;
}
ds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
return TRUE;
}
/*!
Returns a QTime object containing a time \a nsecs seconds later
than the time of this object (or earlier if \a nsecs is negative).
Note that the time will wrap if it passes midnight.
Example:
\code
QTime n( 14, 0, 0 ); // n == 14:00:00
QTime t;
t = n.addSecs( 70 ); // t == 14:01:10
t = n.addSecs( -70 ); // t == 13:58:50
t = n.addSecs( 10*60*60 + 5 ); // t == 00:00:05
t = n.addSecs( -15*60*60 ); // t == 23:00:00
\endcode
\sa addMSecs(), secsTo(), QDateTime::addSecs()
*/
QTime QTime::addSecs( int nsecs ) const
{
return addMSecs( nsecs * 1000 );
}
/*!
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( &ltime, &res );
+ else
+ t = gmtime_r( &ltime, &res );
+# else
+ if ( ts == Qt::LocalTime )
t = localtime( &ltime );
- } else {
+ else
t = gmtime( &ltime );
- }
+# 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( &ltime );
tm *t;
if ( ts == Qt::LocalTime )
localtime( &ltime );
else
gmtime( &ltime );
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
time parts of the datetime. The same information is provided in
textual format by the toString() function.
QDateTime provides a full set of operators to compare two
QDateTime objects where smaller means earlier and larger means
later.
You can increment (or decrement) a datetime by a given number of
seconds using addSecs() or days using addDays(). Similarly you can
use addMonths() and addYears(). The daysTo() function returns the
number of days between two datetimes, and secsTo() returns the
number of seconds between two datetimes.
The range of a datetime object is constrained to the ranges of the
QDate and QTime objects which it embodies.
\sa QDate QTime QDateTimeEdit
*/
/*!
\fn QDateTime::QDateTime()
Constructs a null datetime (i.e. null date and null time). A null
datetime is invalid, since the date is invalid.
\sa isValid()
*/
/*!
Constructs a datetime with date \a date and null (but valid) time
(00:00:00.000).
*/
QDateTime::QDateTime( const QDate &date )
: d(date)
{
}
/*!
Constructs a datetime with date \a date and time \a time.
*/
QDateTime::QDateTime( const QDate &date, const QTime &time )
: d(date), t(time)
{
}
/*!
\fn bool QDateTime::isNull() const
Returns TRUE if both the date and the time are null; otherwise
returns FALSE. A null datetime is invalid.
\sa QDate::isNull(), QTime::isNull()
*/
/*!
\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().
\row \i M \i the month as number without a leading zero (1-12)
\row \i MM \i the month as number with a leading zero (01-12)
\row \i MMM
\i the abbreviated localized month name (e.g. 'Jan'..'Dec').
Uses QDate::shortMonthName().
\row \i MMMM
\i the long localized month name (e.g. 'January'..'December').
Uses QDate::longMonthName().
\row \i yy \i the year as two digit number (00-99)
\row \i yyyy \i the year as four digit number (1752-8000)
\endtable
These expressions may be used for the time:
\table
\header \i Expression \i Output
\row \i h
\i the hour without a leading zero (0..23 or 1..12 if AM/PM display)
\row \i hh
\i the hour with a leading zero (00..23 or 01..12 if AM/PM display)
\row \i m \i the minute without a leading zero (0..59)
\row \i mm \i the minute with a leading zero (00..59)
\row \i s \i the second whithout a leading zero (0..59)
\row \i ss \i the second whith a leading zero (00..59)
\row \i z \i the milliseconds without leading zeroes (0..999)
\row \i zzz \i the milliseconds with leading zeroes (000..999)
\row \i AP
\i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
\row \i ap
\i use am/pm display. \e ap will be replaced by either "am" or "pm".
\endtable
All other input characters will be ignored.
Example format strings (assumed that the QDateTime is
21<small><sup>st</sup></small> May 2001 14:13:09)
\table
\header \i Format \i Result
\row \i dd.MM.yyyy \i11 21.05.2001
\row \i ddd MMMM d yy \i11 Tue May 21 01
\row \i hh:mm:ss.zzz \i11 14:13:09.042
\row \i h:m:s ap \i11 2:13:9 pm
\endtable
\sa QDate::toString() QTime::toString()
*/
QString QDateTime::toString( const QString& format ) const
{
return fmtDateTime( format, &t, &d );
}
#endif //QT_NO_DATESTRING
/*!
Returns a QDateTime object containing a datetime \a ndays days
later than the datetime of this object (or earlier if \a ndays is
negative).
\sa daysTo(), addMonths(), addYears(), addSecs()
*/
QDateTime QDateTime::addDays( int ndays ) const
{
return QDateTime( d.addDays(ndays), t );
}
/*!
Returns a QDateTime object containing a datetime \a nmonths months
later than the datetime of this object (or earlier if \a nmonths
is negative).
\sa daysTo(), addDays(), addYears(), addSecs()
*/
QDateTime QDateTime::addMonths( int nmonths ) const
{
return QDateTime( d.addMonths(nmonths), t );
}
/*!
Returns a QDateTime object containing a datetime \a nyears years
later than the datetime of this object (or earlier if \a nyears is
negative).
\sa daysTo(), addDays(), addMonths(), addSecs()
*/
QDateTime QDateTime::addYears( int nyears ) const
{
return QDateTime( d.addYears(nyears), t );
}
/*!
Returns a QDateTime object containing a datetime \a nsecs seconds
later than the datetime of this object (or earlier if \a nsecs is
negative).
\sa secsTo(), addDays(), addMonths(), addYears()
*/
QDateTime QDateTime::addSecs( int nsecs ) const
{
uint dd = d.jd;
int tt = t.ds;
int sign = 1;
if ( nsecs < 0 ) {
nsecs = -nsecs;
sign = -1;
}
if ( nsecs >= (int)SECS_PER_DAY ) {
dd += sign*(nsecs/SECS_PER_DAY);
nsecs %= SECS_PER_DAY;
}
tt += sign*nsecs*1000;
if ( tt < 0 ) {
tt = MSECS_PER_DAY - tt - 1;
dd -= tt / MSECS_PER_DAY;
tt = tt % MSECS_PER_DAY;
tt = MSECS_PER_DAY - tt - 1;
} else if ( tt >= (int)MSECS_PER_DAY ) {
dd += ( tt / MSECS_PER_DAY );
tt = tt % MSECS_PER_DAY;
}
QDateTime ret;
ret.t.ds = tt;
ret.d.jd = dd;
return ret;
}
/*!
Returns the number of days from this datetime to \a dt (which is
negative if \a dt is earlier than this datetime).
\sa addDays(), secsTo()
*/
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
/*****************************************************************************
Date/time stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
/*!
\relates QDate
Writes the date, \a d, to the data stream, \a s.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator<<( QDataStream &s, const QDate &d )
{
return s << (Q_UINT32)(d.jd);
}
/*!
\relates QDate
Reads a date from the stream \a s into \a d.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QDate &d )
{
Q_UINT32 jd;
s >> jd;
d.jd = jd;
return s;
}
/*!
\relates QTime
Writes time \a t to the stream \a s.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator<<( QDataStream &s, const QTime &t )
{
return s << (Q_UINT32)(t.ds);
}
/*!
\relates QTime
Reads a time from the stream \a s into \a t.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QTime &t )
{
Q_UINT32 ds;
s >> ds;
t.ds = ds;
return s;
}
/*!
\relates QDateTime
Writes the datetime \a dt to the stream \a s.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator<<( QDataStream &s, const QDateTime &dt )
{
return s << dt.d << dt.t;
}
/*!
\relates QDateTime
Reads a datetime from the stream \a s into \a dt.
\sa \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QDateTime &dt )
{
s >> dt.d >> dt.t;
return s;
}
#endif //QT_NO_DATASTREAM
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,1294 +1,1342 @@
/****************************************************************************
** $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();
+#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()
{
return cd( QString::fromLatin1("..") );
}
/*!
\fn QString QDir::nameFilter() const
Returns the string set by setNameFilter()
*/
/*!
Sets the name filter used by entryList() and entryInfoList() to \a
nameFilter.
The \a nameFilter is a wildcard (globbing) filter that understands
"*" and "?" wildcards. (See \link qregexp.html#wildcard-matching
QRegExp wildcard matching\endlink.) You may specify several filter
entries all separated by a single space " " or by a semi-colon
";".
For example, if you want entryList() and entryInfoList() to list
all files ending with either ".cpp" or ".h", you would use either
dir.setNameFilter("*.cpp *.h") or dir.setNameFilter("*.cpp;*.h").
\sa nameFilter(), setFilter()
*/
void QDir::setNameFilter( const QString &nameFilter )
{
nameFilt = nameFilter;
if ( nameFilt.isEmpty() )
nameFilt = QString::fromLatin1("*");
dirty = TRUE;
}
/*!
\fn QDir::FilterSpec QDir::filter() const
Returns the value set by setFilter()
*/
/*!
\enum QDir::FilterSpec
This enum describes the filtering options available to QDir, e.g.
for entryList() and entryInfoList(). The filter value is specified
by OR-ing together values from the following list:
\value Dirs List directories only.
\value Files List files only.
\value Drives List disk drives (ignored under Unix).
\value NoSymLinks Do not list symbolic links (ignored by operating
systems that don't support symbolic links).
\value All List directories, files, drives and symlinks (this does not list
broken symlinks unless you specify System).
\value TypeMask A mask for the the Dirs, Files, Drives and
NoSymLinks flags.
\value Readable List files for which the application has read access.
\value Writable List files for which the application has write access.
\value Executable List files for which the application has execute
access. Executables needs to be combined with Dirs or Files.
\value RWEMask A mask for the Readable, Writable and Executable flags.
\value Modified Only list files that have been modified (ignored
under Unix).
\value Hidden List hidden files (on Unix, files starting with a .).
\value System List system files (on Unix, FIFOs, sockets and
device files)
\value AccessMask A mask for the Readable, Writable, Executable
Modified, Hidden and System flags
\value DefaultFilter Internal flag.
If you do not set any of \c Readable, \c Writable or \c
Executable, QDir will set all three of them. This makes the
default easy to write and at the same time useful.
Examples: \c Readable|Writable means list all files for which the
application has read access, write access or both. \c Dirs|Drives
means list drives, directories, all files that the application can
read, write or execute, and also symlinks to such
files/directories.
*/
/*!
Sets the filter used by entryList() and entryInfoList() to \a
filterSpec. The filter is used to specify the kind of files that
should be returned by entryList() and entryInfoList(). See
\l{QDir::FilterSpec}.
\sa filter(), setNameFilter()
*/
void QDir::setFilter( int filterSpec )
{
if ( filtS == (FilterSpec) filterSpec )
return;
filtS = (FilterSpec) filterSpec;
dirty = TRUE;
}
/*!
\fn QDir::SortSpec QDir::sorting() const
Returns the value set by setSorting()
\sa setSorting() SortSpec
*/
/*!
\enum QDir::SortSpec
This enum describes the sort options available to QDir, e.g. for
entryList() and entryInfoList(). The sort value is specified by
OR-ing together values from the following list:
\value Name Sort by name.
\value Time Sort by time (modification time).
\value Size Sort by file size.
\value Unsorted Do not sort.
\value SortByMask A mask for Name, Time and Size.
\value DirsFirst Put the directories first, then the files.
\value Reversed Reverse the sort order.
\value IgnoreCase Sort case-insensitively.
\value DefaultSort Internal flag.
You can only specify one of the first four.
If you specify both \c DirsFirst and \c Reversed, directories are
still put first, but in reverse order; the files will be listed
after the directories, again in reverse order.
*/
// ### Unsorted+DirsFirst ? Unsorted+Reversed?
/*!
Sets the sort order used by entryList() and entryInfoList().
The \a sortSpec is specified by OR-ing values from the enum
\l{QDir::SortSpec}.
\sa sorting() SortSpec
*/
void QDir::setSorting( int sortSpec )
{
if ( sortS == (SortSpec) sortSpec )
return;
sortS = (SortSpec) sortSpec;
dirty = TRUE;
}
/*!
\fn bool QDir::matchAllDirs() const
Returns the value set by setMatchAllDirs()
\sa setMatchAllDirs()
*/
/*!
If \a enable is TRUE then all directories are included (e.g. in
entryList()), and the nameFilter() is only applied to the files.
If \a enable is FALSE then the nameFilter() is applied to both
directories and files.
\sa matchAllDirs()
*/
void QDir::setMatchAllDirs( bool enable )
{
if ( (bool)allDirs == enable )
return;
allDirs = enable;
dirty = TRUE;
}
/*!
Returns the total number of directories and files that were found.
Equivalent to entryList().count().
\sa operator[](), entryList()
*/
uint QDir::count() const
{
return (uint)entryList().count();
}
/*!
Returns the file name at position \a index in the list of file
names. Equivalent to entryList().at(index).
Returns a QString::null if the \a index is out of range or if the
entryList() function failed.
\sa count(), entryList()
*/
QString QDir::operator[]( int index ) const
{
entryList();
return fList && index >= 0 && index < (int)fList->count() ?
(*fList)[index] : QString::null;
}
/*!
\obsolete
This function is included to easy porting from Qt 1.x to Qt 2.0,
it is the same as entryList(), but encodes the filenames as 8-bit
strings using QFile::encodedName().
It is more efficient to use entryList().
*/
QStrList QDir::encodedEntryList( int filterSpec, int sortSpec ) const
{
QStrList r;
QStringList l = entryList(filterSpec,sortSpec);
for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
r.append( QFile::encodeName(*it) );
}
return r;
}
/*!
\obsolete
\overload
This function is included to easy porting from Qt 1.x to Qt 2.0,
it is the same as entryList(), but encodes the filenames as 8-bit
strings using QFile::encodedName().
It is more efficient to use entryList().
*/
QStrList QDir::encodedEntryList( const QString &nameFilter,
int filterSpec,
int sortSpec ) const
{
QStrList r;
QStringList l = entryList(nameFilter,filterSpec,sortSpec);
for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
r.append( QFile::encodeName(*it) );
}
return r;
}
/*!
\overload
Returns a list of the names of all the files and directories in
the directory, ordered in accordance with setSorting() and
filtered in accordance with setFilter() and setNameFilter().
The filter and sorting specifications can be overridden using the
\a filterSpec and \a sortSpec arguments.
Returns an empty list if the directory is unreadable or does not
exist.
\sa entryInfoList(), setNameFilter(), setSorting(), setFilter()
*/
QStringList QDir::entryList( int filterSpec, int sortSpec ) const
{
if ( !dirty && filterSpec == (int)DefaultFilter &&
sortSpec == (int)DefaultSort )
return *fList;
return entryList( nameFilt, filterSpec, sortSpec );
}
/*!
Returns a list of the names of all the files and directories in
the directory, ordered in accordance with setSorting() and
filtered in accordance with setFilter() and setNameFilter().
The filter and sorting specifications can be overridden using the
\a nameFilter, \a filterSpec and \a sortSpec arguments.
Returns an empty list if the directory is unreadable or does not
exist.
\sa entryInfoList(), setNameFilter(), setSorting(), setFilter()
*/
QStringList QDir::entryList( const QString &nameFilter,
int filterSpec, int sortSpec ) const
{
if ( filterSpec == (int)DefaultFilter )
filterSpec = filtS;
if ( sortSpec == (int)DefaultSort )
sortSpec = sortS;
QDir *that = (QDir*)this; // mutable function
if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) {
if ( that->fList )
return *that->fList;
}
return QStringList();
}
/*!
\overload
Returns a list of QFileInfo objects for all the files and
directories in the directory, ordered in accordance with
setSorting() and filtered in accordance with setFilter() and
setNameFilter().
The filter and sorting specifications can be overridden using the
\a filterSpec and \a sortSpec arguments.
Returns 0 if the directory is unreadable or does not exist.
The returned pointer is a const pointer to a QFileInfoList. The
list is owned by the QDir object and will be reused on the next
call to entryInfoList() for the same QDir instance. If you want to
keep the entries of the list after a subsequent call to this
function you must copy them.
\sa entryList(), setNameFilter(), setSorting(), setFilter()
*/
const QFileInfoList *QDir::entryInfoList( int filterSpec, int sortSpec ) const
{
if ( !dirty && filterSpec == (int)DefaultFilter &&
sortSpec == (int)DefaultSort )
return fiList;
return entryInfoList( nameFilt, filterSpec, sortSpec );
}
/*!
Returns a list of QFileInfo objects for all the files and
directories in the directory, ordered in accordance with
setSorting() and filtered in accordance with setFilter() and
setNameFilter().
The filter and sorting specifications can be overridden using the
\a nameFilter, \a filterSpec and \a sortSpec arguments.
Returns 0 if the directory is unreadable or does not exist.
The returned pointer is a const pointer to a QFileInfoList. The
list is owned by the QDir object and will be reused on the next
call to entryInfoList() for the same QDir instance. If you want to
keep the entries of the list after a subsequent call to this
function you must copy them.
\sa entryList(), setNameFilter(), setSorting(), setFilter()
*/
const QFileInfoList *QDir::entryInfoList( const QString &nameFilter,
int filterSpec, int sortSpec ) const
{
if ( filterSpec == (int)DefaultFilter )
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 )
if ( f1->item->isDir() != f2->item->isDir() )
return f1->item->isDir() ? -1 : 1;
int r = 0;
int sortBy = qt_cmp_si_sortSpec & QDir::SortByMask;
switch ( sortBy ) {
case QDir::Time:
r = f1->item->lastModified().secsTo(f2->item->lastModified());
break;
case QDir::Size:
r = f2->item->size() - f1->item->size();
break;
default:
;
}
if ( r == 0 && sortBy != QDir::Unsorted ) {
// Still not sorted - sort by name
bool ic = qt_cmp_si_sortSpec & QDir::IgnoreCase;
if ( f1->filename_cache.isNull() )
f1->filename_cache = ic ? f1->item->fileName().lower()
: f1->item->fileName();
if ( f2->filename_cache.isNull() )
f2->filename_cache = ic ? f2->item->fileName().lower()
: f2->item->fileName();
r = f1->filename_cache.compare(f2->filename_cache);
}
if ( r == 0 ) {
// Enforce an order - the order the items appear in the array
r = (char*)n1 - (char*)n2;
}
if ( qt_cmp_si_sortSpec & QDir::Reversed )
return -r;
else
return r;
}
#if defined(Q_C_CALLBACKS)
}
#endif
#endif // QT_NO_DIR
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 ) {
+ if ( ::getcwd( cur, PATH_MAX ) ) {
char tmp[PATH_MAX+1];
- if ( ::getcwd( tmp, PATH_MAX ) )
+ if( ::realpath( QFile::encodeName( dPath ), tmp ) )
r = QFile::decodeName(tmp);
+ slashify( r );
+
+ // always make sure we go back to the current dir
::chdir( cur );
}
-
- slashify( r );
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,614 +1,615 @@
/****************************************************************************
** $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().
\sa setName(), QFileInfo::fileName()
*/
/*!
Sets the name of the file to \a name. The name can have no path, a
relative path or an absolute absolute path.
Do not call this function if the file has already been opened.
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;
}
/*!
Reads a single byte/character from the file.
Returns the byte/character read, or -1 if the end of the file has
been reached.
\sa putch(), ungetch()
*/
int QFile::getch()
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // file not open
qWarning( "QFile::getch: File not open" );
return EOF;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QFile::getch: Read operation not permitted" );
return EOF;
}
#endif
int ch;
if ( !ungetchBuffer.isEmpty() ) {
int len = ungetchBuffer.length();
ch = ungetchBuffer[ len-1 ];
ungetchBuffer.truncate( len - 1 );
return ch;
}
if ( isRaw() ) { // raw file (inefficient)
char buf[1];
ch = readBlock( buf, 1 ) == 1 ? buf[0] : EOF;
} else { // buffered file
if ( (ch = getc( fh )) != EOF )
if ( !isSequentialAccess() )
ioIndex++;
else
setStatus(IO_ReadError);
}
return ch;
}
/*!
Writes the character \a ch to the file.
Returns \a ch, or -1 if some error occurred.
\sa getch(), ungetch()
*/
int QFile::putch( int ch )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // file not open
qWarning( "QFile::putch: File not open" );
return EOF;
}
if ( !isWritable() ) { // writing not permitted
qWarning( "QFile::putch: Write operation not permitted" );
return EOF;
}
#endif
if ( isRaw() ) { // raw file (inefficient)
char buf[1];
buf[0] = ch;
ch = writeBlock( buf, 1 ) == 1 ? ch : EOF;
} else { // buffered file
if ( (ch = putc( ch, fh )) != EOF ) {
if ( !isSequentialAccess() )
ioIndex++;
if ( ioIndex > length ) // update file length
length = ioIndex;
} else {
setStatus(IO_WriteError);
}
}
return ch;
}
/*!
Puts the character \a ch back into the file and decrements the
index if it is not zero.
This function is normally called to "undo" a getch() operation.
Returns \a ch, or -1 if an error occurred.
\sa getch(), putch()
*/
int QFile::ungetch( int ch )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // file not open
qWarning( "QFile::ungetch: File not open" );
return EOF;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QFile::ungetch: Read operation not permitted" );
return EOF;
}
#endif
if ( ch == EOF ) // cannot unget EOF
return ch;
if ( isSequentialAccess() && !fh) {
// pipe or similar => we cannot ungetch, so do it manually
ungetchBuffer +=ch;
return ch;
}
if ( isRaw() ) { // raw file (very inefficient)
char buf[1];
at( ioIndex-1 );
buf[0] = ch;
if ( writeBlock(buf, 1) == 1 )
at ( ioIndex-1 );
else
ch = EOF;
} else { // buffered file
if ( (ch = ungetc(ch, fh)) != EOF )
if ( !isSequentialAccess() )
ioIndex--;
else
setStatus( IO_ReadError );
}
return ch;
}
static QCString locale_encoder( const QString &fileName )
{
return fileName.local8Bit();
}
static QFile::EncoderFn encoder = locale_encoder;
/*!
When you use QFile, QFileInfo, and QDir to access the file system
with Qt, you can use Unicode file names. On Unix, these file names
are converted to an 8-bit encoding. If you want to do your own
file I/O on Unix, you should convert the file name using this
function. On Windows NT/2000, Unicode file names are supported
directly in the file system and this function should be avoided.
On Windows 95, non-Latin1 locales are not supported.
By default, this function converts \a fileName to the local 8-bit
encoding determined by the user's locale. This is sufficient for
file names that the user chooses. File names hard-coded into the
application should only use 7-bit ASCII filename characters.
The conversion scheme can be changed using setEncodingFunction().
This might be useful if you wish to give the user an option to
store file names in UTF-8, etc., but be aware that such file names
would probably then be unrecognizable when seen by other programs.
\sa decodeName()
*/
QCString QFile::encodeName( const QString &fileName )
{
return (*encoder)(fileName);
}
/*!
\enum QFile::EncoderFn
This is used by QFile::setEncodingFunction().
*/
/*!
\nonreentrant
Sets the function for encoding Unicode file names to \a f. The
default encodes in the locale-specific 8-bit encoding.
\sa encodeName()
*/
void QFile::setEncodingFunction( EncoderFn f )
{
encoder = f;
}
static
QString locale_decoder( const QCString &localFileName )
{
return QString::fromLocal8Bit(localFileName);
}
static QFile::DecoderFn decoder = locale_decoder;
/*!
This does the reverse of QFile::encodeName() using \a localFileName.
\sa setDecodingFunction()
*/
QString QFile::decodeName( const QCString &localFileName )
{
return (*decoder)(localFileName);
}
/*!
\enum QFile::DecoderFn
This is used by QFile::setDecodingFunction().
*/
/*!
\nonreentrant
Sets the function for decoding 8-bit file names to \a f. The
default uses the locale-specific 8-bit encoding.
\sa encodeName(), decodeName()
*/
void QFile::setDecodingFunction( DecoderFn f )
{
decoder = f;
}
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
@@ -1,687 +1,692 @@
/****************************************************************************
** $Id$
**
** Implementation of QFile class
**
** Created : 950628
**
** 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 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"
// 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 "qfile.h"
#include <errno.h>
#include <limits.h>
bool qt_file_access( const QString& fn, int t )
{
if ( fn.isEmpty() )
return FALSE;
return ::access( QFile::encodeName(fn), t ) == 0;
}
/*!
\overload
Removes the file \a fileName.
Returns TRUE if successful, otherwise FALSE.
*/
bool QFile::remove( const QString &fileName )
{
if ( fileName.isEmpty() ) {
#if defined(QT_CHECK_NULL)
qWarning( "QFile::remove: Empty or null file name" );
#endif
return FALSE;
}
return unlink( QFile::encodeName(fileName) ) == 0;
}
#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
/*!
Opens the file specified by the file name currently set, using the
mode \a m. Returns TRUE if successful, otherwise FALSE.
\keyword IO_Raw
\keyword IO_ReadOnly
\keyword IO_WriteOnly
\keyword IO_ReadWrite
\keyword IO_Append
\keyword IO_Truncate
\keyword IO_Translate
The mode parameter \a m must be a combination of the following flags:
\table
\header \i Flag \i Meaning
\row \i IO_Raw
\i Raw (non-buffered) file access.
\row \i IO_ReadOnly
\i Opens the file in read-only mode.
\row \i IO_WriteOnly
\i Opens the file in write-only mode. If this flag is used
with another flag, e.g. \c IO_ReadOnly or \c IO_Raw or \c
IO_Append, the file is \e not truncated; but if used on
its own (or with \c IO_Truncate), the file is truncated.
\row \i IO_ReadWrite
\i Opens the file in read/write mode, equivalent to \c
(IO_ReadOnly | IO_WriteOnly).
\row \i IO_Append
\i Opens the file in append mode. (You must actually use \c
(IO_WriteOnly | IO_Append) to make the file writable and
to go into append mode.) This mode is very useful when you
want to write something to a log file. The file index is
set to the end of the file. Note that the result is
undefined if you position the file index manually using
at() in append mode.
\row \i IO_Truncate
\i Truncates the file.
\row \i IO_Translate
\i Enables carriage returns and linefeed translation for text
files under Windows.
\endtable
The raw access mode is best when I/O is block-operated using a 4KB
block size or greater. Buffered access works better when reading
small portions of data at a time.
\warning When working with buffered files, data may not be written
to the file at once. Call flush() to make sure that the data is
really written.
\warning If you have a buffered file opened for both reading and
writing you must not perform an input operation immediately after
an output operation or vice versa. You should always call flush()
or a file positioning operation, e.g. at(), between input and
output operations, otherwise the buffer may contain garbage.
If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite
is specified, it is created.
Example:
\code
QFile f1( "/tmp/data.bin" );
f1.open( IO_Raw | IO_ReadWrite );
QFile f2( "readme.txt" );
f2.open( IO_ReadOnly | IO_Translate );
QFile f3( "audit.log" );
f3.open( IO_WriteOnly | IO_Append );
\endcode
\sa name(), close(), isOpen(), flush()
*/
bool QFile::open( int m )
{
if ( isOpen() ) { // file already open
#if defined(QT_CHECK_STATE)
qWarning( "QFile::open: File already open" );
#endif
return FALSE;
}
if ( fn.isNull() ) { // no file name defined
#if defined(QT_CHECK_NULL)
qWarning( "QFile::open: No file name specified" );
#endif
return FALSE;
}
init(); // reset params
setMode( m );
if ( !(isReadable() || isWritable()) ) {
#if defined(QT_CHECK_RANGE)
qWarning( "QFile::open: File access not specified" );
#endif
return FALSE;
}
bool ok = TRUE;
struct stat st;
if ( isRaw() ) {
int oflags = O_RDONLY;
if ( isReadable() && isWritable() )
oflags = O_RDWR;
else if ( isWritable() )
oflags = O_WRONLY;
if ( flags() & IO_Append ) { // append to end of file?
if ( flags() & IO_Truncate )
oflags |= (O_CREAT | O_TRUNC);
else
oflags |= (O_APPEND | O_CREAT);
setFlags( flags() | IO_WriteOnly ); // append implies write
} else if ( isWritable() ) { // create/trunc if writable
if ( flags() & IO_Truncate )
oflags |= (O_CREAT | O_TRUNC);
else
oflags |= O_CREAT;
}
#if defined(HAS_TEXT_FILEMODE)
if ( isTranslated() )
oflags |= OPEN_TEXT;
else
oflags |= OPEN_BINARY;
#endif
#if defined(HAS_ASYNC_FILEMODE)
if ( isAsynchronous() )
oflags |= OPEN_ASYNC;
#endif
fd = qt_open( QFile::encodeName(fn), oflags, 0666 );
if ( fd != -1 ) { // open successful
::fstat( fd, &st ); // get the stat for later usage
} else {
ok = FALSE;
}
} else { // buffered file I/O
QCString perm;
char perm2[4];
bool try_create = FALSE;
if ( flags() & IO_Append ) { // append to end of file?
setFlags( flags() | IO_WriteOnly ); // append implies write
perm = isReadable() ? "a+" : "a";
} else {
if ( isReadWrite() ) {
if ( flags() & IO_Truncate ) {
perm = "w+";
} else {
perm = "r+";
try_create = TRUE; // try to create if not exists
}
} else if ( isReadable() ) {
perm = "r";
} else if ( isWritable() ) {
perm = "w";
}
}
qstrcpy( perm2, perm );
#if defined(HAS_TEXT_FILEMODE)
if ( isTranslated() )
strcat( perm2, "t" );
else
strcat( perm2, "b" );
#endif
for (;;) { // At most twice
fh = fopen( QFile::encodeName(fn), perm2 );
if ( !fh && try_create ) {
perm2[0] = 'w'; // try "w+" instead of "r+"
try_create = FALSE;
} else {
break;
}
}
if ( fh ) {
::fstat( fileno(fh), &st ); // get the stat for later usage
} else {
ok = FALSE;
}
}
if ( ok ) {
setState( IO_Open );
// on successful open the file stat was got; now test what type
// of file we have
if ( (st.st_mode & S_IFMT) != S_IFREG ) {
// non-seekable
setType( IO_Sequential );
length = INT_MAX;
ioIndex = 0;
} else {
length = (Offset)st.st_size;
ioIndex = (flags() & IO_Append) == 0 ? 0 : length;
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;
}
}
}
} else {
init();
if ( errno == EMFILE ) // no more file handles/descrs
setStatus( IO_ResourceError );
else
setStatus( IO_OpenError );
}
return ok;
}
/*!
\overload
Opens a file in the mode \a m using an existing file handle \a f.
Returns TRUE if successful, otherwise FALSE.
Example:
\code
#include <stdio.h>
void printError( const char* msg )
{
QFile f;
f.open( IO_WriteOnly, stderr );
f.writeBlock( msg, qstrlen(msg) ); // write to stderr
f.close();
}
\endcode
When a QFile is opened using this function, close() does not actually
close the file, only flushes it.
\warning If \a f is \c stdin, \c stdout, \c stderr, you may not
be able to seek. See QIODevice::isSequentialAccess() for more
information.
\sa close()
*/
bool QFile::open( int m, FILE *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 );
fh = f;
ext_f = TRUE;
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
@@ -1,659 +1,661 @@
/****************************************************************************
** $Id$
**
** Implementation of QFileInfo class
**
** Created : 950628
**
** 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"
#include "qfileinfo.h"
#include "qdatetime.h"
#include "qdir.h"
#include "qfiledefs_p.h"
#if defined(QT_LARGEFILE_SUPPORT) && !defined(QT_ABI_QT4)
#include <limits.h>
#endif
extern bool qt_file_access( const QString& fn, int t );
/*!
\class QFileInfo
\reentrant
\brief The QFileInfo class provides system-independent file information.
\ingroup io
QFileInfo provides information about a file's name and position
(path) in the file system, its access rights and whether it is a
directory or symbolic link, etc. The file's size and last
modified/read times are also available.
A QFileInfo can point to a file with either a relative or an
absolute file path. Absolute file paths begin with the directory
separator "/" (or with a drive specification on Windows). Relative
file names begin with a directory name or a file name and specify
a path relative to the current working directory. 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 whether a QFileInfo is using a relative or an absolute file
path. You can call the function convertToAbs() to convert a
relative QFileInfo's path to an absolute path.
The file that the QFileInfo works on is set in the constructor or
later with setFile(). Use exists() to see if the file exists and
size() to get its size.
To speed up performance, QFileInfo caches information about the
file. Because files can be changed by other users or programs, or
even by other parts of the same program, there is a function that
refreshes the file information: refresh(). If you want to switch
off a QFileInfo's caching and force it to access the file system
every time you request information from it call setCaching(FALSE).
The file's type is obtained with isFile(), isDir() and
isSymLink(). The readLink() function provides the name of the file
the symlink points to.
Elements of the file's name can be extracted with dirPath() and
fileName(). The fileName()'s parts can be extracted with
baseName() and extension().
The file's dates are returned by created(), lastModified() and
lastRead(). Information about the file's access permissions is
obtained with isReadable(), isWritable() and isExecutable(). The
file's ownership is available from owner(), ownerId(), group() and
groupId(). You can examine a file's permissions and ownership in a
single statement using the permission() function.
If you need to read and traverse directories, see the QDir class.
*/
/*!
\enum QFileInfo::PermissionSpec
This enum is used by the permission() function to report the
permissions and ownership of a file. The values may be OR-ed
together to test multiple permissions and ownership values.
\value ReadUser The file is readable by the user.
\value WriteUser The file is writable by the user.
\value ExeUser The file is executable by the user.
\value ReadGroup The file is readable by the group.
\value WriteGroup The file is writable by the group.
\value ExeGroup The file is executable by the group.
\value ReadOther The file is readable by anyone.
\value WriteOther The file is writable by anyone.
\value ExeOther The file is executable by anyone.
*/
/*!
Constructs a new empty QFileInfo.
*/
QFileInfo::QFileInfo()
{
fic = 0;
cache = TRUE;
#if defined(Q_OS_UNIX)
symLink = FALSE;
#endif
}
/*!
Constructs a new QFileInfo that gives information about the given
file. The \a file can also include an absolute or relative path.
\sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
QFileInfo::QFileInfo( const QString &file )
{
fn = file;
slashify( fn );
fic = 0;
cache = TRUE;
#if defined(Q_OS_UNIX)
symLink = FALSE;
#endif
}
/*!
Constructs a new QFileInfo that gives information about file \a
file.
If the \a file has a relative path, the QFileInfo will also have a
relative path.
\sa isRelative()
*/
QFileInfo::QFileInfo( const QFile &file )
{
fn = file.name();
slashify( fn );
fic = 0;
cache = TRUE;
#if defined(Q_OS_UNIX)
symLink = FALSE;
#endif
}
/*!
Constructs a new QFileInfo that gives information about the file
called \a fileName in the directory \a d.
If \a d has a relative path, the QFileInfo will also have a
relative path.
\sa isRelative()
*/
#ifndef QT_NO_DIR
QFileInfo::QFileInfo( const QDir &d, const QString &fileName )
{
fn = d.filePath( fileName );
slashify( fn );
fic = 0;
cache = TRUE;
#if defined(Q_OS_UNIX)
symLink = FALSE;
#endif
}
#endif
/*!
Constructs a new QFileInfo that is a copy of \a fi.
*/
QFileInfo::QFileInfo( const QFileInfo &fi )
{
fn = fi.fn;
if ( fi.fic ) {
fic = new QFileInfoCache;
*fic = *fi.fic;
} else {
fic = 0;
}
cache = fi.cache;
#if defined(Q_OS_UNIX)
symLink = fi.symLink;
#endif
}
/*!
Destroys the QFileInfo and frees its resources.
*/
QFileInfo::~QFileInfo()
{
delete fic;
}
/*!
Makes a copy of \a fi and assigns it to this QFileInfo.
*/
QFileInfo &QFileInfo::operator=( const QFileInfo &fi )
{
fn = fi.fn;
if ( !fi.fic ) {
delete fic;
fic = 0;
} else {
if ( !fic ) {
fic = new QFileInfoCache;
Q_CHECK_PTR( fic );
}
*fic = *fi.fic;
}
cache = fi.cache;
#if defined(Q_OS_UNIX)
symLink = fi.symLink;
#endif
return *this;
}
/*!
Sets the file that the QFileInfo provides information about to \a
file.
The \a file can also include an absolute or relative file path.
Absolute paths begin with the directory separator (e.g. "/" under
Unix) or 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.
Example:
\code
QString absolute = "/local/bin";
QString relative = "local/bin";
QFileInfo absFile( absolute );
QFileInfo relFile( relative );
QDir::setCurrent( QDir::rootDirPath() );
// absFile and relFile now point to the same file
QDir::setCurrent( "/tmp" );
// absFile now points to "/local/bin",
// while relFile points to "/tmp/local/bin"
\endcode
\sa isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
void QFileInfo::setFile( const QString &file )
{
fn = file;
slashify( fn );
delete fic;
fic = 0;
}
/*!
\overload
Sets the file that the QFileInfo provides information about to \a
file.
If \a file includes a relative path, the QFileInfo will also have
a relative path.
\sa isRelative()
*/
void QFileInfo::setFile( const QFile &file )
{
fn = file.name();
slashify( fn );
delete fic;
fic = 0;
}
/*!
\overload
Sets the file that the QFileInfo provides information about to \a
fileName in directory \a d.
If \a fileName includes a relative path, the QFileInfo will also
have a relative path.
\sa isRelative()
*/
#ifndef QT_NO_DIR
void QFileInfo::setFile( const QDir &d, const QString &fileName )
{
fn = d.filePath( fileName );
slashify( fn );
delete fic;
fic = 0;
}
#endif
/*!
Returns TRUE if the file exists; otherwise returns FALSE.
*/
bool QFileInfo::exists() const
{
return qt_file_access( fn, F_OK );
}
/*!
Refreshes the information about the file, i.e. reads in information
from the file system the next time a cached property is fetched.
\sa setCaching()
*/
void QFileInfo::refresh() const
{
QFileInfo *that = (QFileInfo*)this; // Mutable function
delete that->fic;
that->fic = 0;
}
/*!
\fn bool QFileInfo::caching() const
Returns TRUE if caching is enabled; otherwise returns FALSE.
\sa setCaching(), refresh()
*/
/*!
If \a enable is TRUE, enables caching of file information. If \a
enable is FALSE caching is disabled.
When caching is enabled, QFileInfo reads the file information from
the file system the first time it's needed, but generally not
later.
Caching is enabled by default.
\sa refresh(), caching()
*/
void QFileInfo::setCaching( bool enable )
{
if ( cache == enable )
return;
cache = enable;
if ( cache ) {
delete fic;
fic = 0;
}
}
/*!
Returns the file name, including the path (which may be absolute
or relative).
\sa isRelative(), absFilePath()
*/
QString QFileInfo::filePath() const
{
return fn;
}
/*!
Returns the base name of the file.
If \a complete is FALSE (the default) the base name consists of
all characters in the file name up to (but not including) the \e
first '.' character.
If \a complete is TRUE the base name consists of all characters in
the file up to (but not including) the \e last '.' character.
The path is not included in either case.
Example:
\code
QFileInfo fi( "/tmp/archive.tar.gz" );
QString base = fi.baseName(); // base = "archive"
base = fi.baseName( TRUE ); // base = "archive.tar"
\endcode
\sa fileName(), extension()
*/
QString QFileInfo::baseName( bool complete ) const
{
QString tmp = fileName();
int pos = complete ? tmp.findRev( '.' ) : tmp.find( '.' );
if ( pos == -1 )
return tmp;
else
return tmp.left( pos );
}
/*!
Returns the file's extension name.
If \a complete is TRUE (the default), extension() returns the
string of all characters in the file name after (but not
including) the first '.' character.
If \a complete is FALSE, extension() returns the string of all
characters in the file name after (but not including) the last '.'
character.
Example:
\code
QFileInfo fi( "/tmp/archive.tar.gz" );
QString ext = fi.extension(); // ext = "tar.gz"
ext = fi.extension( FALSE ); // ext = "gz"
\endcode
\sa fileName(), baseName()
*/
QString QFileInfo::extension( bool complete ) const
{
QString s = fileName();
int pos = complete ? s.find( '.' ) : s.findRev( '.' );
if ( pos < 0 )
return QString::fromLatin1( "" );
else
return s.right( s.length() - pos - 1 );
}
/*!
Returns the file's path as a QDir object.
If the QFileInfo is relative and \a absPath is FALSE, the QDir
will be relative; otherwise it will be absolute.
\sa dirPath(), filePath(), fileName(), isRelative()
*/
#ifndef QT_NO_DIR
QDir QFileInfo::dir( bool absPath ) const
{
return QDir( dirPath(absPath) );
}
#endif
/*!
Returns TRUE if the file is readable; otherwise returns FALSE.
\sa isWritable(), isExecutable(), permission()
*/
bool QFileInfo::isReadable() const
{
return qt_file_access( fn, R_OK ) && permission( ReadUser );
}
/*!
Returns TRUE if the file is writable; otherwise returns FALSE.
\sa isReadable(), isExecutable(), permission()
*/
bool QFileInfo::isWritable() const
{
return qt_file_access( fn, W_OK ) && permission( WriteUser );
}
/*!
Returns TRUE if the file is executable; otherwise returns FALSE.
\sa isReadable(), isWritable(), permission()
*/
bool QFileInfo::isExecutable() const
{
return qt_file_access( fn, X_OK ) && permission( ExeUser );
}
#ifndef Q_WS_WIN
bool QFileInfo::isHidden() const
{
return fileName()[ 0 ] == QChar( '.' );
}
#endif
/*!
Returns TRUE if the file path name is relative. Returns FALSE if
the path is absolute (e.g. under Unix a path is absolute if it
begins with a "/").
*/
#ifndef QT_NO_DIR
bool QFileInfo::isRelative() const
{
return QDir::isRelativePath( fn );
}
/*!
Converts the file's path to an absolute path.
If it is already absolute, nothing is done.
\sa filePath(), isRelative()
*/
bool QFileInfo::convertToAbs()
{
if ( isRelative() )
fn = absFilePath();
return QDir::isRelativePath( fn );
}
#endif
/*!
Returns the file size in bytes, or 0 if the file does not exist or
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
@@ -1,331 +1,331 @@
/****************************************************************************
** $Id$
**
** Implementation of QFileInfo class
**
** Created : 950628
**
** 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 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 "qfileinfo.h"
#include "qfiledefs_p.h"
#include "qdatetime.h"
#include "qdir.h"
#include <limits.h>
void QFileInfo::slashify( QString& )
{
return;
}
void QFileInfo::makeAbs( QString & )
{
return;
}
/*!
Returns TRUE if this object points to a file. Returns FALSE if the
object points to something which isn't a file, e.g. a directory or
a symlink.
\sa isDir(), isSymLink()
*/
bool QFileInfo::isFile() const
{
if ( !fic || !cache )
doStat();
return fic ? (fic->st.st_mode & S_IFMT) == S_IFREG : FALSE;
}
/*!
Returns TRUE if this object points to a directory or to a symbolic
link to a directory; otherwise returns FALSE.
\sa isFile(), isSymLink()
*/
bool QFileInfo::isDir() const
{
if ( !fic || !cache )
doStat();
return fic ? (fic->st.st_mode & S_IFMT) == S_IFDIR : FALSE;
}
/*!
Returns TRUE if this object points to a symbolic link (or to a
shortcut on Windows); otherwise returns FALSE.
\sa isFile(), isDir(), readLink()
*/
bool QFileInfo::isSymLink() const
{
if ( !fic || !cache )
doStat();
return symLink;
}
/*!
Returns the name a symlink (or shortcut on Windows) points to, or
a QString::null if the object isn't a symbolic link.
This name may not represent an existing file; it is only a string.
QFileInfo::exists() returns TRUE if the symlink points to an
existing file.
\sa exists(), isSymLink(), isDir(), isFile()
*/
QString QFileInfo::readLink() const
{
QString r;
#if defined(Q_OS_UNIX) && !defined(Q_OS_OS2EMX)
char s[PATH_MAX+1];
if ( !isSymLink() )
return QString();
int len = readlink( QFile::encodeName(fn).data(), s, PATH_MAX );
if ( len >= 0 ) {
s[len] = '\0';
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
QFileInfo fi( "/tmp/archive.tar.gz" );
QString name = fi.fileName(); // name = "archive.tar.gz"
\endcode
\sa isRelative(), filePath(), baseName(), extension()
*/
QString QFileInfo::fileName() const
{
int p = fn.findRev( '/' );
if ( p == -1 ) {
return fn;
} else {
return fn.mid( p + 1 );
}
}
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,754 +1,817 @@
/****************************************************************************
** $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.
*/
void QGArray::resetRawData( const char *d, uint len )
{
if ( d != shd->data || len != shd->len ) {
#if defined(QT_CHECK_STATE)
qWarning( "QGArray::resetRawData: Inconsistent arguments" );
#endif
return;
}
shd->data = 0;
shd->len = 0;
}
/*!
Finds the first occurrence of \a d in the array from position \a index,
where \a sz is the size of the \a d element.
Note that \a index is given in units of \a sz, not bytes.
This function only compares whole cells, not bytes.
*/
int QGArray::find( const char *d, uint index, uint sz ) const
{
index *= sz;
if ( index >= shd->len ) {
#if defined(QT_CHECK_RANGE)
qWarning( "QGArray::find: Index %d out of range", index/sz );
#endif
return -1;
}
register uint i;
uint ii;
switch ( sz ) {
case 1: { // 8 bit elements
register char *x = data() + index;
char v = *d;
for ( i=index; i<shd->len; i++ ) {
if ( *x++ == v )
break;
}
ii = i;
}
break;
case 2: { // 16 bit elements
register Q_INT16 *x = (Q_INT16*)(data() + index);
Q_INT16 v = *((Q_INT16*)d);
for ( i=index; i<shd->len; i+=2 ) {
if ( *x++ == v )
break;
}
ii = i/2;
}
break;
case 4: { // 32 bit elements
register Q_INT32 *x = (Q_INT32*)(data() + index);
Q_INT32 v = *((Q_INT32*)d);
for ( i=index; i<shd->len; i+=4 ) {
if ( *x++ == v )
break;
}
ii = i/4;
}
break;
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
@@ -1,975 +1,978 @@
/****************************************************************************
** $Id$
**
** Implementation of QGDict and QGDictIterator classes
**
** Created : 920529
**
** 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 "qgdict.h"
#include "qptrlist.h"
#include "qstring.h"
#include "qdatastream.h"
#include <ctype.h>
/*!
\class QGDict
\reentrant
\ingroup collection
\brief The QGDict class is an internal class for implementing QDict template classes.
\internal
QGDict is a strictly internal class that acts as a base class for the
\link collection.html collection classes\endlink QDict and QIntDict.
QGDict has some virtual functions that can be reimplemented to customize
the subclasses.
\list
\i read() reads a collection/dictionary item from a QDataStream.
\i write() writes a collection/dictionary item to a QDataStream.
\endlist
Normally, you do not have to reimplement any of these functions.
*/
static const int op_find = 0;
static const int op_insert = 1;
static const int op_replace = 2;
class QGDItList : public QPtrList<QGDictIterator>
{
public:
QGDItList() : QPtrList<QGDictIterator>() {}
QGDItList( const QGDItList &list ) : QPtrList<QGDictIterator>(list) {}
~QGDItList() { clear(); }
QGDItList &operator=(const QGDItList &list)
{ return (QGDItList&)QPtrList<QGDictIterator>::operator=(list); }
};
/*****************************************************************************
Default implementation of special and virtual functions
*****************************************************************************/
/*!
Returns the hash key for \a key, when key is a string.
*/
int QGDict::hashKeyString( const QString &key )
{
#if defined(QT_CHECK_NULL)
if ( key.isNull() )
qWarning( "QGDict::hashKeyString: Invalid null key" );
#endif
int i;
register uint h=0;
uint g;
const QChar *p = key.unicode();
if ( cases ) { // case sensitive
for ( i=0; i<(int)key.length(); i++ ) {
h = (h<<4) + p[i].cell();
if ( (g = h & 0xf0000000) )
h ^= g >> 24;
h &= ~g;
}
} else { // case insensitive
for ( i=0; i<(int)key.length(); i++ ) {
h = (h<<4) + p[i].lower().cell();
if ( (g = h & 0xf0000000) )
h ^= g >> 24;
h &= ~g;
}
}
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;
}
++it;
}
return *this;
}
/*!
\fn uint QGDict::count() const
Returns the number of items in the dictionary.
*/
/*!
\fn uint QGDict::size() const
Returns the size of the hash array.
*/
/*!
The do-it-all function; \a op is one of op_find, op_insert, op_replace.
The key is \a key and the item is \a d.
*/
QPtrCollection::Item QGDict::look_string( const QString &key, QPtrCollection::Item d,
int op )
{
QStringBucket *n = 0;
int index = hashKeyString(key) % vlen;
if ( op == op_find ) { // find
if ( cases ) {
n = (QStringBucket*)vec[index];
while( n != 0 ) {
if ( key == n->getKey() )
return n->getData(); // item found
n = (QStringBucket*)n->getNext();
}
} else {
QString k = key.lower();
n = (QStringBucket*)vec[index];
while( n != 0 ) {
if ( k == n->getKey().lower() )
return n->getData(); // item found
n = (QStringBucket*)n->getNext();
}
}
return 0; // not found
}
if ( op == op_replace ) { // replace
if ( vec[index] != 0 ) // maybe something there
remove_string( key );
}
// op_insert or op_replace
n = new QStringBucket(key,newItem(d),vec[index]);
Q_CHECK_PTR( n );
#if defined(QT_CHECK_NULL)
if ( n->getData() == 0 )
qWarning( "QDict: Cannot insert null item" );
#endif
vec[index] = n;
numItems++;
return n->getData();
}
QPtrCollection::Item QGDict::look_ascii( const char *key, QPtrCollection::Item d, int op )
{
QAsciiBucket *n;
int index = hashKeyAscii(key) % vlen;
if ( op == op_find ) { // find
if ( cases ) {
for ( n=(QAsciiBucket*)vec[index]; n;
n=(QAsciiBucket*)n->getNext() ) {
if ( qstrcmp(n->getKey(),key) == 0 )
return n->getData(); // item found
}
} else {
for ( n=(QAsciiBucket*)vec[index]; n;
n=(QAsciiBucket*)n->getNext() ) {
if ( qstricmp(n->getKey(),key) == 0 )
return n->getData(); // item found
}
}
return 0; // not found
}
if ( op == op_replace ) { // replace
if ( vec[index] != 0 ) // maybe something there
remove_ascii( key );
}
// op_insert or op_replace
n = new QAsciiBucket(copyk ? qstrdup(key) : key,newItem(d),vec[index]);
Q_CHECK_PTR( n );
#if defined(QT_CHECK_NULL)
if ( n->getData() == 0 )
qWarning( "QAsciiDict: Cannot insert null item" );
#endif
vec[index] = n;
numItems++;
return n->getData();
}
QPtrCollection::Item QGDict::look_int( long key, QPtrCollection::Item d, int op )
{
QIntBucket *n;
int index = (int)((ulong)key % vlen); // simple hash
if ( op == op_find ) { // find
for ( n=(QIntBucket*)vec[index]; n;
n=(QIntBucket*)n->getNext() ) {
if ( n->getKey() == key )
return n->getData(); // item found
}
return 0; // not found
}
if ( op == op_replace ) { // replace
if ( vec[index] != 0 ) // maybe something there
remove_int( key );
}
// op_insert or op_replace
n = new QIntBucket(key,newItem(d),vec[index]);
Q_CHECK_PTR( n );
#if defined(QT_CHECK_NULL)
if ( n->getData() == 0 )
qWarning( "QIntDict: Cannot insert null item" );
#endif
vec[index] = n;
numItems++;
return n->getData();
}
QPtrCollection::Item QGDict::look_ptr( void *key, QPtrCollection::Item d, int op )
{
QPtrBucket *n;
int index = (int)((ulong)key % vlen); // simple hash
if ( op == op_find ) { // find
for ( n=(QPtrBucket*)vec[index]; n;
n=(QPtrBucket*)n->getNext() ) {
if ( n->getKey() == key )
return n->getData(); // item found
}
return 0; // not found
}
if ( op == op_replace ) { // replace
if ( vec[index] != 0 ) // maybe something there
remove_ptr( key );
}
// op_insert or op_replace
n = new QPtrBucket(key,newItem(d),vec[index]);
Q_CHECK_PTR( n );
#if defined(QT_CHECK_NULL)
if ( n->getData() == 0 )
qWarning( "QPtrDict: Cannot insert null item" );
#endif
vec[index] = n;
numItems++;
return n->getData();
}
/*!
Changes the size of the hashtable to \a newsize.
The contents of the dictionary are preserved,
but all iterators on the dictionary become invalid.
*/
void QGDict::resize( uint newsize )
{
// Save old information
QBaseBucket **old_vec = vec;
uint old_vlen = vlen;
bool old_copyk = copyk;
vec = new QBaseBucket *[vlen = newsize];
Q_CHECK_PTR( vec );
memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) );
numItems = 0;
copyk = FALSE;
// Reinsert every item from vec, deleting vec as we go
for ( uint index = 0; index < old_vlen; index++ ) {
switch ( keytype ) {
case StringKey:
{
QStringBucket *n=(QStringBucket *)old_vec[index];
while ( n ) {
look_string( n->getKey(), n->getData(), op_insert );
QStringBucket *t=(QStringBucket *)n->getNext();
delete n;
n = t;
}
}
break;
case AsciiKey:
{
QAsciiBucket *n=(QAsciiBucket *)old_vec[index];
while ( n ) {
look_ascii( n->getKey(), n->getData(), op_insert );
QAsciiBucket *t=(QAsciiBucket *)n->getNext();
delete n;
n = t;
}
}
break;
case IntKey:
{
QIntBucket *n=(QIntBucket *)old_vec[index];
while ( n ) {
look_int( n->getKey(), n->getData(), op_insert );
QIntBucket *t=(QIntBucket *)n->getNext();
delete n;
n = t;
}
}
break;
case PtrKey:
{
QPtrBucket *n=(QPtrBucket *)old_vec[index];
while ( n ) {
look_ptr( n->getKey(), n->getData(), op_insert );
QPtrBucket *t=(QPtrBucket *)n->getNext();
delete n;
n = t;
}
}
break;
}
}
delete [] old_vec;
// Restore state
copyk = old_copyk;
// Invalidate all iterators, since order is lost
if ( iterators && iterators->count() ) {
QGDictIterator *i = iterators->first();
while ( i ) {
i->toFirst();
i = iterators->next();
}
}
}
/*!
Unlinks the bucket with the specified key (and specified data pointer,
if it is set).
*/
void QGDict::unlink_common( int index, QBaseBucket *node, QBaseBucket *prev )
{
if ( iterators && iterators->count() ) { // update iterators
QGDictIterator *i = iterators->first();
while ( i ) { // invalidate all iterators
if ( i->curNode == node ) // referring to pending node
i->operator++();
i = iterators->next();
}
}
if ( prev ) // unlink node
prev->setNext( node->getNext() );
else
vec[index] = node->getNext();
numItems--;
}
QStringBucket *QGDict::unlink_string( const QString &key, QPtrCollection::Item d )
{
if ( numItems == 0 ) // nothing in dictionary
return 0;
QStringBucket *n;
QStringBucket *prev = 0;
int index = hashKeyString(key) % vlen;
if ( cases ) {
for ( n=(QStringBucket*)vec[index]; n;
n=(QStringBucket*)n->getNext() ) {
bool found = (key == n->getKey());
if ( found && d )
found = (n->getData() == d);
if ( found ) {
unlink_common(index,n,prev);
return n;
}
prev = n;
}
} else {
QString k = key.lower();
for ( n=(QStringBucket*)vec[index]; n;
n=(QStringBucket*)n->getNext() ) {
bool found = (k == n->getKey().lower());
if ( found && d )
found = (n->getData() == d);
if ( found ) {
unlink_common(index,n,prev);
return n;
}
prev = n;
}
}
return 0;
}
QAsciiBucket *QGDict::unlink_ascii( const char *key, QPtrCollection::Item d )
{
if ( numItems == 0 ) // nothing in dictionary
return 0;
QAsciiBucket *n;
QAsciiBucket *prev = 0;
int index = hashKeyAscii(key) % vlen;
for ( n=(QAsciiBucket *)vec[index]; n; n=(QAsciiBucket *)n->getNext() ) {
bool found = (cases ? qstrcmp(n->getKey(),key)
: qstricmp(n->getKey(),key)) == 0;
if ( found && d )
found = (n->getData() == d);
if ( found ) {
unlink_common(index,n,prev);
return n;
}
prev = n;
}
return 0;
}
QIntBucket *QGDict::unlink_int( long key, QPtrCollection::Item d )
{
if ( numItems == 0 ) // nothing in dictionary
return 0;
QIntBucket *n;
QIntBucket *prev = 0;
int index = (int)((ulong)key % vlen);
for ( n=(QIntBucket *)vec[index]; n; n=(QIntBucket *)n->getNext() ) {
bool found = (n->getKey() == key);
if ( found && d )
found = (n->getData() == d);
if ( found ) {
unlink_common(index,n,prev);
return n;
}
prev = n;
}
return 0;
}
QPtrBucket *QGDict::unlink_ptr( void *key, QPtrCollection::Item d )
{
if ( numItems == 0 ) // nothing in dictionary
return 0;
QPtrBucket *n;
QPtrBucket *prev = 0;
int index = (int)((ulong)key % vlen);
for ( n=(QPtrBucket *)vec[index]; n; n=(QPtrBucket *)n->getNext() ) {
bool found = (n->getKey() == key);
if ( found && d )
found = (n->getData() == d);
if ( found ) {
unlink_common(index,n,prev);
return n;
}
prev = n;
}
return 0;
}
/*!
Removes the item with the specified \a key. If \a item is not null,
the remove will match the \a item as well (used to remove an
item when several items have the same key).
*/
bool QGDict::remove_string( const QString &key, QPtrCollection::Item item )
{
QStringBucket *n = unlink_string( key, item );
if ( n ) {
deleteItem( n->getData() );
delete n;
return TRUE;
} else {
return FALSE;
}
}
bool QGDict::remove_ascii( const char *key, QPtrCollection::Item item )
{
QAsciiBucket *n = unlink_ascii( key, item );
if ( n ) {
if ( copyk )
delete [] (char *)n->getKey();
deleteItem( n->getData() );
delete n;
}
return n != 0;
}
bool QGDict::remove_int( long key, QPtrCollection::Item item )
{
QIntBucket *n = unlink_int( key, item );
if ( n ) {
deleteItem( n->getData() );
delete n;
}
return n != 0;
}
bool QGDict::remove_ptr( void *key, QPtrCollection::Item item )
{
QPtrBucket *n = unlink_ptr( key, item );
if ( n ) {
deleteItem( n->getData() );
delete n;
}
return n != 0;
}
QPtrCollection::Item QGDict::take_string( const QString &key )
{
QStringBucket *n = unlink_string( key );
Item d;
if ( n ) {
d = n->getData();
delete n;
} else {
d = 0;
}
return d;
}
QPtrCollection::Item QGDict::take_ascii( const char *key )
{
QAsciiBucket *n = unlink_ascii( key );
Item d;
if ( n ) {
if ( copyk )
delete [] (char *)n->getKey();
d = n->getData();
delete n;
} else {
d = 0;
}
return d;
}
QPtrCollection::Item QGDict::take_int( long key )
{
QIntBucket *n = unlink_int( key );
Item d;
if ( n ) {
d = n->getData();
delete n;
} else {
d = 0;
}
return d;
}
QPtrCollection::Item QGDict::take_ptr( void *key )
{
QPtrBucket *n = unlink_ptr( key );
Item d;
if ( n ) {
d = n->getData();
delete n;
} else {
d = 0;
}
return d;
}
/*!
Removes all items from the dictionary.
*/
void QGDict::clear()
{
if ( !numItems )
return;
numItems = 0; // disable remove() function
for ( uint j=0; j<vlen; j++ ) { // destroy hash table
if ( vec[j] ) {
switch ( keytype ) {
case StringKey:
{
QStringBucket *n=(QStringBucket *)vec[j];
while ( n ) {
QStringBucket *next = (QStringBucket*)n->getNext();
deleteItem( n->getData() );
delete n;
n = next;
}
}
break;
case AsciiKey:
{
QAsciiBucket *n=(QAsciiBucket *)vec[j];
while ( n ) {
QAsciiBucket *next = (QAsciiBucket*)n->getNext();
if ( copyk )
delete [] (char *)n->getKey();
deleteItem( n->getData() );
delete n;
n = next;
}
}
break;
case IntKey:
{
QIntBucket *n=(QIntBucket *)vec[j];
while ( n ) {
QIntBucket *next = (QIntBucket*)n->getNext();
deleteItem( n->getData() );
delete n;
n = next;
}
}
break;
case PtrKey:
{
QPtrBucket *n=(QPtrBucket *)vec[j];
while ( n ) {
QPtrBucket *next = (QPtrBucket*)n->getNext();
deleteItem( n->getData() );
delete n;
n = next;
}
}
break;
}
vec[j] = 0; // detach list of buckets
}
}
if ( iterators && iterators->count() ) { // invalidate all iterators
QGDictIterator *i = iterators->first();
while ( i ) {
i->curNode = 0;
i = iterators->next();
}
}
}
/*!
Outputs debug statistics.
*/
void QGDict::statistics() const
{
#if defined(QT_DEBUG)
QString line;
line.fill( '-', 60 );
double real, ideal;
qDebug( line.ascii() );
qDebug( "DICTIONARY STATISTICS:" );
if ( count() == 0 ) {
qDebug( "Empty!" );
qDebug( line.ascii() );
return;
}
real = 0.0;
ideal = (float)count()/(2.0*size())*(count()+2.0*size()-1);
uint i = 0;
while ( i<size() ) {
QBaseBucket *n = vec[i];
int b = 0;
while ( n ) { // count number of buckets
b++;
n = n->getNext();
}
real = real + (double)b * ((double)b+1.0)/2.0;
char buf[80], *pbuf;
if ( b > 78 )
b = 78;
pbuf = buf;
while ( b-- )
*pbuf++ = '*';
*pbuf = '\0';
qDebug( buf );
i++;
}
qDebug( "Array size = %d", size() );
qDebug( "# items = %d", count() );
qDebug( "Real dist = %g", real );
qDebug( "Rand dist = %g", ideal );
qDebug( "Real/Rand = %g", real/ideal );
qDebug( line.ascii() );
#endif // QT_DEBUG
}
/*****************************************************************************
QGDict stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
QDataStream &operator>>( QDataStream &s, QGDict &dict )
{
return dict.read( s );
}
QDataStream &operator<<( QDataStream &s, const QGDict &dict )
{
return dict.write( s );
}
#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
#pragma message disable narrowptr
#endif
/*!
Reads a dictionary from the stream \a s.
*/
QDataStream &QGDict::read( QDataStream &s )
{
uint num;
s >> num; // read number of items
clear(); // clear dict
while ( num-- ) { // read all items
Item d;
switch ( keytype ) {
case StringKey:
{
QString k;
s >> k;
read( s, d );
look_string( k, d, op_insert );
}
break;
case AsciiKey:
{
char *k;
s >> k;
read( s, d );
look_ascii( k, d, op_insert );
if ( copyk )
delete [] k;
}
break;
case IntKey:
{
Q_UINT32 k;
s >> k;
read( s, d );
look_int( k, d, op_insert );
}
break;
case PtrKey:
{
Q_UINT32 k;
s >> k;
read( s, d );
// ### cannot insert 0 - this renders the thing
// useless since all pointers are written as 0,
// but hey, serializing pointers? can it be done
// at all, ever?
if ( k )
look_ptr( (void *)k, d, op_insert );
}
break;
}
}
return s;
}
/*!
Writes the dictionary to the stream \a s.
*/
QDataStream& QGDict::write( QDataStream &s ) const
{
s << count(); // write number of items
uint i = 0;
while ( i<size() ) {
QBaseBucket *n = vec[i];
while ( n ) { // write all buckets
switch ( keytype ) {
case StringKey:
s << ((QStringBucket*)n)->getKey();
break;
case AsciiKey:
s << ((QAsciiBucket*)n)->getKey();
break;
case IntKey:
s << (Q_UINT32)((QIntBucket*)n)->getKey();
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
@@ -1,1105 +1,1101 @@
/****************************************************************************
** $Id$
**
** Implementation of QGList and QGListIterator classes
**
** Created : 920624
**
** 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 "qglist.h"
#include "qgvector.h"
#include "qdatastream.h"
#include "qvaluelist.h"
/*!
\class QLNode qglist.h
\reentrant
\ingroup collection
\brief The QLNode class is an internal class for the QPtrList template collection.
\internal
QLNode is a doubly-linked list node. It has three pointers:
\list 1
\i Pointer to the previous node.
\i Pointer to the next node.
\i Pointer to the actual data.
\endlist
It might sometimes be practical to have direct access to the list nodes
in a QPtrList, but it is seldom required.
Be very careful if you want to access the list nodes. The heap can
easily get corrupted if you make a mistake.
\sa QPtrList::currentNode(), QPtrList::removeNode(), QPtrList::takeNode()
*/
/*!
\fn QPtrCollection::Item QLNode::getData()
Returns a pointer (\c void*) to the actual data in the list node.
*/
/*!
\class QGList qglist.h
\reentrant
\ingroup collection
\brief The QGList class is an internal class for implementing Qt collection classes.
\internal
QGList is a strictly internal class that acts as a base class for
several collection classes; QPtrList, QPtrQueue and QPtrStack.
QGList has some virtual functions that can be reimplemented to
customize the subclasses, namely compareItems(), read() and
write. Normally, you do not have to reimplement any of these
functions. If you still want to reimplement them, see the QStrList
class (qstrlist.h) for an example.
*/
/* Internal helper class for QGList. Contains some optimization for
the typically case where only one iterators is activre on the list.
*/
class QGListIteratorList
{
public:
QGListIteratorList()
: list(0), iterator(0) {
}
~QGListIteratorList() {
notifyClear( TRUE );
delete list;
}
void add( QGListIterator* i ) {
if ( !iterator ) {
iterator = i;
} else if ( list ) {
list->push_front( i );
} else {
list = new QValueList<QGListIterator*>;
list->push_front( i );
}
}
void remove( QGListIterator* i ) {
if ( iterator == i ) {
iterator = 0;
} else if ( list ) {
list->remove( i );
if ( list->isEmpty() ) {
delete list;
list = 0;
}
}
}
void notifyClear( bool zeroList ) {
if ( iterator ) {
if ( zeroList )
iterator->list = 0;
iterator->curNode = 0;
}
if ( list ) {
for ( QValueList<QGListIterator*>::Iterator i = list->begin(); i != list->end(); ++i ) {
if ( zeroList )
(*i)->list = 0;
(*i)->curNode = 0;
}
}
}
void notifyRemove( QLNode* n, QLNode* curNode ) {
if ( iterator ) {
if ( iterator->curNode == n )
iterator->curNode = curNode;
}
if ( list ) {
for ( QValueList<QGListIterator*>::Iterator i = list->begin(); i != list->end(); ++i ) {
if ( (*i)->curNode == n )
(*i)->curNode = curNode;
}
}
}
private:
QValueList<QGListIterator*>* list;
QGListIterator* iterator;
};
/*****************************************************************************
Default implementation of virtual functions
*****************************************************************************/
/*!
Documented as QPtrList::compareItems().
Compares \a item1 with \a item2.
*/
int QGList::compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 )
{
return item1 != item2; // compare pointers
}
#ifndef QT_NO_DATASTREAM
/*!
\overload
Reads a collection/list item from the stream \a s and returns a reference
to the stream.
The default implementation sets \a item to 0.
\sa write()
*/
QDataStream &QGList::read( QDataStream &s, QPtrCollection::Item &item )
{
item = 0;
return s;
}
/*!
\overload
Writes a collection/list item to the stream \a s and
returns a reference to the stream.
The default implementation does nothing.
\sa read()
*/
QDataStream &QGList::write( QDataStream &s, QPtrCollection::Item ) const
{
return s;
}
#endif // QT_NO_DATASTREAM
/*****************************************************************************
QGList member functions
*****************************************************************************/
/*!
Constructs an empty list.
*/
QGList::QGList()
{
firstNode = lastNode = curNode = 0; // initialize list
numNodes = 0;
curIndex = -1;
iterators = 0; // initialize iterator list
}
/*!
Constructs a copy of \a list.
*/
QGList::QGList( const QGList & list )
: QPtrCollection( list )
{
firstNode = lastNode = curNode = 0; // initialize list
numNodes = 0;
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;
}
QLNode *nextNode = locate( index );
if ( !nextNode )
return FALSE;
QLNode *prevNode = nextNode->prev;
register QLNode *n = new QLNode( newItem(d) );
Q_CHECK_PTR( n );
nextNode->prev = n;
prevNode->next = n;
n->prev = prevNode; // link new node into list
n->next = nextNode;
curNode = n; // curIndex set by locate()
numNodes++;
return TRUE;
}
/*!
Relinks node \a n and makes it the first node in the list.
*/
void QGList::relinkNode( QLNode *n )
{
if ( n == firstNode ) // already first
return;
curNode = n;
unlink();
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;
}
/*!
Unlinks the current list node and returns a pointer to this node.
*/
QLNode *QGList::unlink()
{
if ( curNode == 0 ) // null current node
return 0;
register QLNode *n = curNode; // unlink this node
if ( n == firstNode ) { // removing first node ?
if ( (firstNode = n->next) ) {
firstNode->prev = 0;
} else {
lastNode = curNode = 0; // list becomes empty
curIndex = -1;
}
} else {
if ( n == lastNode ) { // removing last node ?
lastNode = n->prev;
lastNode->next = 0;
} else { // neither last nor first node
n->prev->next = n->next;
n->next->prev = n->prev;
}
}
if ( n->next ) { // change current node
curNode = n->next;
} else if ( n->prev ) {
curNode = n->prev;
curIndex--;
}
if ( iterators )
iterators->notifyRemove( n, curNode );
numNodes--;
return n;
}
/*!
Removes the node \a n from the list.
*/
bool QGList::removeNode( QLNode *n )
{
#if defined(QT_CHECK_NULL)
if ( n == 0 || (n->prev && n->prev->next != n) ||
(n->next && n->next->prev != n) ) {
qWarning( "QGList::removeNode: Corrupted node" );
return FALSE;
}
#endif
curNode = n;
unlink(); // unlink node
deleteItem( n->data ); // deallocate this node
delete n;
curNode = firstNode;
curIndex = curNode ? 0 : -1;
return TRUE;
}
/*!
Removes the item \a d from the list. Uses compareItems() to find the item.
If \a d is 0, removes the current item.
*/
bool QGList::remove( QPtrCollection::Item d )
{
if ( d && find(d) == -1 )
return FALSE;
QLNode *n = unlink();
if ( !n )
return FALSE;
deleteItem( n->data );
delete n;
return TRUE;
}
/*!
Removes the item \a d from the list.
*/
bool QGList::removeRef( QPtrCollection::Item d )
{
if ( findRef(d) == -1 )
return FALSE;
QLNode *n = unlink();
if ( !n )
return FALSE;
deleteItem( n->data );
delete n;
return TRUE;
}
/*!
\fn bool QGList::removeFirst()
Removes the first item in the list.
*/
/*!
\fn bool QGList::removeLast()
Removes the last item in the list.
*/
/*!
Removes the item at position \a index from the list.
*/
bool QGList::removeAt( uint index )
{
if ( !locate(index) )
return FALSE;
QLNode *n = unlink();
if ( !n )
return FALSE;
deleteItem( n->data );
delete n;
return TRUE;
}
/*!
Replaces the item at index \a index with \a d.
*/
bool QGList::replaceAt( uint index, QPtrCollection::Item d )
{
QLNode *n = locate( index );
if ( !n )
return FALSE;
if ( n->data != d ) {
deleteItem( n->data );
n->data = newItem( d );
}
return TRUE;
}
/*!
Takes the node \a n out of the list.
*/
QPtrCollection::Item QGList::takeNode( QLNode *n )
{
#if defined(QT_CHECK_NULL)
if ( n == 0 || (n->prev && n->prev->next != n) ||
(n->next && n->next->prev != n) ) {
qWarning( "QGList::takeNode: Corrupted node" );
return 0;
}
#endif
curNode = n;
unlink(); // unlink node
Item d = n->data;
delete n; // delete the node, not data
curNode = firstNode;
curIndex = curNode ? 0 : -1;
return d;
}
/*!
Takes the current item out of the list.
*/
QPtrCollection::Item QGList::take()
{
QLNode *n = unlink(); // unlink node
Item d = n ? n->data : 0;
delete n; // delete node, keep contents
return d;
}
/*!
Takes the item at position \a index out of the list.
*/
QPtrCollection::Item QGList::takeAt( uint index )
{
if ( !locate(index) )
return 0;
QLNode *n = unlink(); // unlink node
Item d = n ? n->data : 0;
delete n; // delete node, keep contents
return d;
}
/*!
Takes the first item out of the list.
*/
QPtrCollection::Item QGList::takeFirst()
{
first();
QLNode *n = unlink(); // unlink node
Item d = n ? n->data : 0;
delete n;
return d;
}
/*!
Takes the last item out of the list.
*/
QPtrCollection::Item QGList::takeLast()
{
last();
QLNode *n = unlink(); // unlink node
Item d = n ? n->data : 0;
delete n;
return d;
}
/*!
Removes all items from the list.
*/
void QGList::clear()
{
register QLNode *n = firstNode;
firstNode = lastNode = curNode = 0; // initialize list
numNodes = 0;
curIndex = -1;
if ( iterators )
iterators->notifyClear( FALSE );
QLNode *prevNode;
while ( n ) { // for all nodes ...
deleteItem( n->data ); // deallocate data
prevNode = n;
n = n->next;
delete prevNode; // deallocate node
}
}
/*!
Finds item \a d in the list. If \a fromStart is TRUE the search
begins at the first node; otherwise it begins at the current node.
*/
int QGList::findRef( QPtrCollection::Item d, bool fromStart )
{
register QLNode *n;
int index;
if ( fromStart ) { // start from first node
n = firstNode;
index = 0;
} else { // start from current node
n = curNode;
index = curIndex;
}
while ( n && n->data != d ) { // find exact match
n = n->next;
index++;
}
curNode = n;
curIndex = n ? index : -1;
return curIndex; // return position of item
}
/*!
Finds item \a d in the list using compareItems(). If \a fromStart is
TRUE the search begins at the first node; otherwise it begins at the
current node.
*/
int QGList::find( QPtrCollection::Item d, bool fromStart )
{
register QLNode *n;
int index;
if ( fromStart ) { // start from first node
n = firstNode;
index = 0;
} else { // start from current node
n = curNode;
index = curIndex;
}
while ( n && compareItems(n->data,d) ){ // find equal match
n = n->next;
index++;
}
curNode = n;
curIndex = n ? index : -1;
return curIndex; // return position of item
}
/*!
Counts the number item \a d occurs in the list.
*/
uint QGList::containsRef( QPtrCollection::Item d ) const
{
register QLNode *n = firstNode;
uint count = 0;
while ( n ) { // for all nodes...
if ( n->data == d ) // count # exact matches
count++;
n = n->next;
}
return count;
}
/*!
Counts the number of times item \a d occurs in the list. Uses
compareItems().
*/
uint QGList::contains( QPtrCollection::Item d ) const
{
register QLNode *n = firstNode;
uint count = 0;
QGList *that = (QGList*)this; // mutable for compareItems()
while ( n ) { // for all nodes...
if ( !that->compareItems(n->data,d) ) // count # equal matches
count++;
n = n->next;
}
return count;
}
/*!
\overload QPtrCollection::Item QGList::at( uint index )
Sets the item at position \a index to the current item.
*/
/*!
\fn int QGList::at() const
Returns the current index.
*/
/*!
\fn QLNode *QGList::currentNode() const
Returns the current node.
*/
/*!
\fn QPtrCollection::Item QGList::get() const
Returns the current item.
*/
/*!
\fn QPtrCollection::Item QGList::cfirst() const
Returns the first item in the list.
*/
/*!
\fn QPtrCollection::Item QGList::clast() const
Returns the last item in the list.
*/
/*!
Returns the first list item. Sets this to current.
*/
QPtrCollection::Item QGList::first()
{
if ( firstNode ) {
curIndex = 0;
return (curNode=firstNode)->data;
}
return 0;
}
/*!
Returns the last list item. Sets this to current.
*/
QPtrCollection::Item QGList::last()
{
if ( lastNode ) {
curIndex = numNodes-1;
return (curNode=lastNode)->data;
}
return 0;
}
/*!
Returns the next list item (after current). Sets this to current.
*/
QPtrCollection::Item QGList::next()
{
if ( curNode ) {
if ( curNode->next ) {
curIndex++;
curNode = curNode->next;
return curNode->data;
}
curIndex = -1;
curNode = 0;
}
return 0;
}
/*!
Returns the previous list item (before current). Sets this to current.
*/
QPtrCollection::Item QGList::prev()
{
if ( curNode ) {
if ( curNode->prev ) {
curIndex--;
curNode = curNode->prev;
return curNode->data;
}
curIndex = -1;
curNode = 0;
}
return 0;
}
/*!
Converts the list to a vector, \a vector.
*/
void QGList::toVector( QGVector *vector ) const
{
vector->clear();
if ( !vector->resize( count() ) )
return;
register QLNode *n = firstNode;
uint i = 0;
while ( n ) {
vector->insert( i, n->data );
n = n->next;
i++;
}
}
void QGList::heapSortPushDown( QPtrCollection::Item* heap, int first, int last )
{
int r = first;
while( r <= last/2 ) {
// Node r has only one child ?
if ( last == 2*r ) {
// Need for swapping ?
if ( compareItems( heap[r], heap[ 2*r ] ) > 0 ) {
QPtrCollection::Item tmp = heap[r];
heap[ r ] = heap[ 2*r ];
heap[ 2*r ] = tmp;
}
// That's it ...
r = last;
} else {
// Node has two children
if ( compareItems( heap[r], heap[ 2*r ] ) > 0 &&
compareItems( heap[ 2*r ], heap[ 2*r+1 ] ) <= 0 ) {
// Swap with left child
QPtrCollection::Item tmp = heap[r];
heap[ r ] = heap[ 2*r ];
heap[ 2*r ] = tmp;
r *= 2;
} else if ( compareItems( heap[r], heap[ 2*r+1 ] ) > 0 &&
compareItems( heap[ 2*r+1 ], heap[ 2*r ] ) < 0 ) {
// Swap with right child
QPtrCollection::Item tmp = heap[r];
heap[ r ] = heap[ 2*r+1 ];
heap[ 2*r+1 ] = tmp;
r = 2*r+1;
} else {
// We are done
r = last;
}
}
}
}
/*! Sorts the list by the result of the virtual compareItems() function.
The Heap-Sort algorithm is used for sorting. It sorts n items with
O(n*log n) compares. This is the asymptotic optimal solution of the
sorting problem.
*/
void QGList::sort()
{
uint n = count();
if ( n < 2 )
return;
// Create the heap
QPtrCollection::Item* realheap = new QPtrCollection::Item[ n ];
// Wow, what a fake. But I want the heap to be indexed as 1...n
QPtrCollection::Item* heap = realheap - 1;
int size = 0;
QLNode* insert = firstNode;
for( ; insert != 0; insert = insert->next ) {
heap[++size] = insert->data;
int i = size;
while( i > 1 && compareItems( heap[i], heap[ i / 2 ] ) < 0 ) {
QPtrCollection::Item tmp = heap[ i ];
heap[ i ] = heap[ i/2 ];
heap[ i/2 ] = tmp;
i /= 2;
}
}
insert = firstNode;
// Now do the sorting
for ( int i = n; i > 0; i-- ) {
insert->data = heap[1];
insert = insert->next;
if ( i > 1 ) {
heap[1] = heap[i];
heapSortPushDown( heap, 1, i - 1 );
}
}
delete [] realheap;
}
/*****************************************************************************
QGList stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
QDataStream &operator>>( QDataStream &s, QGList &list )
{ // read list
return list.read( s );
}
QDataStream &operator<<( QDataStream &s, const QGList &list )
{ // write list
return list.write( s );
}
/*!
Reads a list from the stream \a s.
*/
QDataStream &QGList::read( QDataStream &s )
{
uint num;
s >> num; // read number of items
clear(); // clear list
while ( num-- ) { // read all items
Item d;
read( s, d );
Q_CHECK_PTR( d );
if ( !d ) // no memory
break;
QLNode *n = new QLNode( d );
Q_CHECK_PTR( n );
if ( !n ) // no memory
break;
n->next = 0;
if ( (n->prev = lastNode) ) // list is not empty
lastNode->next = n;
else // initialize list
firstNode = n;
lastNode = n;
numNodes++;
}
curNode = firstNode;
curIndex = curNode ? 0 : -1;
return s;
}
/*!
Writes the list to the stream \a s.
*/
QDataStream &QGList::write( QDataStream &s ) const
{
s << count(); // write number of items
QLNode *n = firstNode;
while ( n ) { // write all items
write( s, n->data );
n = n->next;
}
return s;
}
#endif // QT_NO_DATASTREAM
/*****************************************************************************
QGListIterator member functions
*****************************************************************************/
/*!
\class QGListIterator qglist.h
\reentrant
\ingroup collection
\brief The QGListIterator class is an internal class for implementing QPtrListIterator.
\internal
QGListIterator is a strictly internal class that does the heavy work for
QPtrListIterator.
*/
/*!
\internal
Constructs an iterator that operates on the list \a l.
*/
QGListIterator::QGListIterator( const QGList &l )
{
list = (QGList *)&l; // get reference to list
curNode = list->firstNode; // set to first node
if ( !list->iterators ) {
list->iterators = new QGListIteratorList; // create iterator list
Q_CHECK_PTR( list->iterators );
}
list->iterators->add( this ); // attach iterator to list
}
/*!
\internal
Constructs a copy of the iterator \a it.
*/
QGListIterator::QGListIterator( const QGListIterator &it )
{
list = it.list;
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
@@ -1,835 +1,868 @@
/****************************************************************************
** $Id$
**
** Global functions
**
** Created : 920604
**
** 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"
#include "qasciidict.h"
#include <limits.h>
#include <stdio.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
/*!
\relates QApplication
Returns the Qt version number as a string, for example, "2.3.0" or
"3.0.5".
The \c QT_VERSION define has the numeric value in the form:
0xmmiibb (m = major, i = minor, b = bugfix). For example, Qt
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
vsprintf( buf, msg, ap );
#endif
va_end( ap );
(*handler)( QtWarningMsg, 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
}
}
// again, copied
void warning( 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)( QtWarningMsg, 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 qFatal( 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)( QtFatalMsg, 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
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
abort(); // trap; generates core dump
#else
exit( 1 ); // goodbye cruel world
#endif
}
}
// yet again, copied
void fatal( 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)( QtFatalMsg, 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
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
abort(); // trap; generates core dump
#else
exit( 1 ); // goodbye cruel world
#endif
}
}
/*!
\relates QApplication
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,
warnings and fatal error messages. The Qt library (debug version)
contains hundreds of warning messages that are printed when
internal errors (usually invalid function arguments) occur. If you
implement your own message handler, you get total control of these
messages.
The default message handler prints the message to the standard
output under X11 or to the debugger under Windows. If it is a
fatal message, the application aborts immediately.
Only one message handler can be defined, since this is usually
done on an application-wide basis to control debug output.
To restore the message handler, call \c qInstallMsgHandler(0).
Example:
\code
#include <qapplication.h>
#include <stdio.h>
#include <stdlib.h>
void myMessageOutput( QtMsgType type, const char *msg )
{
switch ( type ) {
case QtDebugMsg:
fprintf( stderr, "Debug: %s\n", msg );
break;
case QtWarningMsg:
fprintf( stderr, "Warning: %s\n", msg );
break;
case QtFatalMsg:
fprintf( stderr, "Fatal: %s\n", msg );
abort(); // deliberately core dump
}
}
int main( int argc, char **argv )
{
qInstallMsgHandler( myMessageOutput );
QApplication a( argc, argv );
...
return a.exec();
}
\endcode
\sa qDebug(), qWarning(), qFatal(), \link debug.html Debugging\endlink
*/
QtMsgHandler qInstallMsgHandler( QtMsgHandler h )
{
QtMsgHandler old = handler;
handler = h;
return old;
}
/*
Dijkstra's bisection algorithm to find the square root as an integer.
Deliberately not exported as part of the Qt API, but used in both
qsimplerichtext.cpp and qgfxraster_qws.cpp
*/
unsigned int qt_int_sqrt( unsigned int n )
{
// n must be in the range 0...UINT_MAX/2-1
if ( n >= ( UINT_MAX>>2 ) ) {
unsigned int r = 2 * qt_int_sqrt( n / 4 );
unsigned int r2 = r + 1;
return ( n >= r2 * r2 ) ? r2 : r;
}
uint h, p= 0, q= 1, r= n;
while ( q <= n )
q <<= 2;
while ( q != 1 ) {
q >>= 2;
h= p + q;
p >>= 1;
if ( r >= h ) {
p += q;
r -= h;
}
}
return p;
}
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,544 +1,544 @@
/****************************************************************************
** $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
};
/*
The entry bitCount[i] (for i between 0 and 255) is the number of
bits used to represent i in binary.
*/
static const char bitCount[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
class QCoMatrix
{
public:
/*
The matrix has 20 * 20 = 400 entries. This requires 50 bytes, or
13 words. Some operations are performed on words for more
efficiency.
*/
union {
Q_UINT8 b[52];
Q_UINT32 w[13];
};
QCoMatrix() { memset( b, 0, 52 ); }
QCoMatrix( const char *text ) {
char c = '\0', d;
memset( b, 0, 52 );
while ( (d = *text) != '\0' ) {
setCoocc( c, d );
if ( (c = *++text) != '\0' ) {
setCoocc( d, c );
text++;
}
}
}
void setCoocc( char c, char d ) {
int k = indexOf[(uchar) c] + 20 * indexOf[(uchar) d];
b[k >> 3] |= k & 0x7;
}
int worth() const {
int result = 0;
for ( int i = 0; i < 50; i++ )
result += bitCount[b[i]];
return result;
}
static QCoMatrix reunion( const QCoMatrix& m, const QCoMatrix& n )
{
QCoMatrix p;
for ( int i = 0; i < 13; i++ )
p.w[i] = m.w[i] | n.w[i];
return p;
}
static QCoMatrix intersection( const QCoMatrix& m, const QCoMatrix& n )
{
QCoMatrix p;
for ( int i = 0; i < 13; i++ )
p.w[i] = m.w[i] & n.w[i];
return p;
}
};
/*
Returns an integer between 0 (dissimilar) and 15 (very similar)
depending on how similar the string is to \a target.
This function is efficient, but its results might change in future
versions of Qt as the algorithm evolves.
\code
QString s( "color" );
a = similarity( s, "color" ); // a == 15
a = similarity( s, "colour" ); // a == 8
a = similarity( s, "flavor" ); // a == 4
a = similarity( s, "dahlia" ); // a == 0
\endcode
*/
static int similarity( const QString& s1, const QString& s2 )
{
QCoMatrix m1( s1 );
QCoMatrix m2( s2 );
return ( 15 * (QCoMatrix::intersection(m1, m2).worth() + 1) ) /
( QCoMatrix::reunion(m1, m2).worth() + 1 );
}
/*!
\class QPluginManager qpluginmanager.h
\reentrant
\brief The QPluginManager class provides basic functions to access a certain kind of functionality in libraries.
\ingroup componentmodel
\internal
A common usage of components is to extend the existing functionality in an application using plugins. The application
defines interfaces that abstract a certain group of functionality, and a plugin provides a specialized implementation
of one or more of those interfaces.
The QPluginManager template has to be instantiated with an interface definition and the IID for this interface.
\code
QPluginManager<MyPluginInterface> *manager = new QPluginManager<MyPluginInterface>( IID_MyPluginInterface );
\endcode
It searches a specified directory for all shared libraries, queries for components that implement the specific interface and
reads information about the features the plugin wants to add to the application. The component can provide the set of features
provided by implementing either the QFeatureListInterface or the QComponentInformationInterface. The strings returned by the implementations
of
\code
QStringList QFeatureListInterface::featureList() const
\endcode
or
\code
QString QComponentInformationInterface::name() const
\endcode
respectively, can then be used to access the component that provides the requested feature:
\code
MyPluginInterface *iface;
manager->queryInterface( "feature", &iface );
if ( iface )
iface->execute( "feature" );
\endcode
The application can use a QPluginManager instance to create parts of the user interface based on the list of features
found in plugins:
\code
QPluginManager<MyPluginInterface> *manager = new QPluginManager<MyPluginInterface>( IID_ImageFilterInterface );
manager->addLibraryPath(...);
QStringList features = manager->featureList();
for ( QStringList::Iterator it = features.begin(); it != features.end(); ++it ) {
MyPluginInterface *iface;
manager->queryInterface( *it, &iface );
// use QAction to provide toolbuttons and menuitems for each feature...
}
\endcode
*/
/*!
\fn QPluginManager::QPluginManager( const QUuid& id, const QStringList& paths = QString::null, const QString &suffix = QString::null, bool cs = TRUE )
Creates an QPluginManager for interfaces \a id that will load all shared library files in the \a paths + \a suffix.
If \a cs is FALSE the manager will handle feature strings case insensitive.
\warning
Setting the cs flag to FALSE requires that components also convert to lower case when comparing with passed strings, so this has
to be handled with care and documented very well.
\sa QApplication::libraryPaths()
*/
/*!
\fn QRESULT QPluginManager::queryInterface(const QString& feature, Type** iface) const
Sets \a iface to point to the interface providing \a feature.
\sa featureList(), library()
*/
#include <qptrlist.h>
QGPluginManager::QGPluginManager( const QUuid& id, const QStringList& paths, const QString &suffix, bool cs )
: interfaceId( id ), plugDict( 17, cs ), casesens( cs ), autounload( TRUE )
{
// Every QLibrary object is destroyed on destruction of the manager
libDict.setAutoDelete( TRUE );
for ( QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it ) {
QString path = *it;
addLibraryPath( path + suffix );
}
}
QGPluginManager::~QGPluginManager()
{
if ( !autounload ) {
QDictIterator<QLibrary> it( libDict );
while ( it.current() ) {
QLibrary *lib = it.current();
++it;
lib->setAutoUnload( FALSE );
}
}
}
void QGPluginManager::addLibraryPath( const QString& path )
{
if ( !enabled() || !QDir( path ).exists( ".", TRUE ) )
return;
#if defined(Q_OS_WIN32)
QString filter = "dll";
#elif defined(Q_OS_MACX)
QString filter = "dylib";
#elif defined(Q_OS_UNIX)
QString filter = "so";
#endif
QStringList plugins = QDir(path).entryList( "*." + filter );
for ( QStringList::Iterator p = plugins.begin(); p != plugins.end(); ++p ) {
QString lib = QDir::cleanDirPath( path + "/" + *p );
if ( libList.contains( lib ) )
continue;
libList.append( lib );
}
}
const QLibrary* QGPluginManager::library( const QString& feature ) const
{
if ( !enabled() || feature.isEmpty() )
return 0;
// We already have a QLibrary object for this feature
QLibrary *library = 0;
if ( ( library = plugDict[feature] ) )
return library;
// Find the filename that matches the feature request best
QMap<int, QStringList> map;
QStringList::ConstIterator it = libList.begin();
int best = 0;
int worst = 15;
while ( it != libList.end() ) {
if ( (*it).isEmpty() || libDict[*it] ) {
++it;
continue;
}
QString basename = QFileInfo(*it).baseName();
int s = similarity( feature, basename );
if ( s < worst )
worst = s;
if ( s > best )
best = s;
map[s].append( basename + QChar(0xfffd) + *it );
++it;
}
if ( map.isEmpty() )
return 0; // no libraries to add
// Start with the best match to get the library object
QGPluginManager *that = (QGPluginManager*)this;
for ( int s = best; s >= worst; --s ) {
QStringList group = map[s];
group.sort(); // sort according to the base name
QStringList::ConstIterator git = group.begin();
while ( git != group.end() ) {
QString lib = (*git).mid( (*git).find( QChar(0xfffd) ) + 1 );
QString basename = (*git).left( (*git).find( QChar(0xfffd) ) );
++git;
QStringList sameBasename;
while( git != group.end() &&
basename == (*git).left( (*git).find( QChar(0xfffd) ) ) ) {
sameBasename << (*git).mid( (*git).find( QChar(0xfffd) ) + 1 );
++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,584 +1,591 @@
/****************************************************************************
** $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;
}
/*!
Writes a collection/vector item to the stream \a s and returns a reference
to the stream.
The default implementation does nothing.
\sa read()
*/
QDataStream &QGVector::write( QDataStream &s, Item ) const
{ // write item to stream
return s;
}
#endif // QT_NO_DATASTREAM
/*****************************************************************************
QGVector member functions
*****************************************************************************/
QGVector::QGVector() // create empty vector
{
vec = 0;
len = numItems = 0;
}
QGVector::QGVector( uint size ) // create vectors with nullptrs
{
len = size;
numItems = 0;
if ( len == 0 ) { // zero length
vec = 0;
return;
}
vec = NEW(Item,len);
Q_CHECK_PTR( vec );
memset( (void*)vec, 0, len*sizeof(Item) ); // fill with nulls
}
QGVector::QGVector( const QGVector &a ) // make copy of other vector
: QPtrCollection( a )
{
len = a.len;
numItems = a.numItems;
if ( len == 0 ) {
vec = 0;
return;
}
vec = NEW( Item, len );
Q_CHECK_PTR( vec );
for ( uint i = 0; i < len; i++ ) {
if ( a.vec[i] ) {
vec[i] = newItem( a.vec[i] );
Q_CHECK_PTR( vec[i] );
} else {
vec[i] = 0;
}
}
}
QGVector::~QGVector()
{
clear();
}
QGVector& QGVector::operator=( const QGVector &v )
{
if ( &v == this )
return *this;
clear();
len = v.len;
numItems = v.numItems;
if ( len == 0 ) {
vec = 0;
return *this;
}
vec = NEW( Item, len );
Q_CHECK_PTR( vec );
for ( uint i = 0; i < len; i++ ) {
if ( v.vec[i] ) {
vec[i] = newItem( v.vec[i] );
Q_CHECK_PTR( vec[i] );
} else {
vec[i] = 0;
}
}
return *this;
}
bool QGVector::insert( uint index, Item d ) // insert item at index
{
#if defined(QT_CHECK_RANGE)
if ( index >= len ) { // range error
qWarning( "QGVector::insert: Index %d out of range", index );
return FALSE;
}
#endif
if ( vec[index] ) { // remove old item
deleteItem( vec[index] );
numItems--;
}
if ( d ) {
vec[index] = newItem( d );
Q_CHECK_PTR( vec[index] );
numItems++;
return vec[index] != 0;
} else {
vec[index] = 0; // reset item
}
return TRUE;
}
bool QGVector::remove( uint index ) // remove item at index
{
#if defined(QT_CHECK_RANGE)
if ( index >= len ) { // range error
qWarning( "QGVector::remove: Index %d out of range", index );
return FALSE;
}
#endif
if ( vec[index] ) { // valid item
deleteItem( vec[index] ); // delete it
vec[index] = 0; // reset pointer
numItems--;
}
return TRUE;
}
QPtrCollection::Item QGVector::take( uint index ) // take out item
{
#if defined(QT_CHECK_RANGE)
if ( index >= len ) { // range error
qWarning( "QGVector::take: Index %d out of range", index );
return 0;
}
#endif
Item d = vec[index]; // don't delete item
if ( d )
numItems--;
vec[index] = 0;
return d;
}
void QGVector::clear() // clear vector
{
if ( vec ) {
for ( uint i=0; i<len; i++ ) { // delete each item
if ( vec[i] )
deleteItem( vec[i] );
}
DELETE(vec);
vec = 0;
len = numItems = 0;
}
}
bool QGVector::resize( uint newsize ) // resize array
{
if ( newsize == len ) // nothing to do
return TRUE;
if ( vec ) { // existing data
if ( newsize < len ) { // shrink vector
uint i = newsize;
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++;
}
return count;
}
bool QGVector::insertExpand( uint index, Item d )// insert and grow if necessary
{
if ( index >= len ) {
if ( !resize( index+1 ) ) // no memory
return FALSE;
}
insert( index, d );
return TRUE;
}
void QGVector::toList( QGList *list ) const // store items in list
{
list->clear();
for ( uint i=0; i<len; i++ ) {
if ( vec[i] )
list->append( vec[i] );
}
}
void QGVector::warningIndexRange( uint i )
{
#if defined(QT_CHECK_RANGE)
qWarning( "QGVector::operator[]: Index %d out of range", i );
#else
Q_UNUSED( i )
#endif
}
/*****************************************************************************
QGVector stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
QDataStream &operator>>( QDataStream &s, QGVector &vec )
{ // read vector
return vec.read( s );
}
QDataStream &operator<<( QDataStream &s, const QGVector &vec )
{ // write vector
return vec.write( s );
}
QDataStream &QGVector::read( QDataStream &s ) // read vector from stream
{
uint num;
s >> num; // read number of items
clear(); // clear vector
resize( num );
for (uint i=0; i<num; i++) { // read all items
Item d;
read( s, d );
Q_CHECK_PTR( d );
if ( !d ) // no memory
break;
vec[i] = d;
}
return s;
}
QDataStream &QGVector::write( QDataStream &s ) const
{ // write vector to stream
uint num = count();
s << num; // number of items to write
num = size();
for (uint i=0; i<num; i++) { // write non-null items
if ( vec[i] )
write( s, vec[i] );
}
return s;
}
/* Returns whether v equals this vector or not */
bool QGVector::operator==( const QGVector &v ) const
{
if ( size() != v.size() )
return FALSE;
if ( count() != v.count() )
return FALSE;
for ( int i = 0; i < (int)size(); ++i ) {
if ( ( (QGVector*)this )->compareItems( at( i ), v.at( i ) ) != 0 )
return FALSE;
}
return TRUE;
}
#endif // QT_NO_DATASTREAM
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,343 +1,344 @@
/****************************************************************************
** $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 )
return avg( 5, 8 );
else
return -1;
\endcode
*/
void *QLibrary::resolve( const char* symb )
{
if ( !d->pHnd )
load();
if ( !d->pHnd )
return 0;
void *address = d->resolveSymbol( symb );
return address;
}
/*!
\overload
Loads the library \a filename and returns the address of the
exported symbol \a symb. Note that like the constructor, \a
filename does not need to include the (platform specific) file
extension. The library remains loaded until the process exits.
The function returns 0 if the symbol could not be resolved or the
library could not be loaded.
This function is useful only if you want to resolve a single
symbol, e.g. a function pointer from a specific library once:
\code
typedef void (*FunctionType)();
static FunctionType *ptrFunction = 0;
static bool triedResolve = FALSE;
if ( !ptrFunction && !triedResolve )
ptrFunction = QLibrary::resolve( "mylib", "mysymb" );
if ( ptrFunction )
ptrFunction();
else
...
\endcode
If you want to resolve multiple symbols, use a QLibrary object and
call the non-static version of resolve().
\sa resolve()
*/
void *QLibrary::resolve( const QString &filename, const char *symb )
{
QLibrary lib( filename );
lib.setAutoUnload( FALSE );
return lib.resolve( symb );
}
/*!
Returns TRUE if the library is loaded; otherwise returns FALSE.
\sa unload()
*/
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,163 +1,180 @@
/****************************************************************************
** $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
#if defined(QT_DEBUG_COMPONENT)
const char* error = dlerror();
if ( error )
qWarning( "%s", error );
#endif
return address;
}
#endif // POSIX
#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,687 +1,689 @@
/****************************************************************************
** $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)
+ 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
if (ret)
qWarning("Mutex lock failure: %s", strerror(ret));
#endif
}
void QRealMutexPrivate::unlock()
{
int ret = pthread_mutex_unlock(&handle);
#ifdef QT_CHECK_RANGE
if (ret)
qWarning("Mutex unlock failure: %s", strerror(ret));
#endif
}
bool QRealMutexPrivate::locked()
{
int ret = pthread_mutex_trylock(&handle);
if (ret == EBUSY) {
return TRUE;
} else if (ret) {
#ifdef QT_CHECK_RANGE
qWarning("Mutex locktest failure: %s", strerror(ret));
#endif
} else
pthread_mutex_unlock(&handle);
return FALSE;
}
bool QRealMutexPrivate::trylock()
{
int ret = pthread_mutex_trylock(&handle);
if (ret == EBUSY) {
return FALSE;
} else if (ret) {
#ifdef QT_CHECK_RANGE
qWarning("Mutex trylock failure: %s", strerror(ret));
#endif
return FALSE;
}
return TRUE;
}
int QRealMutexPrivate::type() const
{
return recursive ? Q_MUTEX_RECURSIVE : Q_MUTEX_NORMAL;
}
#ifndef Q_RECURSIVE_MUTEX_TYPE
QRecursiveMutexPrivate::QRecursiveMutexPrivate()
: count(0), owner(0)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
Q_MUTEX_SET_TYPE(&attr, Q_NORMAL_MUTEX_TYPE);
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
pthread_mutexattr_init(&attr);
ret = pthread_mutex_init( &handle2, &attr );
pthread_mutexattr_destroy(&attr);
# ifdef QT_CHECK_RANGE
if (ret)
qWarning( "Mutex init failure: %s", strerror(ret) );
# endif
}
QRecursiveMutexPrivate::~QRecursiveMutexPrivate()
{
int ret = pthread_mutex_destroy(&handle2);
# ifdef QT_CHECK_RANGE
if (ret)
qWarning( "Mutex destroy failure: %s", strerror(ret) );
# endif
}
void QRecursiveMutexPrivate::lock()
{
pthread_mutex_lock(&handle2);
if (count > 0 && owner == (unsigned long) pthread_self()) {
count++;
} else {
pthread_mutex_unlock(&handle2);
pthread_mutex_lock(&handle);
pthread_mutex_lock(&handle2);
count = 1;
owner = (unsigned long) pthread_self();
}
pthread_mutex_unlock(&handle2);
}
void QRecursiveMutexPrivate::unlock()
{
pthread_mutex_lock(&handle2);
if (owner == (unsigned long) pthread_self()) {
// do nothing if the count is already 0... to reflect the behaviour described
// in the docs
if (count && (--count) < 1) {
count = 0;
pthread_mutex_unlock(&handle);
}
} else {
#ifdef QT_CHECK_RANGE
qWarning("QMutex::unlock: unlock from different thread than locker");
qWarning(" was locked by %d, unlock attempt from %d",
(int)owner, (int)pthread_self());
#endif
}
pthread_mutex_unlock(&handle2);
}
bool QRecursiveMutexPrivate::locked()
{
pthread_mutex_lock(&handle2);
bool ret;
int code = pthread_mutex_trylock(&handle);
if (code == EBUSY) {
ret = TRUE;
} else {
#ifdef QT_CHECK_RANGE
if (code)
qWarning("Mutex trylock failure: %s", strerror(code));
#endif
pthread_mutex_unlock(&handle);
ret = FALSE;
}
pthread_mutex_unlock(&handle2);
return ret;
}
bool QRecursiveMutexPrivate::trylock()
{
bool ret = TRUE;
pthread_mutex_lock(&handle2);
if ( count > 0 && owner == (unsigned long) pthread_self() ) {
count++;
} else {
int code = pthread_mutex_trylock(&handle);
if (code == EBUSY) {
ret = FALSE;
} else if (code) {
#ifdef QT_CHECK_RANGE
qWarning("Mutex trylock failure: %s", strerror(code));
#endif
ret = FALSE;
} else {
count = 1;
owner = (unsigned long) pthread_self();
}
}
pthread_mutex_unlock(&handle2);
return ret;
}
int QRecursiveMutexPrivate::type() const
{
return Q_MUTEX_RECURSIVE;
}
#endif // !Q_RECURSIVE_MUTEX_TYPE
/*!
\class QMutex qmutex.h
\threadsafe
\brief The QMutex class provides access serialization between threads.
\ingroup thread
\ingroup environment
The purpose of a QMutex is to protect an object, data structure or
section of code so that only one thread can access it at a time
(This is similar to the Java \c synchronized keyword). For
example, say there is a method which prints a message to the user
on two lines:
\code
int number = 6;
void method1()
{
number *= 5;
number /= 4;
}
void method1()
{
number *= 3;
number /= 2;
}
\endcode
If these two methods are called in succession, the following happens:
\code
// method1()
number *= 5; // number is now 30
number /= 4; // number is now 7
// method2()
number *= 3; // nubmer is now 21
number /= 2; // number is now 10
\endcode
If these two methods are called simultaneously from two threads then the
following sequence could result:
\code
// Thread 1 calls method1()
number *= 5; // number is now 30
// Thread 2 calls method2().
//
// Most likely Thread 1 has been put to sleep by the operating
// system to allow Thread 2 to run.
number *= 3; // number is now 90
number /= 2; // number is now 45
// Thread 1 finishes executing.
number /= 4; // number is now 11, instead of 10
\endcode
If we add a mutex, we should get the result we want:
\code
QMutex mutex;
int number = 6;
void method1()
{
mutex.lock();
number *= 5;
number /= 4;
mutex.unlock();
}
void method2()
{
mutex.lock();
number *= 3;
number /= 2;
mutex.unlock();
}
\endcode
Then only one thread can modify \c number at any given time and
the result is correct. This is a trivial example, of course, but
applies to any other case where things need to happen in a
particular sequence.
When you call lock() in a thread, other threads that try to call
lock() in the same place will block until the thread that got the
lock calls unlock(). A non-blocking alternative to lock() is
tryLock().
*/
/*!
Constructs a new mutex. The mutex is created in an unlocked state.
A recursive mutex is created if \a recursive is TRUE; a normal
mutex is created if \a recursive is FALSE (the default). With a
recursive mutex, a thread can lock the same mutex multiple times
and it will not be unlocked until a corresponding number of
unlock() calls have been made.
*/
QMutex::QMutex(bool recursive)
{
#ifndef Q_RECURSIVE_MUTEX_TYPE
if ( recursive )
d = new QRecursiveMutexPrivate();
else
#endif // !Q_RECURSIVE_MUTEX_TYPE
d = new QRealMutexPrivate(recursive);
}
/*!
Destroys the mutex.
\warning If you destroy a mutex that still holds a lock the
resultant behavior is undefined.
*/
QMutex::~QMutex()
{
delete d;
}
/*!
Attempt to lock the mutex. If another thread has locked the mutex
then this call will \e block until that thread has unlocked it.
\sa unlock(), locked()
*/
void QMutex::lock()
{
d->lock();
}
/*!
Unlocks the mutex. Attempting to unlock a mutex in a different
thread to the one that locked it results in an error. Unlocking a
mutex that is not locked results in undefined behaviour (varies
between different Operating Systems' thread implementations).
\sa lock(), locked()
*/
void QMutex::unlock()
{
d->unlock();
}
/*!
Returns TRUE if the mutex is locked by another thread; otherwise
returns FALSE.
\warning Due to differing implementations of recursive mutexes on
various platforms, calling this function from the same thread that
previously locked the mutex will return undefined results.
\sa lock(), unlock()
*/
bool QMutex::locked()
{
return d->locked();
}
/*!
Attempt to lock the mutex. If the lock was obtained, this function
returns TRUE. If another thread has locked the mutex, this
function returns FALSE, instead of waiting for the mutex to become
available, i.e. it does not block.
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
\sa lock(), unlock(), locked()
*/
bool QMutex::tryLock()
{
return d->trylock();
}
/*!
\class QMutexLocker qmutex.h
\brief The QMutexLocker class simplifies locking and unlocking QMutexes.
\threadsafe
\ingroup thread
\ingroup environment
The purpose of QMutexLocker is to simplify QMutex locking and
unlocking. Locking and unlocking a QMutex in complex functions and
statements or in exception handling code is error prone and
difficult to debug. QMutexLocker should be used in such situations
to ensure that the state of the mutex is well defined and always
locked and unlocked properly.
QMutexLocker should be created within a function where a QMutex
needs to be locked. The mutex is locked when QMutexLocker is
created, and unlocked when QMutexLocker is destroyed.
For example, this complex function locks a QMutex upon entering
the function and unlocks the mutex at all the exit points:
\code
int complexFunction( int flag )
{
mutex.lock();
int return_value = 0;
switch ( flag ) {
case 0:
case 1:
{
mutex.unlock();
return moreComplexFunction( flag );
}
case 2:
{
int status = anotherFunction();
if ( status < 0 ) {
mutex.unlock();
return -2;
}
return_value = status + flag;
break;
}
default:
{
if ( flag > 10 ) {
mutex.unlock();
return -1;
}
break;
}
}
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
@@ -1,3935 +1,3943 @@
/****************************************************************************
** $Id$
**
** Implementation of QRegExp class
**
** Created : 950126
**
** 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 "qregexp.h"
#ifndef QT_NO_REGEXP
#include "qmemarray.h"
#include "qbitarray.h"
#include "qcache.h"
#include "qcleanuphandler.h"
#include "qintdict.h"
#include "qmap.h"
#include "qptrvector.h"
#include "qstring.h"
#include "qtl.h"
#ifdef QT_THREAD_SUPPORT
#include "qmutexpool_p.h"
#endif // QT_THREAD_SUPPORT
#undef QT_TRANSLATE_NOOP
#define QT_TRANSLATE_NOOP( context, sourceText ) sourceText
#include <limits.h>
// error strings for the regexp parser
#define RXERR_OK QT_TRANSLATE_NOOP( "QRegExp", "no error occurred" )
#define RXERR_DISABLED QT_TRANSLATE_NOOP( "QRegExp", "disabled feature used" )
#define RXERR_CHARCLASS QT_TRANSLATE_NOOP( "QRegExp", "bad char class syntax" )
#define RXERR_LOOKAHEAD QT_TRANSLATE_NOOP( "QRegExp", "bad lookahead syntax" )
#define RXERR_REPETITION QT_TRANSLATE_NOOP( "QRegExp", "bad repetition syntax" )
#define RXERR_OCTAL QT_TRANSLATE_NOOP( "QRegExp", "invalid octal value" )
#define RXERR_LEFTDELIM QT_TRANSLATE_NOOP( "QRegExp", "missing left delim" )
#define RXERR_END QT_TRANSLATE_NOOP( "QRegExp", "unexpected end" )
#define RXERR_LIMIT QT_TRANSLATE_NOOP( "QRegExp", "met internal limit" )
/*
WARNING! Be sure to read qregexp.tex before modifying this file.
*/
/*!
\class QRegExp qregexp.h
\reentrant
\brief The QRegExp class provides pattern matching using regular expressions.
\ingroup tools
\ingroup misc
\ingroup shared
\mainclass
\keyword regular expression
Regular expressions, or "regexps", provide a way to find patterns
within text. This is useful in many contexts, for example:
\table
\row \i Validation
\i A regexp can be used to check whether a piece of text
meets some criteria, e.g. is an integer or contains no
whitespace.
\row \i Searching
\i Regexps provide a much more powerful means of searching
text than simple string matching does. For example we can
create a regexp which says "find one of the words 'mail',
'letter' or 'correspondence' but not any of the words
'email', 'mailman' 'mailer', 'letterbox' etc."
\row \i Search and Replace
\i A regexp can be used to replace a pattern with a piece of
text, for example replace all occurrences of '&' with
'\&amp;' except where the '&' is already followed by 'amp;'.
\row \i String Splitting
\i A regexp can be used to identify where a string should be
split into its component fields, e.g. splitting tab-delimited
strings.
\endtable
We present a very brief introduction to regexps, a description of
Qt's regexp language, some code examples, and finally the function
documentation itself. QRegExp is modeled on Perl's regexp
language, and also fully supports Unicode. QRegExp can also be
used in the weaker 'wildcard' (globbing) mode which works in a
similar way to command shells. A good text on regexps is \e
{Mastering Regular Expressions: Powerful Techniques for Perl and
Other Tools} by Jeffrey E. Friedl, ISBN 1565922573.
Experienced regexp users may prefer to skip the introduction and
go directly to the relevant information.
\tableofcontents
\section1 Introduction
Regexps are built up from expressions, quantifiers, and assertions.
The simplest form of expression is simply a character, e.g.
<b>x</b> or <b>5</b>. An expression can also be a set of
characters. For example, <b>[ABCD]</b>, will match an <b>A</b> or
a <b>B</b> or a <b>C</b> or a <b>D</b>. As a shorthand we could
write this as <b>[A-D]</b>. If we want to match any of the
captital letters in the English alphabet we can write
<b>[A-Z]</b>. A quantifier tells the regexp engine how many
occurrences of the expression we want, e.g. <b>x{1,1}</b> means
match an <b>x</b> which occurs at least once and at most once.
We'll look at assertions and more complex expressions later.
Note that in general regexps cannot be used to check for balanced
brackets or tags. For example if you want to match an opening html
\c <b> and its closing \c </b> you can only use a regexp if you
know that these tags are not nested; the html fragment, \c{<b>bold
<b>bolder</b></b>} will not match as expected. If you know the
maximum level of nesting it is possible to create a regexp that
will match correctly, but for an unknown level of nesting, regexps
will fail.
We'll start by writing a regexp to match integers in the range 0
to 99. We will require at least one digit so we will start with
<b>[0-9]{1,1}</b> which means match a digit exactly once. This
regexp alone will match integers in the range 0 to 9. To match one
or two digits we can increase the maximum number of occurrences so
the regexp becomes <b>[0-9]{1,2}</b> meaning match a digit at
least once and at most twice. However, this regexp as it stands
will not match correctly. This regexp will match one or two digits
\e within a string. To ensure that we match against the whole
string we must use the anchor assertions. We need <b>^</b> (caret)
which when it is the first character in the regexp means that the
regexp must match from the beginning of the string. And we also
need <b>$</b> (dollar) which when it is the last character in the
regexp means that the regexp must match until the end of the
string. So now our regexp is <b>^[0-9]{1,2}$</b>. Note that
assertions, such as <b>^</b> and <b>$</b>, do not match any
characters.
If you've seen regexps elsewhere they may have looked different from
the ones above. This is because some sets of characters and some
quantifiers are so common that they have special symbols to
represent them. <b>[0-9]</b> can be replaced with the symbol
<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 '\&amp;'. 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
1024.)
If we wish to apply a quantifier to more than just the preceding
character we can use parentheses to group characters together in
an expression. For example, <b>tag+</b> matches a 't' followed by
an 'a' followed by at least one 'g', whereas <b>(tag)+</b> matches
at least one occurrence of 'tag'.
Note that quantifiers are "greedy". They will match as much text
as they can. For example, <b>0+</b> will match as many zeros as it
can from the first zero it finds, e.g. '2.<u>000</u>5'.
Quantifiers can be made non-greedy, see setMinimal().
\target capturing-text
\section1 Capturing Text
Parentheses allow us to group elements together so that we can
quantify and capture them. For example if we have the expression
<b>mail|letter|correspondence</b> that matches a string we know
that \e one of the words matched but not which one. Using
parentheses allows us to "capture" whatever is matched within
their bounds, so if we used <b>(mail|letter|correspondence)</b>
and matched this regexp against the string "I sent you some email"
we can use the cap() or capturedTexts() functions to extract the
matched characters, in this case 'mail'.
We can use captured text within the regexp itself. To refer to the
captured text we use \e backreferences which are indexed from 1,
the same as for cap(). For example we could search for duplicate
words in a string using <b>\b(\w+)\W+\1\b</b> which means match a
word boundary followed by one or more word characters followed by
one or more non-word characters followed by the same text as the
first parenthesised expression followed by a word boundary.
If we want to use parentheses purely for grouping and not for
capturing we can use the non-capturing syntax, e.g.
<b>(?:green|blue)</b>. Non-capturing parentheses begin '(?:' and
end ')'. In this example we match either 'green' or 'blue' but we
do not capture the match so we only know whether or not we matched
but not which color we actually found. Using non-capturing
parentheses is more efficient than using capturing parentheses
since the regexp engine has to do less book-keeping.
Both capturing and non-capturing parentheses may be nested.
\target assertions
\section1 Assertions
Assertions make some statement about the text at the point where
they occur in the regexp but they do not match any characters. In
the following list <b>\e {E}</b> stands for any expression.
\table
\row \i <b>^</b>
\i The caret signifies the beginning of the string. If you
wish to match a literal \c{^} you must escape it by
writing \c{\\^}. For example, <b>^#include</b> will only
match strings which \e begin with the characters '#include'.
(When the caret is the first character of a character set it
has a special meaning, see \link #sets-of-characters Sets of
Characters \endlink.)
\row \i <b>$</b>
\i The dollar signifies the end of the string. For example
<b>\d\s*$</b> will match strings which end with a digit
optionally followed by whitespace. If you wish to match a
literal \c{$} you must escape it by writing
\c{\\$}.
\row \i <b>\\b</b>
\i A word boundary. For example the regexp
<b>\\bOK\\b</b> means match immediately after a word
boundary (e.g. start of string or whitespace) the letter 'O'
then the letter 'K' immediately before another word boundary
(e.g. end of string or whitespace). But note that the
assertion does not actually match any whitespace so if we
write <b>(\\bOK\\b)</b> and we have a match it will only
contain 'OK' even if the string is "Its <u>OK</u> now".
\row \i <b>\\B</b>
\i A non-word boundary. This assertion is true wherever
<b>\\b</b> is false. For example if we searched for
<b>\\Bon\\B</b> in "Left on" the match would fail (space
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 &amp;
QString line1 = "This & that";
line1.replace( rx, "&amp;" );
// line1 == "This &amp; that"
QString line2 = "His &amp; hers & theirs";
line2.replace( rx, "&amp;" );
// line2 == "His &amp; hers &amp; 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)
+ 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( '\\' );
rx += c;
break;
case '[':
rx += c;
if ( wc[i] == QChar('^') )
rx += wc[i++];
if ( i < wclen ) {
if ( rx[i] == ']' )
rx += wc[i++];
while ( i < wclen && wc[i] != QChar(']') ) {
if ( wc[i] == '\\' )
rx += QChar( '\\' );
rx += wc[i++];
}
}
break;
default:
rx += c;
}
}
return rx;
}
#endif
/*
The class QRegExpEngine encapsulates a modified nondeterministic
finite automaton (NFA).
*/
class QRegExpEngine : public QShared
{
public:
#ifndef QT_NO_REGEXP_CCLASS
/*
The class CharClass represents a set of characters, such as can
be found in regular expressions (e.g., [a-z] denotes the set
{a, b, ..., z}).
*/
class CharClass
{
public:
CharClass();
CharClass( const CharClass& cc ) { operator=( cc ); }
CharClass& operator=( const CharClass& cc );
void clear();
bool negative() const { return n; }
void setNegative( bool negative );
void addCategories( int cats );
void addRange( ushort from, ushort to );
void addSingleton( ushort ch ) { addRange( ch, ch ); }
bool in( QChar ch ) const;
#ifndef QT_NO_REGEXP_OPTIM
const QMemArray<int>& firstOccurrence() const { return occ1; }
#endif
#if defined(QT_DEBUG)
void dump() const;
#endif
private:
/*
The struct Range represents a range of characters (e.g.,
[0-9] denotes range 48 to 57).
*/
struct Range
{
ushort from; // 48
ushort to; // 57
};
int c; // character classes
QMemArray<Range> r; // character ranges
bool n; // negative?
#ifndef QT_NO_REGEXP_OPTIM
QMemArray<int> occ1; // first-occurrence array
#endif
};
#else
struct CharClass
{
int dummy;
#ifndef QT_NO_REGEXP_OPTIM
CharClass() { occ1.fill( 0, NumBadChars ); }
const QMemArray<int>& firstOccurrence() const { return occ1; }
QMemArray<int> occ1;
#endif
};
#endif
QRegExpEngine( bool caseSensitive ) { setup( caseSensitive ); }
QRegExpEngine( const QString& rx, bool caseSensitive );
#ifndef QT_NO_REGEXP_OPTIM
~QRegExpEngine();
#endif
bool isValid() const { return valid; }
const QString& errorString() const { return yyError; }
bool caseSensitive() const { return cs; }
int numCaptures() const { return officialncap; }
QMemArray<int> match( const QString& str, int pos, bool minimal,
bool oneTest, int caretIndex );
int matchedLength() const { return mmMatchedLen; }
int createState( QChar ch );
int createState( const CharClass& cc );
#ifndef QT_NO_REGEXP_BACKREF
int createState( int bref );
#endif
void addCatTransitions( const QMemArray<int>& from,
const QMemArray<int>& to );
#ifndef QT_NO_REGEXP_CAPTURE
void addPlusTransitions( const QMemArray<int>& from,
const QMemArray<int>& to, int atom );
#endif
#ifndef QT_NO_REGEXP_ANCHOR_ALT
int anchorAlternation( int a, int b );
int anchorConcatenation( int a, int b );
#else
int anchorAlternation( int a, int b ) { return a & b; }
int anchorConcatenation( int a, int b ) { return a | b; }
#endif
void addAnchors( int from, int to, int a );
#ifndef QT_NO_REGEXP_OPTIM
void setupGoodStringHeuristic( int earlyStart, int lateStart,
const QString& str );
void setupBadCharHeuristic( int minLen, const QMemArray<int>& firstOcc );
void heuristicallyChooseHeuristic();
#endif
#if defined(QT_DEBUG)
void dump() const;
#endif
private:
enum { CharClassBit = 0x10000, BackRefBit = 0x20000 };
/*
The struct State represents one state in a modified NFA. The
input characters matched are stored in the state instead of on
the transitions, something possible for an automaton
constructed from a regular expression.
*/
struct State
{
#ifndef QT_NO_REGEXP_CAPTURE
int atom; // which atom does this state belong to?
#endif
int match; // what does it match? (see CharClassBit and BackRefBit)
QMemArray<int> outs; // out-transitions
QMap<int, int> *reenter; // atoms reentered when transiting out
QMap<int, int> *anchors; // anchors met when transiting out
#ifndef QT_NO_REGEXP_CAPTURE
State( int a, int m )
: atom( a ), match( m ), reenter( 0 ), anchors( 0 ) { }
#else
State( int m )
: match( m ), reenter( 0 ), anchors( 0 ) { }
#endif
~State() { delete reenter; delete anchors; }
};
#ifndef QT_NO_REGEXP_LOOKAHEAD
/*
The struct Lookahead represents a lookahead a la Perl (e.g., (?=foo) and
(?!bar)).
*/
struct Lookahead
{
QRegExpEngine *eng; // NFA representing the embedded regular expression
bool neg; // negative lookahead?
Lookahead( QRegExpEngine *eng0, bool neg0 )
: eng( eng0 ), neg( neg0 ) { }
~Lookahead() { delete eng; }
};
#endif
#ifndef QT_NO_REGEXP_CAPTURE
/*
The struct Atom represents one node in the hierarchy of regular
expression atoms.
*/
struct Atom
{
int parent; // index of parent in array of atoms
int capture; // index of capture, from 1 to ncap
};
#endif
#ifndef QT_NO_REGEXP_ANCHOR_ALT
/*
The struct AnchorAlternation represents a pair of anchors with
OR semantics.
*/
struct AnchorAlternation
{
int a; // this anchor...
int b; // ...or this one
};
#endif
enum { InitialState = 0, FinalState = 1 };
void setup( bool caseSensitive );
int setupState( int match );
/*
Let's hope that 13 lookaheads and 14 back-references are
enough.
*/
enum { MaxLookaheads = 13, MaxBackRefs = 14 };
enum { Anchor_Dollar = 0x00000001, Anchor_Caret = 0x00000002,
Anchor_Word = 0x00000004, Anchor_NonWord = 0x00000008,
Anchor_FirstLookahead = 0x00000010,
Anchor_BackRef1Empty = Anchor_FirstLookahead << MaxLookaheads,
Anchor_BackRef0Empty = Anchor_BackRef1Empty >> 1,
Anchor_Alternation = Anchor_BackRef1Empty << MaxBackRefs,
Anchor_LookaheadMask = ( Anchor_FirstLookahead - 1 ) ^
( (Anchor_FirstLookahead << MaxLookaheads) - 1 ) };
#ifndef QT_NO_REGEXP_CAPTURE
int startAtom( bool capture );
void finishAtom( int atom ) { cf = f[atom].parent; }
#endif
#ifndef QT_NO_REGEXP_LOOKAHEAD
int addLookahead( QRegExpEngine *eng, bool negative );
#endif
#ifndef QT_NO_REGEXP_CAPTURE
bool isBetterCapture( const int *begin1, const int *end1, const int *begin2,
const int *end2 );
#endif
bool testAnchor( int i, int a, const int *capBegin );
#ifndef QT_NO_REGEXP_OPTIM
bool goodStringMatch();
bool badCharMatch();
#else
bool bruteMatch();
#endif
bool matchHere();
QPtrVector<State> s; // array of states
int ns; // number of states
#ifndef QT_NO_REGEXP_CAPTURE
QMemArray<Atom> f; // atom hierarchy
int nf; // number of atoms
int cf; // current atom
#endif
int officialncap; // number of captures, seen from the outside
int ncap; // number of captures, seen from the inside
#ifndef QT_NO_REGEXP_CCLASS
QPtrVector<CharClass> cl; // array of character classes
#endif
#ifndef QT_NO_REGEXP_LOOKAHEAD
QPtrVector<Lookahead> ahead; // array of lookaheads
#endif
#ifndef QT_NO_REGEXP_ANCHOR_ALT
QMemArray<AnchorAlternation> aa; // array of (a, b) pairs of anchors
#endif
#ifndef QT_NO_REGEXP_OPTIM
bool caretAnchored; // does the regexp start with ^?
#endif
bool valid; // is the regular expression valid?
bool cs; // case sensitive?
#ifndef QT_NO_REGEXP_BACKREF
int nbrefs; // number of back-references
#endif
#ifndef QT_NO_REGEXP_OPTIM
bool useGoodStringHeuristic; // use goodStringMatch? otherwise badCharMatch
int goodEarlyStart; // the index where goodStr can first occur in a match
int goodLateStart; // the index where goodStr can last occur in a match
QString goodStr; // the string that any match has to contain
int minl; // the minimum length of a match
QMemArray<int> occ1; // first-occurrence array
#endif
/*
The class Box is an abstraction for a regular expression
fragment. It can also be seen as one node in the syntax tree of
a regular expression with synthetized attributes.
It's interface is ugly for performance reasons.
*/
class Box
{
public:
Box( QRegExpEngine *engine );
Box( const Box& b ) { operator=( b ); }
Box& operator=( const Box& b );
void clear() { operator=(Box(eng)); }
void set( QChar ch );
void set( const CharClass& cc );
#ifndef QT_NO_REGEXP_BACKREF
void set( int bref );
#endif
void cat( const Box& b );
void orx( const Box& b );
void plus( int atom );
void opt();
void catAnchor( int a );
#ifndef QT_NO_REGEXP_OPTIM
void setupHeuristics();
#endif
#if defined(QT_DEBUG)
void dump() const;
#endif
private:
void addAnchorsToEngine( const Box& to ) const;
QRegExpEngine *eng; // the automaton under construction
QMemArray<int> ls; // the left states (firstpos)
QMemArray<int> rs; // the right states (lastpos)
QMap<int, int> lanchors; // the left anchors
QMap<int, int> ranchors; // the right anchors
int skipanchors; // the anchors to match if the box is skipped
#ifndef QT_NO_REGEXP_OPTIM
int earlyStart; // the index where str can first occur
int lateStart; // the index where str can last occur
QString str; // a string that has to occur in any match
QString leftStr; // a string occurring at the left of this box
QString rightStr; // a string occurring at the right of this box
int maxl; // the maximum length of this box (possibly InftyLen)
#endif
int minl; // the minimum length of this box
#ifndef QT_NO_REGEXP_OPTIM
QMemArray<int> occ1; // first-occurrence array
#endif
};
friend class Box;
/*
This is the lexical analyzer for regular expressions.
*/
enum { Tok_Eos, Tok_Dollar, Tok_LeftParen, Tok_MagicLeftParen,
Tok_PosLookahead, Tok_NegLookahead, Tok_RightParen, Tok_CharClass,
Tok_Caret, Tok_Quantifier, Tok_Bar, Tok_Word, Tok_NonWord,
Tok_Char = 0x10000, Tok_BackRef = 0x20000 };
int getChar();
int getEscape();
#ifndef QT_NO_REGEXP_INTERVAL
int getRep( int def );
#endif
#ifndef QT_NO_REGEXP_LOOKAHEAD
void skipChars( int n );
#endif
void error( const char *msg );
void startTokenizer( const QChar *rx, int len );
int getToken();
const QChar *yyIn; // a pointer to the input regular expression pattern
int yyPos0; // the position of yyTok in the input pattern
int yyPos; // the position of the next character to read
int yyLen; // the length of yyIn
int yyCh; // the last character read
CharClass *yyCharClass; // attribute for Tok_CharClass tokens
int yyMinRep; // attribute for Tok_Quantifier
int yyMaxRep; // ditto
QString yyError; // syntax error or overflow during parsing?
/*
This is the syntactic analyzer for regular expressions.
*/
int parse( const QChar *rx, int len );
void parseAtom( Box *box );
void parseFactor( Box *box );
void parseTerm( Box *box );
void parseExpression( Box *box );
int yyTok; // the last token read
bool yyMayCapture; // set this to FALSE to disable capturing
/*
This is the engine state during matching.
*/
const QString *mmStr; // a pointer to the input QString
const QChar *mmIn; // a pointer to the input string data
int mmPos; // the current position in the string
int mmCaretPos;
int mmLen; // the length of the input string
bool mmMinimal; // minimal matching?
QMemArray<int> mmCaptured; // an array of pairs (start, len)
QMemArray<int> mmCapturedNoMatch; // an array of pairs (-1, -1)
QMemArray<int> mmBigArray; // big QMemArray<int> array
int *mmInNextStack; // is state is mmNextStack?
int *mmCurStack; // stack of current states
int *mmNextStack; // stack of next states
int *mmCurCapBegin; // start of current states' captures
int *mmNextCapBegin; // start of next states' captures
int *mmCurCapEnd; // end of current states' captures
int *mmNextCapEnd; // end of next states' captures
int *mmTempCapBegin; // start of temporary captures
int *mmTempCapEnd; // end of temporary captures
int *mmCapBegin; // start of captures for a next state
int *mmCapEnd; // end of captures for a next state
int *mmSlideTab; // bump-along slide table for bad-character heuristic
int mmSlideTabSize; // size of slide table
#ifndef QT_NO_REGEXP_BACKREF
QIntDict<int> mmSleeping; // dictionary of back-reference sleepers
#endif
int mmMatchLen; // length of match
int mmMatchedLen; // length of partial match
};
QRegExpEngine::QRegExpEngine( const QString& rx, bool caseSensitive )
#ifndef QT_NO_REGEXP_BACKREF
: mmSleeping( 101 )
#endif
{
setup( caseSensitive );
valid = ( parse(rx.unicode(), rx.length()) == (int) rx.length() );
if ( !valid )
error( RXERR_LEFTDELIM );
}
#ifndef QT_NO_REGEXP_OPTIM
QRegExpEngine::~QRegExpEngine()
{
}
#endif
/*
Tries to match in str and returns an array of (begin, length) pairs
for captured text. If there is no match, all pairs are (-1, -1).
*/
QMemArray<int> QRegExpEngine::match( const QString& str, int pos, bool minimal,
bool oneTest, int caretIndex )
{
mmStr = &str;
mmIn = str.unicode();
if ( mmIn == 0 )
mmIn = &QChar::null;
mmPos = pos;
mmCaretPos = caretIndex;
mmLen = str.length();
mmMinimal = minimal;
mmMatchLen = 0;
mmMatchedLen = 0;
bool matched = FALSE;
if ( valid && mmPos >= 0 && mmPos <= mmLen ) {
#ifndef QT_NO_REGEXP_OPTIM
if ( oneTest ) {
matched = matchHere();
} else {
if ( mmPos <= mmLen - minl ) {
if ( caretAnchored ) {
matched = matchHere();
} else if ( useGoodStringHeuristic ) {
matched = goodStringMatch();
} else {
matched = badCharMatch();
}
}
}
#else
matched = oneTest ? matchHere() : bruteMatch();
#endif
}
if ( matched ) {
mmCaptured.detach();
mmCaptured[0] = mmPos;
mmCaptured[1] = mmMatchLen;
for ( int j = 0; j < officialncap; j++ ) {
int len = mmCapEnd[j] - mmCapBegin[j];
mmCaptured[2 + 2 * j] = len > 0 ? mmPos + mmCapBegin[j] : 0;
mmCaptured[2 + 2 * j + 1] = len;
}
return mmCaptured;
} else {
return mmCapturedNoMatch;
}
}
/*
The three following functions add one state to the automaton and
return the number of the state.
*/
int QRegExpEngine::createState( QChar ch )
{
return setupState( ch.unicode() );
}
int QRegExpEngine::createState( const CharClass& cc )
{
#ifndef QT_NO_REGEXP_CCLASS
int n = cl.size();
cl.resize( n + 1 );
cl.insert( n, new CharClass(cc) );
return setupState( CharClassBit | n );
#else
Q_UNUSED( cc );
return setupState( CharClassBit );
#endif
}
#ifndef QT_NO_REGEXP_BACKREF
int QRegExpEngine::createState( int bref )
{
if ( bref > nbrefs ) {
nbrefs = bref;
if ( nbrefs > MaxBackRefs ) {
error( RXERR_LIMIT );
return 0;
}
}
return setupState( BackRefBit | bref );
}
#endif
/*
The two following functions add a transition between all pairs of
states (i, j) where i is fond in from, and j is found in to.
Cat-transitions are distinguished from plus-transitions for
capturing.
*/
void QRegExpEngine::addCatTransitions( const QMemArray<int>& from,
const QMemArray<int>& to )
{
for ( int i = 0; i < (int) from.size(); i++ ) {
State *st = s[from[i]];
mergeInto( &st->outs, to );
}
}
#ifndef QT_NO_REGEXP_CAPTURE
void QRegExpEngine::addPlusTransitions( const QMemArray<int>& from,
const QMemArray<int>& to, int atom )
{
for ( int i = 0; i < (int) from.size(); i++ ) {
State *st = s[from[i]];
QMemArray<int> oldOuts = st->outs.copy();
mergeInto( &st->outs, to );
if ( f[atom].capture >= 0 ) {
if ( st->reenter == 0 )
st->reenter = new QMap<int, int>;
for ( int j = 0; j < (int) to.size(); j++ ) {
if ( !st->reenter->contains(to[j]) &&
oldOuts.bsearch(to[j]) < 0 )
st->reenter->insert( to[j], atom );
}
}
}
}
#endif
#ifndef QT_NO_REGEXP_ANCHOR_ALT
/*
Returns an anchor that means a OR b.
*/
int QRegExpEngine::anchorAlternation( int a, int b )
{
if ( ((a & b) == a || (a & b) == b) && ((a | b) & Anchor_Alternation) == 0 )
return a & b;
int n = aa.size();
#ifndef QT_NO_REGEXP_OPTIM
if ( n > 0 && aa[n - 1].a == a && aa[n - 1].b == b )
return Anchor_Alternation | ( n - 1 );
#endif
aa.resize( n + 1 );
aa[n].a = a;
aa[n].b = b;
return Anchor_Alternation | n;
}
/*
Returns an anchor that means a AND b.
*/
int QRegExpEngine::anchorConcatenation( int a, int b )
{
if ( ((a | b) & Anchor_Alternation) == 0 )
return a | b;
if ( (b & Anchor_Alternation) != 0 )
qSwap( a, b );
int aprime = anchorConcatenation( aa[a ^ Anchor_Alternation].a, b );
int bprime = anchorConcatenation( aa[a ^ Anchor_Alternation].b, b );
return anchorAlternation( aprime, bprime );
}
#endif
/*
Adds anchor a on a transition caracterised by its from state and
its to state.
*/
void QRegExpEngine::addAnchors( int from, int to, int a )
{
State *st = s[from];
if ( st->anchors == 0 )
st->anchors = new QMap<int, int>;
if ( st->anchors->contains(to) )
a = anchorAlternation( (*st->anchors)[to], a );
st->anchors->insert( to, a );
}
#ifndef QT_NO_REGEXP_OPTIM
/*
The two following functions provide the engine with the information
needed by its matching heuristics.
*/
void QRegExpEngine::setupGoodStringHeuristic( int earlyStart, int lateStart,
const QString& str )
{
goodEarlyStart = earlyStart;
goodLateStart = lateStart;
goodStr = cs ? str : str.lower();
}
void QRegExpEngine::setupBadCharHeuristic( int minLen,
const QMemArray<int>& firstOcc )
{
minl = minLen;
if ( cs ) {
occ1 = firstOcc;
} else {
occ1.fill( 0, NumBadChars );
}
}
/*
This function chooses between the good-string and the bad-character
heuristics. It computes two scores and chooses the heuristic with
the highest score.
Here are some common-sense constraints on the scores that should be
respected if the formulas are ever modified: (1) If goodStr is
empty, the good-string heuristic scores 0. (2) If the search is
case insensitive, the good-string heuristic should be used, unless
it scores 0. (Case insensitivity turns all entries of occ1 to 0.)
(3) If (goodLateStart - goodEarlyStart) is big, the good-string
heuristic should score less.
*/
void QRegExpEngine::heuristicallyChooseHeuristic()
{
int i;
if ( minl == 0 )
return;
/*
Magic formula: The good string has to constitute a good
proportion of the minimum-length string, and appear at a
more-or-less known index.
*/
int goodStringScore = ( 64 * goodStr.length() / minl ) -
( goodLateStart - goodEarlyStart );
/*
Less magic formula: We pick a couple of characters at random,
and check whether they are good or bad.
*/
int badCharScore = 0;
int step = QMAX( 1, NumBadChars / 32 );
for ( i = 1; i < NumBadChars; i += step ) {
if ( occ1[i] == NoOccurrence )
badCharScore += minl;
else
badCharScore += occ1[i];
}
badCharScore /= minl;
useGoodStringHeuristic = ( goodStringScore > badCharScore );
}
#endif
#if defined(QT_DEBUG)
void QRegExpEngine::dump() const
{
int i, j;
qDebug( "Case %ssensitive engine", cs ? "" : "in" );
qDebug( " States" );
for ( i = 0; i < ns; i++ ) {
qDebug( " %d%s", i,
i == InitialState ? " (initial)" :
i == FinalState ? " (final)" : "" );
#ifndef QT_NO_REGEXP_CAPTURE
qDebug( " in atom %d", s[i]->atom );
#endif
int m = s[i]->match;
if ( (m & CharClassBit) != 0 ) {
qDebug( " match character class %d", m ^ CharClassBit );
#ifndef QT_NO_REGEXP_CCLASS
cl[m ^ CharClassBit]->dump();
#else
qDebug( " negative character class" );
#endif
} else if ( (m & BackRefBit) != 0 ) {
qDebug( " match back-reference %d", m ^ BackRefBit );
} else if ( m >= 0x20 && m <= 0x7e ) {
qDebug( " match 0x%.4x (%c)", m, m );
} else {
qDebug( " match 0x%.4x", m );
}
for ( j = 0; j < (int) s[i]->outs.size(); j++ ) {
int next = s[i]->outs[j];
qDebug( " -> %d", next );
if ( s[i]->reenter != 0 && s[i]->reenter->contains(next) )
qDebug( " [reenter %d]", (*s[i]->reenter)[next] );
if ( s[i]->anchors != 0 && at(*s[i]->anchors, next) != 0 )
qDebug( " [anchors 0x%.8x]", (*s[i]->anchors)[next] );
}
}
#ifndef QT_NO_REGEXP_CAPTURE
if ( nf > 0 ) {
qDebug( " Atom Parent Capture" );
for ( i = 0; i < nf; i++ )
qDebug( " %6d %6d %6d", i, f[i].parent, f[i].capture );
}
#endif
#ifndef QT_NO_REGEXP_ANCHOR_ALT
for ( i = 0; i < (int) aa.size(); i++ )
qDebug( " Anchor alternation 0x%.8x: 0x%.8x 0x%.9x", i, aa[i].a,
aa[i].b );
#endif
}
#endif
void QRegExpEngine::setup( bool caseSensitive )
{
s.setAutoDelete( TRUE );
s.resize( 32 );
ns = 0;
#ifndef QT_NO_REGEXP_CAPTURE
f.resize( 32 );
nf = 0;
cf = -1;
#endif
officialncap = 0;
ncap = 0;
#ifndef QT_NO_REGEXP_CCLASS
cl.setAutoDelete( TRUE );
#endif
#ifndef QT_NO_REGEXP_LOOKAHEAD
ahead.setAutoDelete( TRUE );
#endif
#ifndef QT_NO_REGEXP_OPTIM
caretAnchored = TRUE;
#endif
valid = FALSE;
cs = caseSensitive;
#ifndef QT_NO_REGEXP_BACKREF
nbrefs = 0;
#endif
#ifndef QT_NO_REGEXP_OPTIM
useGoodStringHeuristic = FALSE;
minl = 0;
occ1.fill( 0, NumBadChars );
#endif
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 ) {
if ( mmSlideTab[slideHead] - 1 > mmSlideTab[slideNext] )
mmSlideTab[slideNext] = mmSlideTab[slideHead] - 1;
mmSlideTab[slideHead] = 0;
} else {
if ( matchHere() )
return TRUE;
}
if ( mmPos == lastPos )
break;
/*
Update the slide table. This code has much in common with
the initialization code.
*/
int sk = occ1[BadChar(mmIn[mmPos + minl])];
if ( sk == NoOccurrence ) {
mmSlideTab[slideNext] = minl;
} else if ( sk > 0 ) {
int k = slideNext + minl - sk;
if ( k >= mmSlideTabSize )
k -= mmSlideTabSize;
if ( sk > mmSlideTab[k] )
mmSlideTab[k] = sk;
}
slideHead = slideNext;
mmPos++;
}
return FALSE;
}
#else
bool QRegExpEngine::bruteMatch()
{
while ( mmPos <= mmLen ) {
if ( matchHere() )
return TRUE;
mmPos++;
}
return FALSE;
}
#endif
/*
Here's the core of the engine. It tries to do a match here and now.
*/
bool QRegExpEngine::matchHere()
{
int ncur = 1, nnext = 0;
int i = 0, j, k, m;
bool stop = FALSE;
mmMatchLen = -1;
mmMatchedLen = -1;
mmCurStack[0] = InitialState;
#ifndef QT_NO_REGEXP_CAPTURE
if ( ncap > 0 ) {
for ( j = 0; j < ncap; j++ ) {
mmCurCapBegin[j] = EmptyCapture;
mmCurCapEnd[j] = EmptyCapture;
}
}
#endif
#ifndef QT_NO_REGEXP_BACKREF
int *zzZ = 0;
while ( (ncur > 0 || !mmSleeping.isEmpty()) && i <= mmLen - mmPos &&
!stop )
#else
while ( ncur > 0 && i <= mmLen - mmPos && !stop )
#endif
{
int ch = ( i < mmLen - mmPos ) ? mmIn[mmPos + i].unicode() : 0;
for ( j = 0; j < ncur; j++ ) {
int cur = mmCurStack[j];
State *scur = s[cur];
QMemArray<int>& outs = scur->outs;
for ( k = 0; k < (int) outs.size(); k++ ) {
int next = outs[k];
State *snext = s[next];
bool in = TRUE;
#ifndef QT_NO_REGEXP_BACKREF
int needSomeSleep = 0;
#endif
/*
First, check if the anchors are anchored properly.
*/
if ( scur->anchors != 0 ) {
int a = at( *scur->anchors, next );
if ( a != 0 && !testAnchor(i, a, mmCurCapBegin + j * ncap) )
in = FALSE;
}
/*
If indeed they are, check if the input character is
correct for this transition.
*/
if ( in ) {
m = snext->match;
if ( (m & (CharClassBit | BackRefBit)) == 0 ) {
if ( cs )
in = ( m == ch );
else
in = ( QChar(m).lower() == QChar(ch).lower() );
} else if ( next == FinalState ) {
mmMatchLen = i;
stop = mmMinimal;
in = TRUE;
} else if ( (m & CharClassBit) != 0 ) {
#ifndef QT_NO_REGEXP_CCLASS
const CharClass *cc = cl[m ^ CharClassBit];
if ( cs )
in = cc->in( ch );
else if ( cc->negative() )
in = cc->in( QChar(ch).lower() ) &&
cc->in( QChar(ch).upper() );
else
in = cc->in( QChar(ch).lower() ) ||
cc->in( QChar(ch).upper() );
#endif
#ifndef QT_NO_REGEXP_BACKREF
} else { /* ( (m & BackRefBit) != 0 ) */
int bref = m ^ BackRefBit;
int ell = j * ncap + ( bref - 1 );
in = bref <= ncap && mmCurCapBegin[ell] != EmptyCapture;
if ( in ) {
if ( cs )
in = ( mmIn[mmPos + mmCurCapBegin[ell]]
== QChar(ch) );
else
in = ( mmIn[mmPos + mmCurCapBegin[ell]].lower()
== QChar(ch).lower() );
}
if ( in ) {
int delta;
if ( mmCurCapEnd[ell] == EmptyCapture )
delta = i - mmCurCapBegin[ell];
else
delta = mmCurCapEnd[ell] - mmCurCapBegin[ell];
in = ( delta <= mmLen - (mmPos + i) );
if ( in && delta > 1 ) {
int n = 1;
if ( cs ) {
while ( n < delta ) {
if ( mmIn[mmPos +
mmCurCapBegin[ell] + n] !=
mmIn[mmPos + i + n] )
break;
n++;
}
} else {
while ( n < delta ) {
QChar a = mmIn[mmPos +
mmCurCapBegin[ell] + n];
QChar b = mmIn[mmPos + i + n];
if ( a.lower() != b.lower() )
break;
n++;
}
}
in = ( n == delta );
if ( in )
needSomeSleep = delta - 1;
}
}
#endif
}
}
/*
We must now update our data structures.
*/
if ( in ) {
#ifndef QT_NO_REGEXP_CAPTURE
int *capBegin, *capEnd;
#endif
/*
If the next state was not encountered yet, all
is fine.
*/
if ( (m = mmInNextStack[next]) == -1 ) {
m = nnext++;
mmNextStack[m] = next;
mmInNextStack[next] = m;
#ifndef QT_NO_REGEXP_CAPTURE
capBegin = mmNextCapBegin + m * ncap;
capEnd = mmNextCapEnd + m * ncap;
/*
Otherwise, we'll first maintain captures in
temporary arrays, and decide at the end whether
it's best to keep the previous capture zones or
the new ones.
*/
} else {
capBegin = mmTempCapBegin;
capEnd = mmTempCapEnd;
#endif
}
#ifndef QT_NO_REGEXP_CAPTURE
/*
Updating the capture zones is much of a task.
*/
if ( ncap > 0 ) {
memcpy( capBegin, mmCurCapBegin + j * ncap,
ncap * sizeof(int) );
memcpy( capEnd, mmCurCapEnd + j * ncap,
ncap * sizeof(int) );
int c = scur->atom, n = snext->atom;
int p = -1, q = -1;
int cap;
/*
Lemma 1. For any x in the range [0..nf), we
have f[x].parent < x.
Proof. By looking at startAtom(), it is
clear that cf < nf holds all the time, and
thus that f[nf].parent < nf.
*/
/*
If we are reentering an atom, we empty all
capture zones inside it.
*/
if ( scur->reenter != 0 &&
(q = at(*scur->reenter, next)) != 0 ) {
QBitArray b;
b.fill( FALSE, nf );
b.setBit( q, TRUE );
for ( int ell = q + 1; ell < nf; ell++ ) {
if ( b.testBit(f[ell].parent) ) {
b.setBit( ell, TRUE );
cap = f[ell].capture;
if ( cap >= 0 ) {
capBegin[cap] = EmptyCapture;
capEnd[cap] = EmptyCapture;
}
}
}
p = f[q].parent;
/*
Otherwise, close the capture zones we are
leaving. We are leaving f[c].capture,
f[f[c].parent].capture,
f[f[f[c].parent].parent].capture, ...,
until f[x].capture, with x such that
f[x].parent is the youngest common ancestor
for c and n.
We go up along c's and n's ancestry until
we find x.
*/
} else {
p = c;
q = n;
while ( p != q ) {
if ( p > q ) {
cap = f[p].capture;
if ( cap >= 0 ) {
if ( capBegin[cap] == i ) {
capBegin[cap] = EmptyCapture;
capEnd[cap] = EmptyCapture;
} else {
capEnd[cap] = i;
}
}
p = f[p].parent;
} else {
q = f[q].parent;
}
}
}
/*
In any case, we now open the capture zones
we are entering. We work upwards from n
until we reach p (the parent of the atom we
reenter or the youngest common ancestor).
*/
while ( n > p ) {
cap = f[n].capture;
if ( cap >= 0 ) {
capBegin[cap] = i;
capEnd[cap] = EmptyCapture;
}
n = f[n].parent;
}
/*
If the next state was already in
mmNextStack, we must choose carefully which
capture zones we want to keep.
*/
if ( capBegin == mmTempCapBegin &&
isBetterCapture(capBegin, capEnd,
mmNextCapBegin + m * ncap,
mmNextCapEnd + m * ncap) ) {
memcpy( mmNextCapBegin + m * ncap, capBegin,
ncap * sizeof(int) );
memcpy( mmNextCapEnd + m * ncap, capEnd,
ncap * sizeof(int) );
}
}
#ifndef QT_NO_REGEXP_BACKREF
/*
We are done with updating the capture zones.
It's now time to put the next state to sleep,
if it needs to, and to remove it from
mmNextStack.
*/
if ( needSomeSleep > 0 ) {
zzZ = new int[1 + 2 * ncap];
zzZ[0] = next;
if ( ncap > 0 ) {
memcpy( zzZ + 1, capBegin, ncap * sizeof(int) );
memcpy( zzZ + 1 + ncap, capEnd,
ncap * sizeof(int) );
}
mmInNextStack[mmNextStack[--nnext]] = -1;
mmSleeping.insert( i + needSomeSleep, zzZ );
}
#endif
#endif
}
}
}
#ifndef QT_NO_REGEXP_CAPTURE
/*
If we reached the final state, hurray! Copy the captured
zone.
*/
if ( ncap > 0 && (m = mmInNextStack[FinalState]) != -1 ) {
memcpy( mmCapBegin, mmNextCapBegin + m * ncap, ncap * sizeof(int) );
memcpy( mmCapEnd, mmNextCapEnd + m * ncap, ncap * sizeof(int) );
}
#ifndef QT_NO_REGEXP_BACKREF
/*
It's time to wake up the sleepers.
*/
if ( !mmSleeping.isEmpty() ) {
while ( (zzZ = mmSleeping.take(i)) != 0 ) {
int next = zzZ[0];
int *capBegin = zzZ + 1;
int *capEnd = zzZ + 1 + ncap;
bool copyOver = TRUE;
if ( (m = mmInNextStack[zzZ[0]]) == -1 ) {
m = nnext++;
mmNextStack[m] = next;
mmInNextStack[next] = m;
} else {
copyOver = isBetterCapture( mmNextCapBegin + m * ncap,
mmNextCapEnd + m * ncap,
capBegin, capEnd );
}
if ( copyOver ) {
memcpy( mmNextCapBegin + m * ncap, capBegin,
ncap * sizeof(int) );
memcpy( mmNextCapEnd + m * ncap, capEnd,
ncap * sizeof(int) );
}
delete[] zzZ;
}
}
#endif
#endif
for ( j = 0; j < nnext; j++ )
mmInNextStack[mmNextStack[j]] = -1;
// avoid needless iteration that confuses mmMatchedLen
if ( nnext == 1 && mmNextStack[0] == FinalState
#ifndef QT_NO_REGEXP_BACKREF
&& mmSleeping.isEmpty()
#endif
)
stop = TRUE;
qSwap( mmCurStack, mmNextStack );
#ifndef QT_NO_REGEXP_CAPTURE
qSwap( mmCurCapBegin, mmNextCapBegin );
qSwap( mmCurCapEnd, mmNextCapEnd );
#endif
ncur = nnext;
nnext = 0;
i++;
}
#ifndef QT_NO_REGEXP_BACKREF
/*
If minimal matching is enabled, we might have some sleepers
left.
*/
while ( !mmSleeping.isEmpty() ) {
zzZ = mmSleeping.take( *QIntDictIterator<int>(mmSleeping) );
delete[] zzZ;
}
#endif
mmMatchedLen = i - 1;
return ( mmMatchLen >= 0 );
}
#ifndef QT_NO_REGEXP_CCLASS
QRegExpEngine::CharClass::CharClass()
: c( 0 ), n( FALSE )
{
#ifndef QT_NO_REGEXP_OPTIM
occ1.fill( NoOccurrence, NumBadChars );
#endif
}
QRegExpEngine::CharClass& QRegExpEngine::CharClass::operator=(
const CharClass& cc )
{
c = cc.c;
r = cc.r.copy();
n = cc.n;
#ifndef QT_NO_REGEXP_OPTIM
occ1 = cc.occ1;
#endif
return *this;
}
void QRegExpEngine::CharClass::clear()
{
c = 0;
r.resize( 0 );
n = FALSE;
}
void QRegExpEngine::CharClass::setNegative( bool negative )
{
n = negative;
#ifndef QT_NO_REGEXP_OPTIM
occ1.fill( 0, NumBadChars );
#endif
}
void QRegExpEngine::CharClass::addCategories( int cats )
{
c |= cats;
#ifndef QT_NO_REGEXP_OPTIM
occ1.fill( 0, NumBadChars );
#endif
}
void QRegExpEngine::CharClass::addRange( ushort from, ushort to )
{
if ( from > to )
qSwap( from, to );
int m = r.size();
r.resize( m + 1 );
r[m].from = from;
r[m].to = to;
#ifndef QT_NO_REGEXP_OPTIM
int i;
if ( to - from < NumBadChars ) {
occ1.detach();
if ( from % NumBadChars <= to % NumBadChars ) {
for ( i = from % NumBadChars; i <= to % NumBadChars; i++ )
occ1[i] = 0;
} else {
for ( i = 0; i <= to % NumBadChars; i++ )
occ1[i] = 0;
for ( i = from % NumBadChars; i < NumBadChars; i++ )
occ1[i] = 0;
}
} else {
occ1.fill( 0, NumBadChars );
}
#endif
}
bool QRegExpEngine::CharClass::in( QChar ch ) const
{
#ifndef QT_NO_REGEXP_OPTIM
if ( occ1[BadChar(ch)] == NoOccurrence )
return n;
#endif
if ( c != 0 && (c & (1 << (int) ch.category())) != 0 )
return !n;
for ( int i = 0; i < (int) r.size(); i++ ) {
if ( ch.unicode() >= r[i].from && ch.unicode() <= r[i].to )
return !n;
}
return n;
}
#if defined(QT_DEBUG)
void QRegExpEngine::CharClass::dump() const
{
int i;
qDebug( " %stive character class", n ? "nega" : "posi" );
#ifndef QT_NO_REGEXP_CCLASS
if ( c != 0 )
qDebug( " categories 0x%.8x", c );
#endif
for ( i = 0; i < (int) r.size(); i++ )
qDebug( " 0x%.4x through 0x%.4x", r[i].from, r[i].to );
}
#endif
#endif
QRegExpEngine::Box::Box( QRegExpEngine *engine )
: eng( engine ), skipanchors( 0 )
#ifndef QT_NO_REGEXP_OPTIM
, earlyStart( 0 ), lateStart( 0 ), maxl( 0 )
#endif
{
#ifndef QT_NO_REGEXP_OPTIM
occ1.fill( NoOccurrence, NumBadChars );
#endif
minl = 0;
}
QRegExpEngine::Box& QRegExpEngine::Box::operator=( const Box& b )
{
eng = b.eng;
ls = b.ls;
rs = b.rs;
lanchors = b.lanchors;
ranchors = b.ranchors;
skipanchors = b.skipanchors;
#ifndef QT_NO_REGEXP_OPTIM
earlyStart = b.earlyStart;
lateStart = b.lateStart;
str = b.str;
leftStr = b.leftStr;
rightStr = b.rightStr;
maxl = b.maxl;
occ1 = b.occ1;
#endif
minl = b.minl;
return *this;
}
void QRegExpEngine::Box::set( QChar ch )
{
ls.resize( 1 );
ls[0] = eng->createState( ch );
rs = ls;
rs.detach();
#ifndef QT_NO_REGEXP_OPTIM
str = ch;
leftStr = ch;
rightStr = ch;
maxl = 1;
occ1.detach();
occ1[BadChar(ch)] = 0;
#endif
minl = 1;
}
void QRegExpEngine::Box::set( const CharClass& cc )
{
ls.resize( 1 );
ls[0] = eng->createState( cc );
rs = ls;
rs.detach();
#ifndef QT_NO_REGEXP_OPTIM
maxl = 1;
occ1 = cc.firstOccurrence();
#endif
minl = 1;
}
#ifndef QT_NO_REGEXP_BACKREF
void QRegExpEngine::Box::set( int bref )
{
ls.resize( 1 );
ls[0] = eng->createState( bref );
rs = ls;
rs.detach();
if ( bref >= 1 && bref <= MaxBackRefs )
skipanchors = Anchor_BackRef0Empty << bref;
#ifndef QT_NO_REGEXP_OPTIM
maxl = InftyLen;
#endif
minl = 0;
}
#endif
void QRegExpEngine::Box::cat( const Box& b )
{
eng->addCatTransitions( rs, b.ls );
addAnchorsToEngine( b );
if ( minl == 0 ) {
mergeInto( &lanchors, b.lanchors );
if ( skipanchors != 0 ) {
for ( int i = 0; i < (int) b.ls.size(); i++ ) {
int a = eng->anchorConcatenation( at(lanchors, b.ls[i]),
skipanchors );
lanchors.insert( b.ls[i], a );
}
}
mergeInto( &ls, b.ls );
}
if ( b.minl == 0 ) {
mergeInto( &ranchors, b.ranchors );
if ( b.skipanchors != 0 ) {
for ( int i = 0; i < (int) rs.size(); i++ ) {
int a = eng->anchorConcatenation( at(ranchors, rs[i]),
b.skipanchors );
ranchors.insert( rs[i], a );
}
}
mergeInto( &rs, b.rs );
} else {
ranchors = b.ranchors;
rs = b.rs;
}
#ifndef QT_NO_REGEXP_OPTIM
if ( maxl != InftyLen ) {
if ( rightStr.length() + b.leftStr.length() >
QMAX(str.length(), b.str.length()) ) {
earlyStart = minl - rightStr.length();
lateStart = maxl - rightStr.length();
str = rightStr + b.leftStr;
} else if ( b.str.length() > str.length() ) {
earlyStart = minl + b.earlyStart;
lateStart = maxl + b.lateStart;
str = b.str;
}
}
if ( (int) leftStr.length() == maxl )
leftStr += b.leftStr;
if ( (int) b.rightStr.length() == b.maxl )
rightStr += b.rightStr;
else
rightStr = b.rightStr;
if ( maxl == InftyLen || b.maxl == InftyLen )
maxl = InftyLen;
else
maxl += b.maxl;
occ1.detach();
for ( int i = 0; i < NumBadChars; i++ ) {
if ( b.occ1[i] != NoOccurrence && minl + b.occ1[i] < occ1[i] )
occ1[i] = minl + b.occ1[i];
}
#endif
minl += b.minl;
if ( minl == 0 )
skipanchors = eng->anchorConcatenation( skipanchors, b.skipanchors );
else
skipanchors = 0;
}
void QRegExpEngine::Box::orx( const Box& b )
{
mergeInto( &ls, b.ls );
mergeInto( &lanchors, b.lanchors );
mergeInto( &rs, b.rs );
mergeInto( &ranchors, b.ranchors );
if ( b.minl == 0 ) {
if ( minl == 0 )
skipanchors = eng->anchorAlternation( skipanchors, b.skipanchors );
else
skipanchors = b.skipanchors;
}
#ifndef QT_NO_REGEXP_OPTIM
occ1.detach();
for ( int i = 0; i < NumBadChars; i++ ) {
if ( occ1[i] > b.occ1[i] )
occ1[i] = b.occ1[i];
}
earlyStart = 0;
lateStart = 0;
str = QString();
leftStr = QString();
rightStr = QString();
if ( b.maxl > maxl )
maxl = b.maxl;
#endif
if ( b.minl < minl )
minl = b.minl;
}
void QRegExpEngine::Box::plus( int atom )
{
#ifndef QT_NO_REGEXP_CAPTURE
eng->addPlusTransitions( rs, ls, atom );
#else
Q_UNUSED( atom );
eng->addCatTransitions( rs, ls );
#endif
addAnchorsToEngine( *this );
#ifndef QT_NO_REGEXP_OPTIM
maxl = InftyLen;
#endif
}
void QRegExpEngine::Box::opt()
{
#ifndef QT_NO_REGEXP_OPTIM
earlyStart = 0;
lateStart = 0;
str = QString();
leftStr = QString();
rightStr = QString();
#endif
skipanchors = 0;
minl = 0;
}
void QRegExpEngine::Box::catAnchor( int a )
{
if ( a != 0 ) {
for ( int i = 0; i < (int) rs.size(); i++ ) {
a = eng->anchorConcatenation( at(ranchors, rs[i]), a );
ranchors.insert( rs[i], a );
}
if ( minl == 0 )
skipanchors = eng->anchorConcatenation( skipanchors, a );
}
}
#ifndef QT_NO_REGEXP_OPTIM
void QRegExpEngine::Box::setupHeuristics()
{
eng->setupGoodStringHeuristic( earlyStart, lateStart, str );
/*
A regular expression such as 112|1 has occ1['2'] = 2 and minl =
1 at this point. An entry of occ1 has to be at most minl or
infinity for the rest of the algorithm to go well.
We waited until here before normalizing these cases (instead of
doing it in Box::orx()) because sometimes things improve by
themselves. Consider for example (112|1)34.
*/
for ( int i = 0; i < NumBadChars; i++ ) {
if ( occ1[i] != NoOccurrence && occ1[i] >= minl )
occ1[i] = minl;
}
eng->setupBadCharHeuristic( minl, occ1 );
eng->heuristicallyChooseHeuristic();
}
#endif
#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();
#endif
yyMinRep = 0;
yyMaxRep = 0;
yyCh = getChar();
switch ( prevCh ) {
case EOS:
yyPos0 = yyPos;
return Tok_Eos;
case '$':
return Tok_Dollar;
case '(':
if ( yyCh == '?' ) {
prevCh = getChar();
yyCh = getChar();
switch ( prevCh ) {
#ifndef QT_NO_REGEXP_LOOKAHEAD
case '!':
return Tok_NegLookahead;
case '=':
return Tok_PosLookahead;
#endif
case ':':
return Tok_MagicLeftParen;
default:
error( RXERR_LOOKAHEAD );
return Tok_MagicLeftParen;
}
} else {
return Tok_LeftParen;
}
case ')':
return Tok_RightParen;
case '*':
yyMinRep = 0;
yyMaxRep = InftyRep;
return Tok_Quantifier;
case '+':
yyMinRep = 1;
yyMaxRep = InftyRep;
return Tok_Quantifier;
case '.':
#ifndef QT_NO_REGEXP_CCLASS
yyCharClass->setNegative( TRUE );
#endif
return Tok_CharClass;
case '?':
yyMinRep = 0;
yyMaxRep = 1;
return Tok_Quantifier;
case '[':
#ifndef QT_NO_REGEXP_CCLASS
if ( yyCh == '^' ) {
yyCharClass->setNegative( TRUE );
yyCh = getChar();
}
charPending = FALSE;
rangePending = FALSE;
do {
if ( yyCh == '-' && charPending && !rangePending ) {
rangePending = TRUE;
yyCh = getChar();
} else {
if ( charPending && !rangePending ) {
yyCharClass->addSingleton( pendingCh );
charPending = FALSE;
}
if ( yyCh == '\\' ) {
yyCh = getChar();
tok = getEscape();
if ( tok == Tok_Word )
tok = '\b';
} else {
tok = Tok_Char | yyCh;
yyCh = getChar();
}
if ( tok == Tok_CharClass ) {
if ( rangePending ) {
yyCharClass->addSingleton( '-' );
yyCharClass->addSingleton( pendingCh );
charPending = FALSE;
rangePending = FALSE;
}
} else if ( (tok & Tok_Char) != 0 ) {
if ( rangePending ) {
yyCharClass->addRange( pendingCh, tok ^ Tok_Char );
charPending = FALSE;
rangePending = FALSE;
} else {
pendingCh = tok ^ Tok_Char;
charPending = TRUE;
}
} else {
error( RXERR_CHARCLASS );
}
}
} while ( yyCh != ']' && yyCh != EOS );
if ( rangePending )
yyCharClass->addSingleton( '-' );
if ( charPending )
yyCharClass->addSingleton( pendingCh );
if ( yyCh == EOS )
error( RXERR_END );
else
yyCh = getChar();
return Tok_CharClass;
#else
error( RXERR_END );
return Tok_Char | '[';
#endif
case '\\':
return getEscape();
case ']':
error( RXERR_LEFTDELIM );
return Tok_Char | ']';
case '^':
return Tok_Caret;
case '{':
#ifndef QT_NO_REGEXP_INTERVAL
yyMinRep = getRep( 0 );
yyMaxRep = yyMinRep;
if ( yyCh == ',' ) {
yyCh = getChar();
yyMaxRep = getRep( InftyRep );
}
if ( yyMaxRep < yyMinRep )
qSwap( yyMinRep, yyMaxRep );
if ( yyCh != '}' )
error( RXERR_REPETITION );
yyCh = getChar();
return Tok_Quantifier;
#else
error( RXERR_DISABLED );
return Tok_Char | '{';
#endif
case '|':
return Tok_Bar;
case '}':
error( RXERR_LEFTDELIM );
return Tok_Char | '}';
default:
return Tok_Char | prevCh;
}
}
int QRegExpEngine::parse( const QChar *pattern, int len )
{
valid = TRUE;
startTokenizer( pattern, len );
yyTok = getToken();
#ifndef QT_NO_REGEXP_CAPTURE
yyMayCapture = TRUE;
#else
yyMayCapture = FALSE;
#endif
#ifndef QT_NO_REGEXP_CAPTURE
int atom = startAtom( FALSE );
#endif
CharClass anything;
Box box( this ); // create InitialState
box.set( anything );
Box rightBox( this ); // create FinalState
rightBox.set( anything );
Box middleBox( this );
parseExpression( &middleBox );
#ifndef QT_NO_REGEXP_CAPTURE
finishAtom( atom );
#endif
#ifndef QT_NO_REGEXP_OPTIM
middleBox.setupHeuristics();
#endif
box.cat( middleBox );
box.cat( rightBox );
delete yyCharClass;
yyCharClass = 0;
officialncap = ncap;
#ifndef QT_NO_REGEXP_BACKREF
if ( nbrefs > ncap )
ncap = nbrefs;
#endif
mmCaptured.resize( 2 + 2 * officialncap );
mmCapturedNoMatch.fill( -1, 2 + 2 * officialncap );
/*
We use one QMemArray<int> for all the big data used a lot in
matchHere() and friends.
*/
#ifndef QT_NO_REGEXP_OPTIM
mmSlideTabSize = QMAX( minl + 1, 16 );
#else
mmSlideTabSize = 0;
#endif
mmBigArray.resize( (3 + 4 * ncap) * ns + 4 * ncap + mmSlideTabSize );
mmInNextStack = mmBigArray.data();
memset( mmInNextStack, -1, ns * sizeof(int) );
mmCurStack = mmInNextStack + ns;
mmNextStack = mmInNextStack + 2 * ns;
mmCurCapBegin = mmInNextStack + 3 * ns;
mmNextCapBegin = mmCurCapBegin + ncap * ns;
mmCurCapEnd = mmCurCapBegin + 2 * ncap * ns;
mmNextCapEnd = mmCurCapBegin + 3 * ncap * ns;
mmTempCapBegin = mmCurCapBegin + 4 * ncap * ns;
mmTempCapEnd = mmTempCapBegin + ncap;
mmCapBegin = mmTempCapBegin + 2 * ncap;
mmCapEnd = mmTempCapBegin + 3 * ncap;
mmSlideTab = mmTempCapBegin + 4 * ncap;
if ( !yyError.isEmpty() )
return -1;
#ifndef QT_NO_REGEXP_OPTIM
State *sinit = s[InitialState];
caretAnchored = ( sinit->anchors != 0 );
if ( caretAnchored ) {
QMap<int, int>& anchors = *sinit->anchors;
QMap<int, int>::ConstIterator a;
for ( a = anchors.begin(); a != anchors.end(); ++a ) {
#ifndef QT_NO_REGEXP_ANCHOR_ALT
if ( (*a & Anchor_Alternation) != 0 )
break;
#endif
if ( (*a & Anchor_Caret) == 0 ) {
caretAnchored = FALSE;
break;
}
}
}
#endif
return yyPos0;
}
void QRegExpEngine::parseAtom( Box *box )
{
#ifndef QT_NO_REGEXP_LOOKAHEAD
QRegExpEngine *eng = 0;
bool neg;
int len;
#endif
switch ( yyTok ) {
case Tok_Dollar:
box->catAnchor( Anchor_Dollar );
break;
case Tok_Caret:
box->catAnchor( Anchor_Caret );
break;
#ifndef QT_NO_REGEXP_LOOKAHEAD
case Tok_PosLookahead:
case Tok_NegLookahead:
neg = ( yyTok == Tok_NegLookahead );
eng = new QRegExpEngine( cs );
len = eng->parse( yyIn + yyPos - 1, yyLen - yyPos + 1 );
if ( len >= 0 )
skipChars( len );
else
error( RXERR_LOOKAHEAD );
box->catAnchor( addLookahead(eng, neg) );
yyTok = getToken();
if ( yyTok != Tok_RightParen )
error( RXERR_LOOKAHEAD );
break;
#endif
#ifndef QT_NO_REGEXP_ESCAPE
case Tok_Word:
box->catAnchor( Anchor_Word );
break;
case Tok_NonWord:
box->catAnchor( Anchor_NonWord );
break;
#endif
case Tok_LeftParen:
case Tok_MagicLeftParen:
yyTok = getToken();
parseExpression( box );
if ( yyTok != Tok_RightParen )
error( RXERR_END );
break;
case Tok_CharClass:
box->set( *yyCharClass );
break;
case Tok_Quantifier:
error( RXERR_REPETITION );
break;
default:
if ( (yyTok & Tok_Char) != 0 )
box->set( QChar(yyTok ^ Tok_Char) );
#ifndef QT_NO_REGEXP_BACKREF
else if ( (yyTok & Tok_BackRef) != 0 )
box->set( yyTok ^ Tok_BackRef );
#endif
else
error( RXERR_DISABLED );
}
yyTok = getToken();
}
void QRegExpEngine::parseFactor( Box *box )
{
#ifndef QT_NO_REGEXP_CAPTURE
int atom = startAtom( yyMayCapture && yyTok == Tok_LeftParen );
#else
static const int atom = 0;
#endif
#ifndef QT_NO_REGEXP_INTERVAL
#define YYREDO() \
yyIn = in, yyPos0 = pos0, yyPos = pos, yyLen = len, yyCh = ch, \
*yyCharClass = charClass, yyMinRep = 0, yyMaxRep = 0, yyTok = tok
const QChar *in = yyIn;
int pos0 = yyPos0;
int pos = yyPos;
int len = yyLen;
int ch = yyCh;
CharClass charClass;
if ( yyTok == Tok_CharClass )
charClass = *yyCharClass;
int tok = yyTok;
bool mayCapture = yyMayCapture;
#endif
parseAtom( box );
#ifndef QT_NO_REGEXP_CAPTURE
finishAtom( atom );
#endif
if ( yyTok == Tok_Quantifier ) {
if ( yyMaxRep == InftyRep ) {
box->plus( atom );
#ifndef QT_NO_REGEXP_INTERVAL
} else if ( yyMaxRep == 0 ) {
box->clear();
#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 )
{
rx.eng->ref();
derefEngine( eng, priv->rxpattern );
eng = rx.eng;
priv->pattern = rx.priv->pattern;
priv->rxpattern = rx.priv->rxpattern;
#ifndef QT_NO_REGEXP_WILDCARD
priv->wc = rx.priv->wc;
#endif
priv->min = rx.priv->min;
#ifndef QT_NO_REGEXP_CAPTURE
priv->t = rx.priv->t;
priv->capturedCache = rx.priv->capturedCache;
#endif
priv->captured = rx.priv->captured;
return *this;
}
/*!
Returns TRUE if this regular expression is equal to \a rx;
otherwise returns FALSE.
Two QRegExp objects are equal if they have the same pattern
strings and the same settings for case sensitivity, wildcard and
minimal matching.
*/
bool QRegExp::operator==( const QRegExp& rx ) const
{
return priv->pattern == rx.priv->pattern &&
eng->caseSensitive() == rx.eng->caseSensitive() &&
#ifndef QT_NO_REGEXP_WILDCARD
priv->wc == rx.priv->wc &&
#endif
priv->min == rx.priv->min;
}
/*!
\fn bool QRegExp::operator!=( const QRegExp& rx ) const
Returns TRUE if this regular expression is not equal to \a rx;
otherwise returns FALSE.
\sa operator==()
*/
/*!
Returns TRUE if the pattern string is empty; otherwise returns
FALSE.
If you call exactMatch() with an empty pattern on an empty string
it will return TRUE; otherwise it returns FALSE since it operates
over the whole string. If you call search() with an empty pattern
on \e any string it will return the start offset (0 by default)
because the empty pattern matches the 'emptiness' at the start of
the string. In this case the length of the match returned by
matchedLength() will be 0.
See QString::isEmpty().
*/
bool QRegExp::isEmpty() const
{
return priv->pattern.isEmpty();
}
/*!
Returns TRUE if the regular expression is valid; otherwise returns
FALSE. An invalid regular expression never matches.
The pattern <b>[a-z</b> is an example of an invalid pattern, since
it lacks a closing square bracket.
Note that the validity of a regexp may also depend on the setting
of the wildcard flag, for example <b>*.html</b> is a valid
wildcard regexp but an invalid full regexp.
\sa errorString()
*/
bool QRegExp::isValid() const
{
return eng->isValid();
}
/*!
Returns the pattern string of the regular expression. The pattern
has either regular expression syntax or wildcard syntax, depending
on wildcard().
\sa setPattern()
*/
QString QRegExp::pattern() const
{
return priv->pattern;
}
/*!
Sets the pattern string to \a pattern. The case sensitivity,
wildcard and minimal matching options are not changed.
\sa pattern()
*/
void QRegExp::setPattern( const QString& pattern )
{
if ( priv->pattern != pattern ) {
priv->pattern = pattern;
compile( caseSensitive() );
}
}
/*!
Returns TRUE if case sensitivity is enabled; otherwise returns
FALSE. The default is TRUE.
\sa setCaseSensitive()
*/
bool QRegExp::caseSensitive() const
{
return eng->caseSensitive();
}
/*!
Sets case sensitive matching to \a sensitive.
If \a sensitive is TRUE, <b>\\.txt$</b> matches \c{readme.txt} but
not \c{README.TXT}.
\sa caseSensitive()
*/
void QRegExp::setCaseSensitive( bool sensitive )
{
if ( sensitive != eng->caseSensitive() )
compile( sensitive );
}
#ifndef QT_NO_REGEXP_WILDCARD
/*!
Returns TRUE if wildcard mode is enabled; otherwise returns FALSE.
The default is FALSE.
\sa setWildcard()
*/
bool QRegExp::wildcard() const
{
return priv->wc;
}
/*!
Sets the wildcard mode for the regular expression. The default is
FALSE.
Setting \a wildcard to TRUE enables simple shell-like wildcard
matching. (See \link #wildcard-matching wildcard matching
(globbing) \endlink.)
For example, <b>r*.txt</b> matches the string \c{readme.txt} in
wildcard mode, but does not match \c{readme}.
\sa wildcard()
*/
void QRegExp::setWildcard( bool wildcard )
{
if ( wildcard != priv->wc ) {
priv->wc = wildcard;
compile( caseSensitive() );
}
}
#endif
/*!
Returns TRUE if minimal (non-greedy) matching is enabled;
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
The order of elements matched by cap() is as follows. The first
element, cap(0), is the entire matching string. Each subsequent
element corresponds to the next capturing open left parentheses.
Thus cap(1) is the text of the first capturing parentheses, cap(2)
is the text of the second, and so on.
\target cap_in_a_loop
Some patterns may lead to a number of matches which cannot be
determined in advance, for example:
\code
QRegExp rx( "(\\d+)" );
str = "Offsets: 12 14 99 231 7";
QStringList list;
pos = 0;
while ( pos >= 0 ) {
pos = rx.search( str, pos );
if ( pos > -1 ) {
list += rx.cap( 1 );
pos += rx.matchedLength();
}
}
// list contains "12", "14", "99", "231", "7"
\endcode
\sa capturedTexts() pos() exactMatch() search() searchRev()
*/
QString QRegExp::cap( int nth )
{
if ( nth < 0 || nth >= (int) priv->captured.size() / 2 )
return QString::null;
else
return capturedTexts()[nth];
}
/*!
Returns the position of the \a nth captured text in the searched
string. If \a nth is 0 (the default), pos() returns the position
of the whole match.
Example:
\code
QRegExp rx( "/([a-z]+)/([a-z]+)" );
rx.search( "Output /dev/null" ); // returns 7 (position of /dev/null)
rx.pos( 0 ); // returns 7 (position of /dev/null)
rx.pos( 1 ); // returns 8 (position of dev)
rx.pos( 2 ); // returns 12 (position of null)
\endcode
For zero-length matches, pos() always returns -1. (For example, if
cap(4) would return an empty string, pos(4) returns -1.) This is
due to an implementation tradeoff.
\sa capturedTexts() exactMatch() search() searchRev()
*/
int QRegExp::pos( int nth )
{
if ( nth < 0 || nth >= (int) priv->captured.size() / 2 )
return -1;
else
return priv->captured[2 * nth];
}
/*!
Returns a text string that explains why a regexp pattern is
invalid the case being; otherwise returns "no error occurred".
\sa isValid()
*/
QString QRegExp::errorString()
{
if ( isValid() ) {
return QString( RXERR_OK );
} else {
return eng->errorString();
}
}
#endif
/*!
Returns the string \a str with every regexp special character
escaped with a backslash. The special characters are $, (, ), *, +,
., ?, [, \, ], ^, {, | and }.
Example:
\code
s1 = QRegExp::escape( "bingo" ); // s1 == "bingo"
s2 = QRegExp::escape( "f(x)" ); // s2 == "f\\(x\\)"
\endcode
This function is useful to construct regexp patterns dynamically:
\code
QRegExp rx( "(" + QRegExp::escape(name) +
"|" + QRegExp::escape(alias) + ")" );
\endcode
*/
QString QRegExp::escape( const QString& str )
{
static const char meta[] = "$()*+.?[\\]^{|}";
QString quoted = str;
int i = 0;
while ( i < (int) quoted.length() ) {
if ( strchr(meta, quoted[i].latin1()) != 0 )
quoted.insert( i++, "\\" );
i++;
}
return quoted;
}
void QRegExp::compile( bool caseSensitive )
{
derefEngine( eng, priv->rxpattern );
#ifndef QT_NO_REGEXP_WILDCARD
if ( priv->wc )
priv->rxpattern = wc2rx( priv->pattern );
else
#endif
priv->rxpattern = priv->pattern.isNull() ? QString::fromLatin1( "" )
: priv->pattern;
eng = newEngine( priv->rxpattern, caseSensitive );
#ifndef QT_NO_REGEXP_CAPTURE
priv->t = QString();
priv->capturedCache.clear();
#endif
priv->captured.detach();
priv->captured.fill( -1, 2 + 2 * eng->numCaptures() );
}
int QRegExp::caretIndex( int offset, CaretMode caretMode )
{
if ( caretMode == CaretAtZero ) {
return 0;
} else if ( caretMode == CaretAtOffset ) {
return offset;
} else { // CaretWontMatch
return -1;
}
}
#endif // QT_NO_REGEXP
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
@@ -1,292 +1,290 @@
/****************************************************************************
** $Id$
**
** QSemaphore 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 "qsemaphore.h"
#include "qmutex.h"
#include "qwaitcondition.h"
/*!
\class QSemaphore qsemaphore.h
\threadsafe
\brief The QSemaphore class provides a robust integer semaphore.
\ingroup thread
\ingroup environment
A QSemaphore can be used to serialize thread execution, in a
similar way to a QMutex. A semaphore differs from a mutex, in
that a semaphore can be accessed by more than one thread at a
time.
For example, suppose we have an application that stores data in a
large tree structure. The application creates 10 threads
(commonly called a thread pool) to perform searches on the tree.
When the application searches the tree for some piece of data, it
uses one thread per base node to do the searching. A semaphore
could be used to make sure that two threads don't try to search
the same branch of the tree at the same time.
A non-computing example of a semaphore would be dining at a
restuarant. A semaphore is initialized to have a maximum count
equal to the number of chairs in the restuarant. As people
arrive, they want a seat. As seats are filled, the semaphore is
accessed, once per person. As people leave, the access is
released, allowing more people to enter. If a party of 10 people
want to be seated, but there are only 9 seats, those 10 people
will wait, but a party of 4 people would be seated (taking the
available seats to 5, making the party of 10 people wait longer).
When a semaphore is created it is given a number which is the
maximum number of concurrent accesses it will permit. This amount
may be changed using operator++(), operator--(), operator+=() and
operator-=(). The number of accesses allowed is retrieved with
available(), and the total number with total(). Note that the
incrementing functions will block if there aren't enough available
accesses. Use tryAccess() if you want to acquire accesses without
blocking.
*/
class QSemaphorePrivate {
public:
QSemaphorePrivate(int);
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.
+ 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
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
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.
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 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,829 +1,833 @@
/****************************************************************************
** $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});
%joining_code = numberize(qw{U D R C});
# Read data into hashes...
#
open IN, "UnicodeData.txt";
$position = 1;
while (<IN>) {
@fields = split /;/;
if ( length($fields[0]) < 5 ) {
if ( $fields[1] =~ /, First>/ ) {
$codeRangeBegin = $fields[0];
} elsif ( $fields[1] =~ /, Last>/ ) {
for ( $i=hex($codeRangeBegin); $i<=hex($fields[0]); $i+=1 ) {
@fields2 = @fields;
$fields2[0] = sprintf "%lX", $i;
readUnicodeDataLine @fields2;
}
} else {
readUnicodeDataLine @fields;
}
}
}
open IN2, "ArabicShaping.txt";
$position = 1;
while (<IN2>) {
@fields = split /;/;
$code = shift @fields;
$dummy = shift @fields;
$join = shift @fields;
$join =~ s/ //g;
$join = $joining_code{$join};
$joining{$code}=$join;
}
# Build pages...
#
$rowtable_txt =
"static const Q_UINT8 * const unicode_info[256] = {";
for $row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$row,$cell);
$info = $category{$code};
$info = 0 if !defined $info;
$txt .= "\n " if $cell%8 == 0;
$txt .= "$info, ";
}
$therow = $row{$txt};
if ( !defined $therow ) {
$size+=256;
$therow = "ui_".sprintf("%02X",$row);
$rowtext{$therow} =
"static const Q_UINT8 ${therow}[] = {$txt\n};\n\n";
$row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $row%8 == 0;
$rowtable_txt .= "$therow, ";
}
print "// START OF GENERATED DATA\n\n";
print "#ifndef QT_NO_UNICODETABLES\n\n";
# Print pages...
#
for $r ( sort keys %rowtext ) {
print $rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# Build decomposition tables
#
$rowtable_txt =
"static const Q_UINT16 * const decomposition_info[256] = {";
$table_txt =
"static const Q_UINT16 decomposition_map[] = {\n 0,\n";
for $row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$row,$cell);
$txt .= "\n " if $cell%8 == 0;
if( $decomposition_tag{$code} != 0 ) {
$txt .= " $decomposition_pos{$code},";
$table_txt .= " $decomposition_tag{$code},";
$table_txt .= " 0x$code,";
$table_txt .= " $decomposition{$code}, 0,\n";
$size += 2 * $decomposition_len{$code} + 6;
} else {
$txt .= " 0,";
}
}
$therow = $row{$txt};
if ( !defined $therow ) {
$size+=512;
$therow = "di_".sprintf("%02X",$row);
$dec_rowtext{$therow} =
"static const Q_UINT16 ${therow}[] = {$txt\n};\n\n";
$row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $row%8 == 0;
$rowtable_txt .= "$therow, ";
}
# Print decomposition tables
#
print "$table_txt\n};\n\n";
for $r ( sort keys %dec_rowtext ) {
print $dec_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# build ligature tables
#
$size = 0;
$position = 1;
$rowtable_txt =
"static const Q_UINT16 * const ligature_info[256] = {";
$table_txt =
"static const Q_UINT16 ligature_map[] = {\n 0,\n";
for $lig_row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$lig_row,$cell);
$txt .= "\n " if $cell%8 == 0;
if( defined $ligature{$code} ) {
$txt .= " $position,";
@ligature = split(" ", $ligature{$code});
# we need to sort ligatures according to their length.
# long ones have to come first!
@ligature_sort = sort { $decomposition_len{$b} <=> $decomposition_len{$a} } @ligature;
# now replace each code by its position in
# the decomposition map.
undef(@lig_pos);
for $n (@ligature_sort) {
push(@lig_pos, $decomposition_pos{$n});
}
# debug info
if( 0 ) {
print "ligatures: $ligature{$code}\n";
$sort = join(" ", @ligature_sort);
print "sorted : $sort\n";
}
$lig = join(", ", @lig_pos);
$table_txt .= " $lig, 0,\n";
$size += 2 * scalar(@ligature) + 2;
$position += scalar(@ligature) + 1;
} else {
$txt .= " 0,";
}
}
$therow = $lig_row{$txt};
if ( !defined $therow ) {
$size+=512;
$therow = "li_".sprintf("%02X",$lig_row);
$lig_rowtext{$therow} =
"static const Q_UINT16 ${therow}[] = {$txt\n};\n\n";
$lig_row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $lig_row%8 == 0;
$rowtable_txt .= "$therow, ";
}
# Print ligature tables
#
print "$table_txt\n};\n\n";
for $r ( sort keys %lig_rowtext ) {
print $lig_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# Build direction/joining/mirrored pages...
#
$rowtable_txt =
"static const Q_UINT8 * const direction_info[256] = {";
for $dir_row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$dir_row,$cell);
$dir = $bidi_category{$code};
$dir = 0 if !defined $dir;
$join = $joining{$code};
$join = 0 if !defined $join;
$mirr = $mirrored{$code};
$mirr = 0 if !defined $mirr;
$info = $dir + 32*$join + 128*$mirr;
$txt .= "\n " if $cell%8 == 0;
$txt .= "$info, ";
}
$therow = $dir_row{$txt};
if ( !defined $therow ) {
$size+=256;
$therow = "dir_".sprintf("%02X",$dir_row);
$dir_rowtext{$therow} =
"static const Q_UINT8 ${therow}[] = {$txt\n};\n\n";
$dir_row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $dir_row%8 == 0;
$rowtable_txt .= "$therow, ";
}
# Print pages...
#
for $r ( sort keys %dir_rowtext ) {
print $dir_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# Build table of combining classes
#
$rowtable_txt =
"static const Q_UINT8 * const combining_info[256] = {";
for $combining_row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$combining_row,$cell);
$info = $combining_class{$code};
$info = 0 if !defined $info;
$txt .= "\n " if $cell%8 == 0;
$txt .= "$info, ";
}
$therow = $combining_row{$txt};
if ( !defined $therow ) {
$size+=256;
$therow = "cmb_".sprintf("%02X",$combining_row);
$combining_rowtext{$therow} =
"static const Q_UINT8 ${therow}[] = {$txt\n};\n\n";
$combining_row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $combining_row%8 == 0;
$rowtable_txt .= "$therow, ";
}
# Print pages...
#
for $r ( sort keys %combining_rowtext ) {
print $combining_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# Build case info
#
$rowtable_txt =
"static const Q_UINT16 * const case_info[256] = {";
for $row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$row,$cell);
$info = $uppercase{$code};
if ( length( $info ) eq 0 ) {
$info = $lowercase{$code};
}
$info =~ s/^0+//;
if ( length( $info ) eq 0 ) {
$info = "0";
} else {
$info = "0x".lc($info);
}
if ( length( $info ) ne 1 ) {
$nonzero = 1;
}
$txt .= "\n " if $cell%8 == 0;
$txt .= "$info, ";
}
$therow = $case_row{$txt};
if ( !defined $therow && $nonzero ne 0 ) {
$size+=512;
$therow = "case_".sprintf("%02X",$row);
$case_rowtext{$therow} =
"static const Q_UINT16 ${therow}[] = {$txt\n};\n\n";
$case_row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $row%8 == 0;
if ( $nonzero ne 0 ) {
$rowtable_txt .= "$therow, ";
} else {
$rowtable_txt .= "0, ";
}
}
# Print pages...
#
for $r ( sort keys %case_rowtext ) {
print $case_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
# Build decimal info
#
$rowtable_txt =
"static const Q_INT8 * const decimal_info[256] = {";
for $row ( 0..255 ) {
$nonzero=0;
$txt = "";
for $cell ( 0..255 ) {
$code = sprintf("%02X%02X",$row,$cell);
$info = $digit_value{$code};
if ( length( $info ) eq 0 ) {
$info = -1;
} else {
$nonzero = 1;
}
$txt .= "\n " if $cell%8 == 0;
$txt .= "$info, ";
}
$therow = $decimal_row{$txt};
if ( !defined $therow && $nonzero ne 0 ) {
$size+=512;
$therow = "num_".sprintf("%02X",$row);
$decimal_rowtext{$therow} =
"static const Q_INT8 ${therow}[] = {$txt\n};\n\n";
$decimal_row{$txt}=$therow;
}
$rowtable_txt .= "\n " if $row%8 == 0;
if ( $nonzero ne 0 ) {
$rowtable_txt .= "$therow, ";
} else {
$rowtable_txt .= "0, ";
}
}
# Print pages...
#
for $r ( sort keys %decimal_rowtext ) {
print $decimal_rowtext{$r};
}
print "$rowtable_txt\n};\n";
$size += 256*4;
print "// $size bytes\n\n";
print "#endif\n\n";
print "// END OF GENERATED DATA\n\n";
__END__
*/
// START OF GENERATED DATA
static const Q_UINT8 ui_00[] = {
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
7, 26, 26, 26, 28, 26, 26, 26,
22, 23, 26, 27, 26, 21, 26, 26,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 26, 26, 27, 27, 27, 26,
26, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 22, 26, 23, 29, 20,
29, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 22, 27, 23, 27, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10,
7, 26, 28, 28, 28, 28, 30, 30,
29, 30, 16, 24, 27, 21, 30, 29,
30, 27, 6, 6, 29, 16, 30, 26,
29, 6, 16, 25, 6, 6, 6, 26,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 27,
15, 15, 15, 15, 15, 15, 15, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 27,
16, 16, 16, 16, 16, 16, 16, 16,
};
#ifndef QT_NO_UNICODETABLES
static const Q_UINT8 ui_01[] = {
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
16, 15, 16, 15, 16, 15, 16, 15,
16, 15, 16, 15, 16, 15, 16, 15,
16, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 15, 16, 15, 16, 15, 16, 16,
16, 15, 15, 16, 15, 16, 15, 15,
16, 15, 15, 15, 16, 16, 15, 15,
15, 15, 16, 15, 15, 16, 15, 15,
15, 16, 16, 16, 15, 15, 16, 15,
15, 16, 15, 16, 15, 16, 15, 15,
16, 15, 16, 16, 15, 16, 15, 15,
16, 15, 15, 15, 16, 15, 16, 15,
15, 16, 16, 19, 15, 16, 16, 16,
19, 19, 19, 19, 15, 17, 16, 15,
17, 16, 15, 17, 16, 15, 16, 15,
16, 15, 16, 15, 16, 15, 16, 15,
16, 15, 16, 15, 16, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
16, 15, 17, 16, 15, 16, 15, 15,
15, 16, 15, 16, 15, 16, 15, 16,
};
static const Q_UINT8 ui_02[] = {
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 0, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 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,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 0, 0,
18, 18, 18, 18, 18, 18, 18, 18,
18, 29, 29, 18, 18, 18, 18, 18,
18, 18, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29,
18, 18, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29,
18, 18, 18, 18, 18, 29, 29, 29,
29, 29, 29, 29, 29, 29, 18, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT8 ui_03[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 29, 29, 0, 0,
0, 0, 18, 0, 0, 0, 26, 0,
0, 0, 0, 0, 29, 29, 15, 26,
15, 15, 15, 0, 15, 0, 15, 15,
16, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 0,
16, 16, 15, 15, 15, 16, 16, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
16, 16, 16, 16, 15, 16, 27, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT8 ui_04[] = {
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 30, 1, 1, 1, 1, 0,
3, 3, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 15, 16, 15, 16, 15, 16, 15,
16, 15, 16, 15, 16, 15, 16, 0,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 0, 0,
15, 16, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT8 ui_05[] = {
15, 16, 15, 16, 15, 16, 15, 16,
15, 16, 15, 16, 15, 16, 15, 16,
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, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0,
0, 18, 26, 26, 26, 26, 26, 26,
0, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
0, 26, 21, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 1, 1, 1, 26, 1,
26, 1, 1, 26, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 0, 0, 0, 0, 0,
19, 19, 19, 26, 26, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT8 ui_06[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 26, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 26, 0, 0, 0, 26,
0, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 0, 0, 0, 0, 0,
18, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 26, 26, 26, 26, 19, 19,
1, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 26, 19, 1, 1,
1, 1, 1, 1, 1, 11, 3, 1,
1, 1, 1, 1, 1, 18, 18, 1,
1, 30, 1, 1, 1, 1, 0, 0,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 19, 19, 19, 30, 30, 0,
};
static const Q_UINT8 ui_07[] = {
26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 0, 11,
19, 1, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 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,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 19, 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,
};
static const Q_UINT8 ui_08[] = {
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,
@@ -11022,6810 +11026,6952 @@ static const Q_UINT16 case_1E[] = {
0x1ef1, 0x1ef0, 0x1ef3, 0x1ef2, 0x1ef5, 0x1ef4, 0x1ef7, 0x1ef6,
0x1ef9, 0x1ef8, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT16 case_1F[] = {
0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f,
0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0, 0,
0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0, 0,
0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f,
0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f,
0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0, 0,
0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0, 0,
0, 0x1f59, 0, 0x1f5b, 0, 0x1f5d, 0, 0x1f5f,
0, 0x1f51, 0, 0x1f53, 0, 0x1f55, 0, 0x1f57,
0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f,
0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb,
0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0, 0,
0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f,
0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f,
0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97,
0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf,
0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7,
0x1fb8, 0x1fb9, 0, 0x1fbc, 0, 0, 0, 0,
0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0, 0x399, 0,
0, 0, 0, 0x1fcc, 0, 0, 0, 0,
0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0, 0, 0,
0x1fd8, 0x1fd9, 0, 0, 0, 0, 0, 0,
0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0, 0, 0, 0,
0x1fe8, 0x1fe9, 0, 0, 0, 0x1fec, 0, 0,
0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0, 0, 0,
0, 0, 0, 0x1ffc, 0, 0, 0, 0,
0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0, 0, 0,
};
static const Q_UINT16 case_21[] = {
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, 0x3c9, 0,
0, 0, 0x6b, 0xe5, 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,
0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167,
0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f,
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,
};
static const Q_UINT16 case_24[] = {
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, 0x24d0, 0x24d1,
0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9,
0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1,
0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9,
0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd,
0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5,
0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd,
0x24ce, 0x24cf, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const Q_UINT16 case_FF[] = {
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, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
0xff58, 0xff59, 0xff5a, 0, 0, 0, 0, 0,
0, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27,
0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f,
0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37,
0xff38, 0xff39, 0xff3a, 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,
};
static const Q_UINT16 * const case_info[256] = {
case_00, case_01, case_02, case_03, case_04, case_05, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, case_1E, case_1F,
0, case_21, 0, 0, case_24, 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, 0, 0, 0, case_FF,
};
// 39162 bytes
static const Q_INT8 num_00[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 2, 3, -1, -1, -1, -1,
-1, 1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_06[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_09[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_0B[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 1,
2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_0D[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_0E[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_0F[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_10[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_13[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_17[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_18[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_20[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
0, -1, -1, -1, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 num_24[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 3, 4, 5, 6, 7, 8,
9, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 1, 2, 3, 4,
5, 6, 7, 8, 9, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 3, 4, 5, 6, 7, 8,
9, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 0, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 1, 2, 3,
4, 5, 6, 7, 8, 9, -1, -1,
};
static const Q_INT8 num_27[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 1, 2,
3, 4, 5, 6, 7, 8, 9, -1,
1, 2, 3, 4, 5, 6, 7, 8,
9, -1, 1, 2, 3, 4, 5, 6,
7, 8, 9, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
};
static const Q_INT8 * const decimal_info[256] = {
num_00, 0, 0, 0, 0, 0, num_06, 0,
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 &aring;) 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.
The following characters are normative in Unicode:
\value Mark_NonSpacing Unicode class name Mn
\value Mark_SpacingCombining Unicode class name Mc
\value Mark_Enclosing Unicode class name Me
\value Number_DecimalDigit Unicode class name Nd
\value Number_Letter Unicode class name Nl
\value Number_Other Unicode class name No
\value Separator_Space Unicode class name Zs
\value Separator_Line Unicode class name Zl
\value Separator_Paragraph Unicode class name Zp
\value Other_Control Unicode class name Cc
\value Other_Format Unicode class name Cf
\value Other_Surrogate Unicode class name Cs
\value Other_PrivateUse Unicode class name Co
\value Other_NotAssigned Unicode class name Cn
The following categories are informative in Unicode:
\value Letter_Uppercase Unicode class name Lu
\value Letter_Lowercase Unicode class name Ll
\value Letter_Titlecase Unicode class name Lt
\value Letter_Modifier Unicode class name Lm
\value Letter_Other Unicode class name Lo
\value Punctuation_Connector Unicode class name Pc
\value Punctuation_Dash Unicode class name Pd
\value Punctuation_Open Unicode class name Ps
\value Punctuation_Close Unicode class name Pe
\value Punctuation_InitialQuote Unicode class name Pi
\value Punctuation_FinalQuote Unicode class name Pf
\value Punctuation_Other Unicode class name Po
\value Symbol_Math Unicode class name Sm
\value Symbol_Currency Unicode class name Sc
\value Symbol_Modifier Unicode class name Sk
\value Symbol_Other Unicode class name So
There are two categories that are specific to Qt:
\value NoCategory used when Qt is dazed and confused and cannot
make sense of anything.
\value Punctuation_Dask old typo alias for Punctuation_Dash
*/
/*!
\enum QChar::Direction
This enum type defines the Unicode direction attributes. See \link
http://www.unicode.org/ the Unicode Standard\endlink for a
description of the values.
In order to conform to C/C++ naming conventions "Dir" is prepended
to the codes used in the Unicode Standard.
*/
/*!
\enum QChar::Decomposition
This enum type defines the Unicode decomposition attributes. See
\link http://www.unicode.org/ the Unicode Standard\endlink for a
description of the values.
*/
/*!
\enum QChar::Joining
This enum type defines the Unicode joining attributes. See \link
http://www.unicode.org/ the Unicode Standard\endlink for a
description of the values.
*/
/*!
\enum QChar::CombiningClass
This enum type defines names for some of the Unicode combining
classes. See \link http://www.unicode.org/ the Unicode
Standard\endlink for a description of the values.
*/
/*!
\fn void QChar::setCell( uchar cell )
\internal
*/
/*!
\fn void QChar::setRow( uchar row )
\internal
*/
/*!
\fn QChar::QChar()
Constructs a null QChar (one that isNull()).
*/
/*!
\fn QChar::QChar( char c )
Constructs a QChar corresponding to ASCII/Latin1 character \a c.
*/
/*!
\fn QChar::QChar( uchar c )
Constructs a QChar corresponding to ASCII/Latin1 character \a c.
*/
/*!
\fn QChar::QChar( uchar c, uchar r )
Constructs a QChar for Unicode cell \a c in row \a r.
*/
/*!
\fn QChar::QChar( const QChar& c )
Constructs a copy of \a c. This is a deep copy, if such a
lightweight object can be said to have deep copies.
*/
/*!
\fn QChar::QChar( ushort rc )
Constructs a QChar for the character with Unicode code point \a rc.
*/
/*!
\fn QChar::QChar( short rc )
Constructs a QChar for the character with Unicode code point \a rc.
*/
/*!
\fn QChar::QChar( uint rc )
Constructs a QChar for the character with Unicode code point \a rc.
*/
/*!
\fn QChar::QChar( int rc )
Constructs a QChar for the character with Unicode code point \a rc.
*/
/*!
\fn bool QChar::networkOrdered ()
\obsolete
Returns TRUE if this character is in network byte order (MSB
first); otherwise returns FALSE. This is platform dependent.
*/
/*!
\fn bool QChar::isNull() const
Returns TRUE if the character is the Unicode character 0x0000,
i.e. ASCII NUL; otherwise returns FALSE.
*/
/*!
\fn uchar QChar::cell () const
Returns the cell (least significant byte) of the Unicode
character.
*/
/*!
\fn uchar QChar::row () const
Returns the row (most significant byte) of the Unicode character.
*/
/*!
Returns TRUE if the character is a printable character; otherwise
returns FALSE. This is any character not of category Cc or Cn.
Note that this gives no indication of whether the character is
available in a particular \link QFont font\endlink.
*/
bool QChar::isPrint() const
{
Category c = ::category( *this );
return !(c == Other_Control || c == Other_NotAssigned);
}
/*!
Returns TRUE if the character is a separator character
(Separator_* categories); otherwise returns FALSE.
*/
bool QChar::isSpace() const
{
if( ucs >= 9 && ucs <=13 ) return TRUE;
Category c = ::category( *this );
return c >= Separator_Space && c <= Separator_Paragraph;
}
/*!
Returns TRUE if the character is a mark (Mark_* categories);
otherwise returns FALSE.
*/
bool QChar::isMark() const
{
Category c = ::category( *this );
return c >= Mark_NonSpacing && c <= Mark_Enclosing;
}
/*!
Returns TRUE if the character is a punctuation mark (Punctuation_*
categories); otherwise returns FALSE.
*/
bool QChar::isPunct() const
{
Category c = ::category( *this );
return (c >= Punctuation_Connector && c <= Punctuation_Other);
}
/*!
Returns TRUE if the character is a letter (Letter_* categories);
otherwise returns FALSE.
*/
bool QChar::isLetter() const
{
Category c = ::category( *this );
return (c >= Letter_Uppercase && c <= Letter_Other);
}
/*!
Returns TRUE if the character is a number (of any sort - Number_*
categories); otherwise returns FALSE.
\sa isDigit()
*/
bool QChar::isNumber() const
{
Category c = ::category( *this );
return c >= Number_DecimalDigit && c <= Number_Other;
}
/*!
Returns TRUE if the character is a letter or number (Letter_* or
Number_* categories); otherwise returns FALSE.
*/
bool QChar::isLetterOrNumber() const
{
Category c = ::category( *this );
return (c >= Letter_Uppercase && c <= Letter_Other)
|| (c >= Number_DecimalDigit && c <= Number_Other);
}
/*!
Returns TRUE if the character is a decimal digit
(Number_DecimalDigit); otherwise returns FALSE.
*/
bool QChar::isDigit() const
{
return (::category( *this ) == Number_DecimalDigit);
}
/*!
Returns TRUE if the character is a symbol (Symbol_* categories);
otherwise returns FALSE.
*/
bool QChar::isSymbol() const
{
Category c = ::category( *this );
return c >= Symbol_Math && c <= Symbol_Other;
}
/*!
Returns the numeric value of the digit, or -1 if the character is
not a digit.
*/
int QChar::digitValue() const
{
#ifndef QT_NO_UNICODETABLES
const Q_INT8 *dec_row = decimal_info[row()];
if( !dec_row )
return -1;
return dec_row[cell()];
#else
// ##### just latin1
if ( ucs < '0' || ucs > '9' )
return -1;
else
return ucs - '0';
#endif
}
/*!
Returns the character category.
\sa Category
*/
QChar::Category QChar::category() const
{
return ::category( *this );
}
/*!
Returns the character's direction.
\sa Direction
*/
QChar::Direction QChar::direction() const
{
return ::direction( *this );
}
/*!
\warning This function is not supported (it may change to use
Unicode character classes).
Returns information about the joining properties of the character
(needed for example, for Arabic).
*/
QChar::Joining QChar::joining() const
{
#ifndef QT_NO_UNICODETABLES
const Q_UINT8 *rowp = direction_info[row()];
if ( !rowp )
return QChar::OtherJoining;
return (Joining) ((*(rowp+cell()) >> 5) &0x3);
#else
return OtherJoining;
#endif
}
/*!
Returns TRUE if the character is a mirrored character (one that
should be reversed if the text direction is reversed); otherwise
returns FALSE.
*/
bool QChar::mirrored() const
{
return ::mirrored( *this );
}
/*!
Returns the mirrored character if this character is a mirrored
character, otherwise returns the character itself.
*/
QChar QChar::mirroredChar() const
{
#ifndef QT_NO_UNICODETABLES
if(!::mirrored( *this ))
return *this;
int i;
int c = unicode();
for (i = 0; i < symmetricPairsSize; i ++) {
if (symmetricPairs[i] == c)
return symmetricPairs[(i%2) ? (i-1) : (i+1)];
}
#endif
return *this;
}
#ifndef QT_NO_UNICODETABLES
// ### REMOVE ME 4.0
static QString shared_decomp;
#endif
/*!
\nonreentrant
Decomposes a character into its parts. Returns QString::null if no
decomposition exists.
*/
const QString &QChar::decomposition() const
{
#ifndef QT_NO_UNICODETABLES
const Q_UINT16 *r = decomposition_info[row()];
if(!r) return QString::null;
Q_UINT16 pos = r[cell()];
if(!pos) return QString::null;
pos+=2;
QString s;
Q_UINT16 c;
while((c = decomposition_map[pos++]) != 0) s += QChar(c);
// ### In 4.0, return s, and not shared_decomp. shared_decomp
// prevents this function from being reentrant.
shared_decomp = s;
return shared_decomp;
#else
return QString::null;
#endif
}
/*!
Returns the tag defining the composition of the character. Returns
QChar::Single if no decomposition exists.
*/
QChar::Decomposition QChar::decompositionTag() const
{
#ifndef QT_NO_UNICODETABLES
const Q_UINT16 *r = decomposition_info[row()];
if(!r) return QChar::Single;
Q_UINT16 pos = r[cell()];
if(!pos) return QChar::Single;
return (QChar::Decomposition) decomposition_map[pos];
#else
return Single; // ########### FIX eg. just latin1
#endif
}
/*!
Returns the combining class for the character as defined in the
Unicode standard. This is mainly useful as a positioning hint for
marks attached to a base character.
The Qt text rendering engine uses this information to correctly
position non spacing marks around a base character.
*/
unsigned char QChar::combiningClass() const
{
#ifndef QT_NO_UNICODETABLES
const Q_UINT8 *rowp = combining_info[row()];
if ( !rowp )
return 0;
return *(rowp+cell());
#else
return 0;
#endif
}
/*!
Returns the lowercase equivalent if the character is uppercase;
otherwise returns the character itself.
*/
QChar QChar::lower() const
{
return ::lower( *this );
}
/*!
Returns the uppercase equivalent if the character is lowercase;
otherwise returns the character itself.
*/
QChar QChar::upper() const
{
return ::upper( *this );
}
/*!
\fn QChar::operator char() const
Returns the Latin1 character equivalent to the QChar, or 0. This
is mainly useful for non-internationalized software.
\sa unicode()
*/
/*!
\fn ushort QChar::unicode() const
Returns the numeric Unicode value equal to the QChar. Normally,
you should use QChar objects as they are equivalent, but for some
low-level tasks (e.g. indexing into an array of Unicode
information), this function is useful.
*/
/*!
\fn ushort & QChar::unicode()
\overload
Returns a reference to the numeric Unicode value equal to the
QChar.
*/
/*****************************************************************************
Documentation of QChar related functions
*****************************************************************************/
/*!
\fn bool operator==( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if \a c1 and \a c2 are the same Unicode character;
otherwise returns FALSE.
*/
/*!
\fn bool operator==( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if \a c is the ASCII/Latin1 character \a ch;
otherwise returns FALSE.
*/
/*!
\fn bool operator==( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if \a c is the ASCII/Latin1 character \a ch;
otherwise returns FALSE.
*/
/*!
\fn int operator!=( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if \a c1 and \a c2 are not the same Unicode
character; otherwise returns FALSE.
*/
/*!
\fn int operator!=( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if \a c is not the ASCII/Latin1 character \a ch;
otherwise returns FALSE.
*/
/*!
\fn int operator!=( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if \a c is not the ASCII/Latin1 character \a ch;
otherwise returns FALSE.
*/
/*!
\fn int operator<=( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if the numeric Unicode value of \a c1 is less than
that of \a c2, or they are the same Unicode character; otherwise
returns FALSE.
*/
/*!
\fn int operator<=( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of \a c is less than or
equal to that of the ASCII/Latin1 character \a ch; otherwise
returns FALSE.
*/
/*!
\fn int operator<=( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of the ASCII/Latin1
character \a ch is less than or equal to that of \a c; otherwise
returns FALSE.
*/
/*!
\fn int operator>=( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if the numeric Unicode value of \a c1 is greater than
that of \a c2, or they are the same Unicode character; otherwise
returns FALSE.
*/
/*!
\fn int operator>=( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of \a c is greater than
or equal to that of the ASCII/Latin1 character \a ch; otherwise
returns FALSE.
*/
/*!
\fn int operator>=( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of the ASCII/Latin1
character \a ch is greater than or equal to that of \a c;
otherwise returns FALSE.
*/
/*!
\fn int operator<( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if the numeric Unicode value of \a c1 is less than
that of \a c2; otherwise returns FALSE.
*/
/*!
\fn int operator<( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of \a c is less than that
of the ASCII/Latin1 character \a ch; otherwise returns FALSE.
*/
/*!
\fn int operator<( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of the ASCII/Latin1
character \a ch is less than that of \a c; otherwise returns
FALSE.
*/
/*!
\fn int operator>( QChar c1, QChar c2 )
\relates QChar
Returns TRUE if the numeric Unicode value of \a c1 is greater than
that of \a c2; otherwise returns FALSE.
*/
/*!
\fn int operator>( QChar c, char ch )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of \a c is greater than
that of the ASCII/Latin1 character \a ch; otherwise returns FALSE.
*/
/*!
\fn int operator>( char ch, QChar c )
\overload
\relates QChar
Returns TRUE if the numeric Unicode value of the ASCII/Latin1
character \a ch is greater than that of \a c; otherwise returns
FALSE.
*/
#ifndef QT_NO_UNICODETABLES
// small class used internally in QString::Compose()
class QLigature
{
public:
QLigature( QChar c );
Q_UINT16 first() { cur = ligatures; return cur ? *cur : 0; }
Q_UINT16 next() { return cur && *cur ? *(cur++) : 0; }
Q_UINT16 current() { return cur ? *cur : 0; }
int match(QString & str, unsigned int index);
QChar head();
QChar::Decomposition tag();
private:
Q_UINT16 *ligatures;
Q_UINT16 *cur;
};
QLigature::QLigature( QChar c )
{
const Q_UINT16 *r = ligature_info[c.row()];
if( !r )
ligatures = 0;
else
{
const Q_UINT16 pos = r[c.cell()];
ligatures = (Q_UINT16 *)&(ligature_map[pos]);
}
cur = ligatures;
}
QChar QLigature::head()
{
if(current())
return QChar(decomposition_map[current()+1]);
return QChar::null;
}
QChar::Decomposition QLigature::tag()
{
if(current())
return (QChar::Decomposition) decomposition_map[current()];
return QChar::Canonical;
}
int QLigature::match(QString & str, unsigned int index)
{
unsigned int i=index;
if(!current()) return 0;
Q_UINT16 lig = current() + 2;
Q_UINT16 ch;
while ((i < str.length()) && (ch = decomposition_map[lig])) {
if (str[(int)i] != QChar(ch))
return 0;
i++;
lig++;
}
if (!decomposition_map[lig])
{
return i-index;
}
return 0;
}
// this function is just used in QString::compose()
static inline bool format(QChar::Decomposition tag, QString & str,
int index, int len)
{
unsigned int l = index + len;
unsigned int r = index;
bool left = FALSE, right = FALSE;
left = ((l < str.length()) &&
((str[(int)l].joining() == QChar::Dual) ||
(str[(int)l].joining() == QChar::Right)));
if (r > 0) {
r--;
//printf("joining(right) = %d\n", str[(int)r].joining());
right = (str[(int)r].joining() == QChar::Dual);
}
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 = internalAsciiToUnicode(str,&l);
- Q2HELPER(stat_construct_charstar_size+=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 = 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
\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( ushort 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.
*/
/*!
\overload
\a a is assumed to be in the Latin1 character set.
*/
QString QString::arg( char a, int fieldwidth ) const
{
QString c;
c += a;
return arg( c, fieldwidth );
}
/*!
\overload
*/
QString QString::arg( QChar a, int fieldwidth ) const
{
QString c;
c += a;
return arg( c, fieldwidth );
}
/*!
\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;
*(st++) = l;
*(st++) = l;
*(st++) = l;
*(st++) = l;
*(st++) = l;
*(st++) = l;
*(st++) = l;
}
const QChar *uc = pattern.unicode();
if ( cs ) {
while( l-- ) {
skiptable[ uc->cell() ] = l;
uc++;
}
} else {
while( l-- ) {
skiptable[ ::lower( *uc ).cell() ] = l;
uc++;
}
}
}
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"
\endcode
If \a start or \a end is negative, we count fields from the right
of the string, the right-most field being -1, the one from
right-most field being -2, and so on.
\code
QString csv( "forename,middlename,surname,phone" );
QString s = csv.section( ',', -3, -2 ); // s == "middlename,surname"
QString path( "/usr/local/bin/myapp" ); // First field is empty
QString s = path.section( '/', -1 ); // s == "myapp"
\endcode
\sa QStringList::split()
*/
/*!
\overload
This function returns a section of the string.
This string is treated as a sequence of fields separated by the
string, \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 data( "forename**middlename**surname**phone" );
QString s = data.section( "**", 2, 2 ); // s == "surname"
\endcode
If \a start or \a end is negative, we count fields from the right
of the string, the right-most field being -1, the one from
right-most field being -2, and so on.
\code
QString data( "forename**middlename**surname**phone" );
QString s = data.section( "**", -3, -2 ); // s == "middlename**surname"
\endcode
\sa QStringList::split()
*/
QString QString::section( const QString &sep, int start, int end, int flags ) const
{
const QChar *uc = unicode();
if ( !uc )
return QString();
QString _sep = (flags & SectionCaseInsensitiveSeps) ? sep.lower() : sep;
const QChar *uc_sep = _sep.unicode();
if(!uc_sep)
return QString();
bool match = FALSE, last_match = TRUE;
//find start
int n = length(), sep_len = _sep.length();
const QChar *begin = start < 0 ? uc + n : uc;
while(start) {
match = FALSE;
int c = 0;
for(const QChar *tmp = start < 0 ? begin - sep_len : begin;
c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
if(flags & SectionCaseInsensitiveSeps) {
if( ::lower( *tmp ) != *(uc_sep + c))
break;
} else {
if( *tmp != *(uc_sep + c) )
break;
}
if(c == sep_len - 1) {
match = TRUE;
break;
}
}
if(start > 0 && (flags & SectionSkipEmpty) && match && last_match)
match = FALSE;
last_match = match;
if(start < 0) {
if(match) {
begin -= sep_len;
if(!++start)
break;
} else {
if(start == -1 && begin == uc)
break;
begin--;
}
} else {
if(match) {
if(!--start)
break;
begin += sep_len;
} else {
if(start == 1 && begin == uc + n)
break;
begin++;
}
}
if(begin > uc + n || begin < uc)
return QString();
}
if(match && !(flags & SectionIncludeLeadingSep))
begin+=sep_len;
if(begin > uc + n || begin < uc)
return QString();
//now find last
match = FALSE;
const QChar *last = end < 0 ? uc + n : uc;
if(end == -1) {
int c = 0;
for(const QChar *tmp = end < 0 ? last - sep_len : last;
c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
if(flags & SectionCaseInsensitiveSeps) {
if( ::lower( *tmp ) != *(uc_sep + c))
break;
} else {
if( *tmp != *(uc_sep + c) )
break;
}
if(c == sep_len - 1) {
match = TRUE;
break;
}
}
} else {
end++;
last_match = TRUE;
while(end) {
match = FALSE;
int c = 0;
for(const QChar *tmp = end < 0 ? last - sep_len : last;
c < sep_len && tmp < uc + n && tmp >= uc; tmp++, c++) {
if(flags & SectionCaseInsensitiveSeps) {
if( ::lower( *tmp ) != *(uc_sep + c))
break;
} else {
if( *tmp != *(uc_sep + c) )
break;
}
if(c == sep_len - 1) {
match = TRUE;
break;
}
}
if(end > 0 && (flags & SectionSkipEmpty) && match && last_match)
match = FALSE;
last_match = match;
if(end < 0) {
if(match) {
if(!++end)
break;
last -= sep_len;
} else {
last--;
}
} else {
if(match) {
last += sep_len;
if(!--end)
break;
} else {
last++;
}
}
if(last >= uc + n) {
last = uc + n;
break;
} else if(last < uc) {
return QString();
}
}
}
if(match && !(flags & SectionIncludeTrailingSep))
last -= sep_len;
if(last < uc || last > uc + n || begin >= last)
return QString();
//done
return QString(begin, last - begin);
}
#ifndef QT_NO_REGEXP
class section_chunk {
public:
section_chunk(int l, QString s) { length = l; string = s; }
int length;
QString string;
};
/*!
\overload
This function returns a section of the string.
This string is treated as a sequence of fields separated by the
regular expression, \a reg. 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 line( "forename\tmiddlename surname \t \t phone" );
QRegExp sep( "\s+" );
QString s = line.section( sep, 2, 2 ); // s == "surname"
\endcode
If \a start or \a end is negative, we count fields from the right
of the string, the right-most field being -1, the one from
right-most field being -2, and so on.
\code
QString line( "forename\tmiddlename surname \t \t phone" );
QRegExp sep( "\\s+" );
QString s = line.section( sep, -3, -2 ); // s == "middlename surname"
\endcode
\warning Using this QRegExp version is much more expensive than
the overloaded string and character versions.
\sa QStringList::split() simplifyWhiteSpace()
*/
QString QString::section( const QRegExp &reg, int start, int end, int flags ) const
{
const QChar *uc = unicode();
if(!uc)
return QString();
QRegExp sep(reg);
sep.setCaseSensitive(!(flags & SectionCaseInsensitiveSeps));
QPtrList<section_chunk> l;
l.setAutoDelete(TRUE);
int n = length(), m = 0, last_m = 0, last = 0, last_len = 0;
while( ( m = sep.search( *this, m ) ) != -1 ) {
l.append(new section_chunk(last_len, QString(uc + last_m, m - last_m)));
last_m = m;
last_len = sep.matchedLength();
if((m += sep.matchedLength()) >= n) {
last = 1;
break;
}
}
if(!last)
l.append(new section_chunk(last_len, QString(uc + last_m, n - last_m)));
if(start < 0)
start = l.count() + start;
if(end == -1)
end = l.count();
else if(end < 0)
end = l.count() + end;
int i = 0;
QString ret;
for ( section_chunk *chk=l.first(); chk; chk=l.next(), i++ ) {
if((flags & SectionSkipEmpty) && chk->length == (int)chk->string.length()) {
if(i <= start)
start++;
end++;
}
if(i == start) {
ret = (flags & SectionIncludeLeadingSep) ? chk->string : chk->string.mid(chk->length);
} else if(i > start) {
ret += chk->string;
}
if(i == end) {
if((chk=l.next()) && flags & SectionIncludeTrailingSep)
ret += chk->string.left(chk->length);
break;
}
}
return ret;
}
#endif
/*!
\fn QString QString::section( char sep, int start, int end = 0xffffffff, int flags = SectionDefault ) const
\overload
*/
/*!
\fn QString QString::section( const char *sep, int start, int end = 0xffffffff, int flags = SectionDefault ) const
\overload
*/
/*!
Returns the number of times the character \a c occurs in the
string.
If \a cs is TRUE, the search is case sensitive; otherwise the
search is case insensitive.
\code
QString string( "Trolltech and Qt" );
int i = string.contains( 't', FALSE ); // i == 3
\endcode
*/
int QString::contains( QChar c, bool cs ) const
{
int count = 0;
const QChar *uc = unicode();
if ( !uc )
return 0;
int n = length();
if ( cs ) {
while ( n-- )
if ( *uc++ == c )
count++;
} else {
c = ::lower( c );
while ( n-- ) {
if ( ::lower( *uc ) == c )
count++;
uc++;
}
}
return count;
}
/*!
\overload
Returns the number of times the string \a str occurs in the string.
If \a cs is TRUE, the search is case sensitive; otherwise the
search is case insensitive.
*/
int QString::contains( const char* str, bool cs ) const
{
return contains( QString(str), cs );
}
/*!
\fn int QString::contains( char c, bool cs ) const
\overload
*/
/*!
\fn int QString::find( char c, int index, bool cs ) const
\overload
Find character \a c starting from position \a index.
If \a cs is TRUE, the search is case sensitive; otherwise the
search is case insensitive.
*/
/*!
\fn int QString::findRev( char c, int index, bool cs ) const
\overload
Find character \a c starting from position \a index and working
backwards.
If \a cs is TRUE, the search is case sensitive; otherwise the
search is case insensitive.
*/
/*!
\overload
Returns the number of times \a str occurs in the string.
If \a cs is TRUE, the search is case sensitive; otherwise the
search is case insensitive.
This function counts overlapping strings, so in the example below,
there are two instances of "ana" in "bananas".
\code
QString str( "bananas" );
int i = str.contains( "ana" ); // i == 2
\endcode
\sa findRev()
*/
int QString::contains( const QString &str, bool cs ) const
{
if ( isNull() )
return 0;
int count = 0;
uint skiptable[0x100];
bm_init_skiptable( str, skiptable, cs );
int i = -1;
// use boyer-moore for the ultimate speed experience
while ( ( i = bm_find( *this, i+1, str, skiptable, cs ) ) != -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.
\code
QString s = "Pineapple";
QString t = s.left( 4 ); // t == "Pine"
\endcode
\sa right(), mid(), isEmpty()
*/
QString QString::left( uint len ) const
{
if ( isEmpty() ) {
return QString();
} else if ( len == 0 ) { // ## just for 1.x compat:
return fromLatin1( "" );
} else if ( len >= length() ) {
return *this;
} else {
QString s( len, TRUE );
memcpy( s.d->unicode, d->unicode, len * sizeof(QChar) );
s.d->len = len;
return s;
}
}
/*!
Returns a string that contains the \a len rightmost characters of
the string.
If \a len is greater than the length of the string then the whole
string is returned.
\code
QString string( "Pineapple" );
QString t = string.right( 5 ); // t == "apple"
\endcode
\sa left(), mid(), isEmpty()
*/
QString QString::right( uint len ) const
{
if ( isEmpty() ) {
return QString();
} else if ( len == 0 ) { // ## just for 1.x compat:
return fromLatin1( "" );
} else {
uint l = length();
if ( len >= l )
return *this;
QString s( len, TRUE );
memcpy( s.d->unicode, d->unicode+(l-len), len*sizeof(QChar) );
s.d->len = len;
return s;
}
}
/*!
Returns a string that contains the \a len characters of this
string, starting at position \a index.
Returns a null string if the string is empty or \a index is out of
range. Returns the whole string from \a index if \a index + \a len
exceeds the length of the string.
\code
QString s( "Five pineapples" );
QString t = s.mid( 5, 4 ); // t == "pine"
\endcode
\sa left(), right()
*/
QString QString::mid( uint index, uint len ) const
{
uint slen = length();
if ( isEmpty() || index >= slen ) {
return QString();
} else if ( len == 0 ) { // ## just for 1.x compat:
return fromLatin1( "" );
} else {
if ( len > slen-index )
len = slen - index;
if ( index == 0 && len == slen )
return *this;
register const QChar *p = unicode()+index;
QString s( len, TRUE );
memcpy( s.d->unicode, p, len * sizeof(QChar) );
s.d->len = len;
return s;
}
}
/*!
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-- ) {
+ 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-- ) {
+ 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
Replaces every occurrence of \a c1 with the char \a c2.
Returns a reference to the string.
*/
QString &QString::replace( QChar c1, QChar c2 )
{
real_detach();
uint i = 0;
while ( i < d->len ) {
if ( d->unicode[i] == c1 )
d->unicode[i] = c2;
i++;
}
return *this;
}
#ifndef QT_NO_REGEXP_CAPTURE
/*! \overload
Removes every occurrence of the regular expression \a rx in the
string. Returns a reference to the string.
This is the same as replace(\a rx, "").
*/
QString &QString::remove( const QRegExp & rx )
{
return replace( rx, QString::null );
}
#endif
/*! \overload
Removes every occurrence of \a str in the string. Returns a
reference to the string.
*/
QString &QString::remove( const char *str )
{
return remove( QString::fromLatin1(str) );
}
/*!
Replaces \a len characters from the string with \a s, starting at
position \a index, and returns a reference to the string.
If \a index is beyond the length of the string, nothing is deleted
and \a s is appended at the end of the string. If \a index is
valid, but \a index + \a len is beyond the end of the string,
the string is truncated at position \a index, then \a s is
appended at the end.
\code
QString string( "Say yes!" );
string = string.replace( 4, 3, "NO" );
// string == "Say NO!"
\endcode
\sa insert(), remove()
*/
QString &QString::replace( uint index, uint len, const QString &s )
{
return replace( index, len, s.unicode(), s.length() );
}
/*! \overload
This is the same as replace(\a index, \a len, QString(\a c)).
*/
QString &QString::replace( uint index, uint len, QChar c )
{
return replace( index, len, &c, 1 );
}
/*! \overload
\fn QString &QString::replace( uint index, uint len, char c )
This is the same as replace(\a index, \a len, QChar(\a c)).
*/
/*!
\overload
Replaces \a len characters with \a slen characters of QChar data
from \a s, starting at position \a index, and returns a reference
to the string.
\sa insert(), remove()
*/
QString &QString::replace( uint index, uint len, const QChar* s, uint slen )
{
real_detach();
if ( len == slen && index + len <= length() ) {
// Optimized common case: replace without size change
memcpy( d->unicode+index, s, len * sizeof(QChar) );
} else if ( s >= d->unicode && (uint)(s - d->unicode) < d->maxl ) {
// Part of me - take a copy.
QChar *tmp = QT_ALLOC_QCHAR_VEC( slen );
memcpy( tmp, s, slen * sizeof(QChar) );
replace( index, len, tmp, slen );
QT_DELETE_QCHAR_VEC( tmp );
} else {
remove( index, len );
insert( index, s, slen );
}
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
QString s = "a,b,c";
s.replace( QChar(','), " or " );
// s == "a or b or c"
\endcode
*/
QString &QString::replace( QChar c, const QString & after )
{
return replace( QString( c ), after );
}
/*! \overload
\fn QString &QString::replace( char c, const QString & after )
Replaces every occurrence of the character \a c in the string
with \a after. Returns a reference to the string.
*/
/*! \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
QString s = "Greek is Greek";
s.replace( "Greek", "English" );
// s == "English is English"
\endcode
*/
QString &QString::replace( const QString & before, const QString & after )
{
if ( before == after || isNull() )
return *this;
real_detach();
int index = 0;
uint skiptable[256];
bm_init_skiptable( before, skiptable, TRUE );
const int bl = before.length();
const int al = after.length();
if ( bl == al ) {
if ( bl ) {
const QChar *auc = after.unicode();
while( (index = bm_find(*this, index, before, skiptable, TRUE) ) != -1 ) {
memcpy( d->unicode+index, auc, al*sizeof(QChar) );
index += bl;
}
}
} else if ( al < bl ) {
const QChar *auc = after.unicode();
uint to = 0;
uint movestart = 0;
uint num = 0;
while( (index = bm_find(*this, index, before, skiptable, TRUE) ) != -1 ) {
if ( num ) {
int msize = index - movestart;
if ( msize > 0 ) {
memmove( d->unicode + to, d->unicode + movestart, msize*sizeof(QChar) );
to += msize;
}
} else {
to = index;
}
if ( al ) {
memcpy( d->unicode+to, auc, al*sizeof(QChar) );
to += al;
}
index += bl;
movestart = index;
num++;
}
if ( num ) {
int msize = d->len - movestart;
if ( msize > 0 )
memmove( d->unicode + to, d->unicode + movestart, msize*sizeof(QChar) );
setLength( d->len - num*(bl-al) );
}
} 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 = bm_find(*this, index, before, skiptable, TRUE);
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 = d->len + adjust;
int moveend = d->len;
if ( newlen > d->len )
setLength( newlen );
while( pos ) {
pos--;
int movestart = indices[pos] + bl;
int insertstart = indices[pos] + pos*(al-bl);
int moveto = insertstart + al;
memmove( d->unicode + moveto, d->unicode + movestart, (moveend - movestart)*sizeof(QChar) );
memcpy( d->unicode + insertstart, after.unicode(), al*sizeof(QChar) );
moveend = movestart-bl;
}
}
}
return *this;
}
#ifndef QT_NO_REGEXP_CAPTURE
/*! \overload
Replaces every occurrence of the regexp \a rx in the string with \a str.
Returns a reference to the string. For example:
\code
QString s = "banana";
s.replace( QRegExp("an"), "" );
// s == "ba"
\endcode
For regexps containing \link qregexp.html#capturing-text capturing
parentheses \endlink, occurrences of <b>\\1</b>, <b>\\2</b>, ...,
in \a str are replaced with \a{rx}.cap(1), cap(2), ...
\code
QString t = "A <i>bon mot</i>.";
t.replace( QRegExp("<i>([^<]*)</i>"), "\\emph{\\1}" );
// t == "A \\emph{bon mot}."
\endcode
\sa find(), findRev(), QRegExp::cap()
*/
QString &QString::replace( const QRegExp &rx, const QString &str )
{
if ( isNull() )
return *this;
real_detach();
QRegExp rx2 = rx;
int index = 0;
int numCaptures = rx2.numCaptures();
int al = str.length();
QRegExp::CaretMode caretMode = QRegExp::CaretAtZero;
if ( numCaptures > 0 ) {
if ( numCaptures > 9 )
numCaptures = 9;
const QChar *uc = str.unicode();
int numBackRefs = 0;
for ( int i = 0; i < al - 1; i++ ) {
if ( uc[i] == '\\' ) {
int no = uc[i + 1].digitValue();
if ( no > 0 && no <= numCaptures )
numBackRefs++;
}
}
/*
This is the harder case where we have back-references. We
don't try to optimize it.
*/
if ( numBackRefs > 0 ) {
int *capturePositions = new int[numBackRefs];
int *captureNumbers = new int[numBackRefs];
int j = 0;
for ( int i = 0; i < al - 1; i++ ) {
if ( uc[i] == '\\' ) {
int no = uc[i + 1].digitValue();
if ( no > 0 && no <= numCaptures ) {
capturePositions[j] = i;
captureNumbers[j] = no;
j++;
}
}
}
while ( index <= (int)length() ) {
index = rx2.search( *this, index, caretMode );
if ( index == -1 )
break;
QString str2 = str;
for ( j = numBackRefs - 1; j >= 0; j-- )
str2.replace( capturePositions[j], 2,
rx2.cap(captureNumbers[j]) );
replace( index, rx2.matchedLength(), str2 );
index += str2.length();
if ( rx2.matchedLength() == 0 ) {
// avoid infinite loop on 0-length matches (e.g., [a-z]*)
index++;
} else if ( index == 0 ) {
caretMode = QRegExp::CaretWontMatch;
}
}
delete[] capturePositions;
delete[] captureNumbers;
return *this;
}
}
/*
This is the simple and optimized case where we don't have
back-references.
*/
while ( index != -1 ) {
struct {
int pos;
int length;
} replacements[2048];
uint pos = 0;
int adjust = 0;
while( pos < 2047 ) {
index = rx2.search( *this, index, caretMode );
if ( index == -1 )
break;
int ml = rx2.matchedLength();
replacements[pos].pos = index;
replacements[pos++].length = ml;
index += ml;
adjust += al - ml;
// avoid infinite loop
if ( !ml )
index++;
}
if ( !pos )
break;
replacements[pos].pos = d->len;
uint newlen = d->len + adjust;
// to continue searching at the right position after we did
// the first round of replacements
if ( index != -1 )
index += adjust;
QChar *newuc = QT_ALLOC_QCHAR_VEC( newlen + 1 );
QChar *uc = newuc;
int copystart = 0;
uint i = 0;
while( i < pos ) {
int copyend = replacements[i].pos;
int size = copyend - copystart;
memcpy( uc, d->unicode + copystart, size*sizeof(QChar) );
uc += size;
memcpy( uc, str.unicode(), al*sizeof( QChar ) );
uc += al;
copystart = copyend + replacements[i].length;
i++;
}
memcpy( uc, d->unicode + copystart,
(d->len - copystart) * sizeof(QChar) );
QT_DELETE_QCHAR_VEC( d->unicode );
d->unicode = newuc;
d->len = newlen;
d->maxl = newlen + 1;
d->setDirty();
caretMode = QRegExp::CaretWontMatch;
}
return *this;
}
#endif
#ifndef QT_NO_REGEXP
/*!
Finds the first match of the regular expression \a rx, starting
from 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.)
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++;
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
\a f with precision \a prec, and returns a reference to the
string.
The format \a f can be 'f', 'F', 'e', 'E', 'g' or 'G'. See \link
#arg-formats arg \endlink() for an explanation of the formats.
*/
QString &QString::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( "QString::setNum: Invalid format char '%c'", f );
f = 'f';
}
#endif
char format[20];
char *fs = format; // generate format string: %.<prec>l<f>
*fs++ = '%';
if ( prec >= 0 ) {
if ( prec > 99 ) // rather than crash in sprintf()
prec = 99;
*fs++ = '.';
if ( prec >= 10 ) {
*fs++ = prec / 10 + '0';
*fs++ = prec % 10 + '0';
} else {
*fs++ = prec + '0';
}
}
*fs++ = 'l';
*fs++ = f;
*fs = '\0';
#ifndef QT_NO_SPRINTF
sprintf( format, n );
return *this;
#else
char buf[512];
::sprintf( buf, format, n ); // snprintf is unfortunately not portable
return setLatin1(buf);
#endif
}
/*!
\fn QString &QString::setNum( float n, char f, int prec )
\overload
Sets the string to the printed value of \a n, formatted in format
\a f with precision \a prec, and returns a reference to the
string.
The format \a f can be 'f', 'F', 'e', 'E', 'g' or 'G'. See \link
#arg-formats arg \endlink() for an explanation of the formats.
*/
/*!
A convenience function that returns a string equivalent of the
number \a n to base \a base, which is 10 by default and must be
between 2 and 36.
\code
long a = 63;
QString str = QString::number( a, 16 ); // str == "3f"
QString str = QString::number( a, 16 ).upper(); // str == "3F"
\endcode
\sa setNum()
*/
QString QString::number( long n, int base )
{
QString s;
s.setNum( n, base );
return s;
}
/*!
\overload
\sa setNum()
*/
QString QString::number( ulong n, int base )
{
QString s;
s.setNum( n, base );
return s;
}
/*!
\overload
\sa setNum()
*/
QString QString::number( int n, int base )
{
QString s;
s.setNum( n, base );
return s;
}
/*!
\overload
A convenience factory function that returns a string
representation of the number \a n to the base \a base, which is 10
by default and must be between 2 and 36.
\sa setNum()
*/
QString QString::number( uint n, int base )
{
QString s;
s.setNum( n, base );
return s;
}
/*!
\overload
Argument \a n is formatted according to the \a f format specified,
which is \c 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
\sa setNum()
*/
QString QString::number( double n, char f, int prec )
{
QString s;
s.setNum( n, f, prec );
return s;
}
/*! \obsolete
Sets the character at position \a index to \a c and expands the
string if necessary, filling with spaces.
This method is redundant in Qt 3.x, because operator[] will expand
the string as necessary.
*/
void QString::setExpand( uint index, QChar c )
{
int spaces = index - d->len;
at(index) = c;
while (spaces-->0)
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.
+
+ 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().
- This function simply calls latin1() and returns the result.
+ \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 );
#if defined(Q_WS_WIN)
int res;
QT_WA( {
const TCHAR* s1 = (TCHAR*)ucs2();
const TCHAR* s2 = (TCHAR*)s.ucs2();
res = CompareStringW( LOCALE_USER_DEFAULT, 0, s1, length(), s2, s.length() );
} , {
QCString s1 = local8Bit();
QCString s2 = s.local8Bit();
res = CompareStringA( LOCALE_USER_DEFAULT, 0, s1.data(), s1.length(), s2.data(), s2.length() );
} );
switch ( res ) {
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
#elif defined(Q_WS_X11)
// declared in <string.h>
int delta = strcoll( local8Bit(), s.local8Bit() );
if ( delta == 0 )
delta = ucstrcmp( *this, s );
return delta;
#else
return ucstrcmp( *this, s );
#endif
}
bool operator==( const QString &s1, const QString &s2 )
{
if ( s1.unicode() == s2.unicode() )
return TRUE;
return (s1.length() == s2.length()) && s1.isNull() == s2.isNull() &&
(memcmp((char*)s1.unicode(),(char*)s2.unicode(),
s1.length()*sizeof(QChar)) == 0 );
}
bool operator!=( const QString &s1, const QString &s2 )
{ return !(s1==s2); }
bool operator<( const QString &s1, const QString &s2 )
{ return ucstrcmp(s1,s2) < 0; }
bool operator<=( const QString &s1, const QString &s2 )
{ return ucstrcmp(s1,s2) <= 0; }
bool operator>( const QString &s1, const QString &s2 )
{ return ucstrcmp(s1,s2) > 0; }
bool operator>=( const QString &s1, const QString &s2 )
{ return ucstrcmp(s1,s2) >= 0; }
bool operator==( const QString &s1, const char *s2 )
{
if ( !s2 )
return s1.isNull();
int len = s1.length();
const QChar *uc = s1.unicode();
while ( len ) {
if ( !(*s2) || uc->unicode() != (uchar) *s2 )
return FALSE;
++uc;
++s2;
--len;
}
return !*s2;
}
bool operator==( const char *s1, const QString &s2 )
{ return (s2 == s1); }
bool operator!=( const QString &s1, const char *s2 )
{ return !(s1==s2); }
bool operator!=( const char *s1, const QString &s2 )
{ return !(s1==s2); }
bool operator<( const QString &s1, const char *s2 )
{ return ucstrcmp(s1,s2) < 0; }
bool operator<( const char *s1, const QString &s2 )
{ return ucstrcmp(s1,s2) < 0; }
bool operator<=( const QString &s1, const char *s2 )
{ return ucstrcmp(s1,s2) <= 0; }
bool operator<=( const char *s1, const QString &s2 )
{ return ucstrcmp(s1,s2) <= 0; }
bool operator>( const QString &s1, const char *s2 )
{ return ucstrcmp(s1,s2) > 0; }
bool operator>( const char *s1, const QString &s2 )
{ return ucstrcmp(s1,s2) > 0; }
bool operator>=( const QString &s1, const char *s2 )
{ return ucstrcmp(s1,s2) >= 0; }
bool operator>=( const char *s1, const QString &s2 )
{ return ucstrcmp(s1,s2) >= 0; }
/*****************************************************************************
Documentation for QString related functions
*****************************************************************************/
/*!
\fn bool operator==( const QString &s1, const QString &s2 )
\relates QString
Returns TRUE if \a s1 is equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) != 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator==( const QString &s1, const char *s2 )
\overload
\relates QString
Returns TRUE if \a s1 is equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) == 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator==( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) == 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator!=( const QString &s1, const QString &s2 )
\relates QString
Returns TRUE if \a s1 is not equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) != 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator!=( const QString &s1, const char *s2 )
\overload
\relates QString
Returns TRUE if \a s1 is not equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) != 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator!=( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is not equal to \a s2; otherwise returns FALSE.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) != 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator<( const QString &s1, const char *s2 )
\relates QString
Returns TRUE if \a s1 is lexically less than \a s2; otherwise returns FALSE.
The comparison is case sensitive.
Equivalent to compare(\a s1, \a s2) \< 0.
*/
/*!
\fn bool operator<( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is lexically less than \a s2; otherwise returns FALSE.
The comparison is case sensitive.
Equivalent to compare(\a s1, \a s2) \< 0.
*/
/*!
\fn bool operator<=( const QString &s1, const char *s2 )
\relates QString
Returns TRUE if \a s1 is lexically less than or equal to \a s2;
otherwise returns FALSE.
The comparison is case sensitive.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1,\a s2) \<= 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator<=( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is lexically less than or equal to \a s2;
otherwise returns FALSE.
The comparison is case sensitive.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) \<= 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator>( const QString &s1, const char *s2 )
\relates QString
Returns TRUE if \a s1 is lexically greater than \a s2; otherwise
returns FALSE.
The comparison is case sensitive.
Equivalent to compare(\a s1, \a s2) \> 0.
*/
/*!
\fn bool operator>( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is lexically greater than \a s2; otherwise
returns FALSE.
The comparison is case sensitive.
Equivalent to compare(\a s1, \a s2) \> 0.
*/
/*!
\fn bool operator>=( const QString &s1, const char *s2 )
\relates QString
Returns TRUE if \a s1 is lexically greater than or equal to \a s2;
otherwise returns FALSE.
The comparison is case sensitive.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) \>= 0.
\sa isNull(), isEmpty()
*/
/*!
\fn bool operator>=( const char *s1, const QString &s2 )
\overload
\relates QString
Returns TRUE if \a s1 is lexically greater than or equal to \a s2;
otherwise returns FALSE.
The comparison is case sensitive.
Note that a null string is not equal to a not-null empty string.
Equivalent to compare(\a s1, \a s2) \>= 0.
\sa isNull(), isEmpty()
*/
/*!
\fn const QString operator+( const QString &s1, const QString &s2 )
\relates QString
Returns a string which is the result of concatenating the string
\a s1 and the string \a s2.
Equivalent to \a {s1}.append(\a s2).
*/
/*!
\fn const QString operator+( const QString &s1, const char *s2 )
\overload
\relates QString
Returns a string which is the result of concatenating the string
\a s1 and character \a s2.
Equivalent to \a {s1}.append(\a s2).
*/
/*!
\fn const QString operator+( const char *s1, const QString &s2 )
\overload
\relates QString
Returns a string which is the result of concatenating the
character \a s1 and string \a s2.
*/
/*!
\fn const QString operator+( const QString &s, char c )
\overload
\relates QString
Returns a string which is the result of concatenating the string
\a s and character \a c.
Equivalent to \a {s}.append(\a c).
*/
/*!
\fn const QString operator+( char c, const QString &s )
\overload
\relates QString
Returns a string which is the result of concatenating the
character \a c and string \a s.
Equivalent to \a {s}.prepend(\a c).
*/
/*****************************************************************************
QString stream functions
*****************************************************************************/
#ifndef QT_NO_DATASTREAM
/*!
\relates QString
Writes the string \a str to the stream \a s.
See also \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator<<( QDataStream &s, const QString &str )
{
if ( s.version() == 1 ) {
QCString l( str.latin1() );
s << l;
}
else {
int byteOrder = s.byteOrder();
const QChar* ub = str.unicode();
if ( ub || s.version() < 3 ) {
static const uint auto_size = 1024;
char t[auto_size];
char *b;
if ( str.length()*sizeof(QChar) > auto_size ) {
b = new char[str.length()*sizeof(QChar)];
} else {
b = t;
}
int l = str.length();
char *c=b;
while ( l-- ) {
if ( byteOrder == QDataStream::BigEndian ) {
*c++ = (char)ub->row();
*c++ = (char)ub->cell();
} else {
*c++ = (char)ub->cell();
*c++ = (char)ub->row();
}
ub++;
}
s.writeBytes( b, sizeof(QChar)*str.length() );
if ( str.length()*sizeof(QChar) > auto_size )
delete [] b;
} else {
// write null marker
s << (Q_UINT32)0xffffffff;
}
}
return s;
}
/*!
\relates QString
Reads a string from the stream \a s into string \a str.
See also \link datastreamformat.html Format of the QDataStream operators \endlink
*/
QDataStream &operator>>( QDataStream &s, QString &str )
{
#ifdef QT_QSTRING_UCS_4
#if defined(Q_CC_GNU)
#warning "operator>> not working properly"
#endif
#endif
if ( s.version() == 1 ) {
QCString l;
s >> l;
str = QString( l );
}
else {
Q_UINT32 bytes;
s >> bytes; // read size of string
if ( bytes == 0xffffffff ) { // null string
str = QString::null;
} else if ( bytes > 0 ) { // not empty
int byteOrder = s.byteOrder();
str.setLength( bytes/2 );
QChar* ch = str.d->unicode;
static const uint auto_size = 1024;
char t[auto_size];
char *b;
if ( bytes > auto_size ) {
b = new char[bytes];
} else {
b = t;
}
s.readRawBytes( b, bytes );
int bt = bytes/2;
char *oldb = b;
while ( bt-- ) {
if ( byteOrder == QDataStream::BigEndian )
*ch++ = (ushort) (((ushort)b[0])<<8) | (uchar)b[1];
else
*ch++ = (ushort) (((ushort)b[1])<<8) | (uchar)b[0];
b += 2;
}
if ( bytes > auto_size )
delete [] oldb;
} else {
str = "";
}
}
return s;
}
#endif // QT_NO_DATASTREAM
/*****************************************************************************
QConstString member functions
*****************************************************************************/
/*!
\class QConstString qstring.h
\reentrant
\ingroup text
\brief The QConstString class provides string objects using constant Unicode data.
In order to minimize copying, highly optimized applications can
use QConstString to provide a QString-compatible object from
existing Unicode data. It is then the programmer's responsibility
to ensure that the Unicode data exists for the entire lifetime of
the QConstString object.
A QConstString is created with the QConstString constructor. The
string held by the object can be obtained by calling string().
*/
/*!
Constructs a QConstString that uses the first \a length Unicode
characters in the array \a unicode. Any attempt to modify copies
of the string will cause it to create a copy of the data, thus it
remains forever unmodified.
The data in \a unicode is not copied. The caller must be able to
guarantee that \a unicode will not be deleted or modified.
*/
QConstString::QConstString( const QChar* unicode, uint length ) :
QString( new QStringData( (QChar*)unicode, length, length ), TRUE )
{
}
/*!
Destroys the QConstString, creating a copy of the data if other
strings are still using it.
*/
QConstString::~QConstString()
{
if ( d->count > 1 ) {
QChar* cp = QT_ALLOC_QCHAR_VEC( d->len );
memcpy( cp, d->unicode, d->len*sizeof(QChar) );
d->unicode = cp;
} else {
d->unicode = 0;
}
// The original d->unicode is now unlinked.
}
/*!
\fn const QString& QConstString::string() const
Returns a constant string referencing the data passed during
construction.
*/
/*!
Returns TRUE if the string starts with \a s; otherwise returns
FALSE.
\code
QString string("Bananas");
bool a = string.startsWith("Ban"); // a == TRUE
\endcode
\sa endsWith()
*/
bool QString::startsWith( const QString& s ) const
{
if ( isNull() )
return s.isNull();
if ( s.length() > length() )
return FALSE;
for ( int i =0; i < (int) s.length(); i++ ) {
if ( d->unicode[i] != s[i] )
return FALSE;
}
return TRUE;
}
/*!
Returns TRUE if the string ends with \a s; otherwise returns
FALSE.
\sa startsWith()
*/
bool QString::endsWith( const QString& s ) const
{
if ( isNull() )
return s.isNull();
int pos = length() - s.length();
if ( pos < 0 )
return FALSE;
for ( uint i = 0; i < s.length(); i++ ) {
if ( d->unicode[pos+i] != s[(int)i] )
return FALSE;
}
return TRUE;
}
/*! \fn void QString::detach()
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 map is modified. The
implicit sharing mechanism is implemented this way.
*/
#if defined(Q_OS_WIN32)
#include <windows.h>
/*!
\obsolete
Returns a static Windows TCHAR* from a QString, adding NUL if \a
addnul is TRUE.
The lifetime of the return value is until the next call to this function,
or until the last copy of str is deleted, whatever comes first.
Use ucs2() instead.
*/
const void* qt_winTchar(const QString& str, bool)
{
// So that the return value lives long enough.
static QString str_cache;
str_cache = str;
#ifdef UNICODE
return str_cache.ucs2();
#else
return str_cache.latin1();
#endif
}
/*!
Makes a new '\0'-terminated Windows TCHAR* from a QString.
*/
void* qt_winTchar_new(const QString& str)
{
if ( str.isNull() )
return 0;
int l = str.length()+1;
TCHAR *tc = new TCHAR[ l ];
#ifdef UNICODE
memcpy( tc, str.ucs2(), sizeof(TCHAR)*l );
#else
memcpy( tc, str.latin1(), sizeof(TCHAR)*l );
#endif
return tc;
}
/*!
Makes a QString from a Windows TCHAR*.
*/
QString qt_winQString(void* tc)
{
#ifdef UNICODE
return QString::fromUcs2( (ushort*)tc );
#else
return QString::fromLatin1( (TCHAR *)tc );
#endif
}
QCString qt_winQString2MB( const QString& s, int uclen )
{
if ( uclen < 0 )
uclen = s.length();
if ( s.isNull() )
return QCString();
if ( uclen == 0 )
return QCString("");
BOOL used_def;
QCString mb(4096);
int len;
while ( !(len=WideCharToMultiByte(CP_ACP, 0, (const WCHAR*)s.unicode(), uclen,
mb.data(), mb.size()-1, 0, &used_def)) )
{
int r = GetLastError();
if ( r == ERROR_INSUFFICIENT_BUFFER ) {
mb.resize(1+WideCharToMultiByte( CP_ACP, 0,
(const WCHAR*)s.unicode(), uclen,
0, 0, 0, &used_def));
// and try again...
} else {
#ifndef QT_NO_DEBUG
// Fail.
qWarning("WideCharToMultiByte cannot convert multibyte text (error %d): %s (UTF8)",
r, s.utf8().data());
#endif
break;
}
}
mb[len]='\0';
return mb;
}
// WATCH OUT: mblen must include the NUL (or just use -1)
QString qt_winMB2QString( const char* mb, int mblen )
{
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
@@ -324,1537 +324,1537 @@ bool QStringBuffer::open( int m )
qWarning( "QStringBuffer::open: No string" );
#endif
return FALSE;
}
if ( isOpen() ) { // buffer already open
#if defined(QT_CHECK_STATE)
qWarning( "QStringBuffer::open: Buffer already open" );
#endif
return FALSE;
}
setMode( m );
if ( m & IO_Truncate ) { // truncate buffer
s->truncate( 0 );
}
if ( m & IO_Append ) { // append to end of buffer
ioIndex = s->length()*sizeof(QChar);
} else {
ioIndex = 0;
}
setState( IO_Open );
setStatus( 0 );
return TRUE;
}
void QStringBuffer::close()
{
if ( isOpen() ) {
setFlags( IO_Direct );
ioIndex = 0;
}
}
void QStringBuffer::flush()
{
}
QIODevice::Offset QStringBuffer::size() const
{
return s ? s->length()*sizeof(QChar) : 0;
}
QIODevice::Offset QStringBuffer::at() const
{
return ioIndex;
}
bool QStringBuffer::at( Offset pos )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) {
qWarning( "QStringBuffer::at: Buffer is not open" );
return FALSE;
}
#endif
if ( pos >= s->length()*2 ) {
#if defined(QT_CHECK_RANGE)
#if defined(QT_LARGEFILE_SUPPORT) && defined(QT_ABI_64BITOFFSET)
qWarning( "QStringBuffer::at: Index %llu out of range", pos );
#else
qWarning( "QStringBuffer::at: Index %lu out of range", pos );
#endif
#endif
return FALSE;
}
ioIndex = pos;
return TRUE;
}
Q_LONG QStringBuffer::readBlock( char *p, Q_ULONG len )
{
#if defined(QT_CHECK_STATE)
Q_CHECK_PTR( p );
if ( !isOpen() ) { // buffer not open
qWarning( "QStringBuffer::readBlock: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QStringBuffer::readBlock: Read operation not permitted" );
return -1;
}
#endif
if ( ioIndex + len > s->length()*sizeof(QChar) ) {
// overflow
if ( (uint)ioIndex >= s->length()*sizeof(QChar) ) {
setStatus( IO_ReadError );
return -1;
} else {
len = s->length()*2 - (uint)ioIndex;
}
}
memcpy( p, ((const char*)(s->unicode()))+ioIndex, len );
ioIndex += len;
return len;
}
Q_LONG QStringBuffer::writeBlock( const char *p, Q_ULONG len )
{
#if defined(QT_CHECK_NULL)
if ( p == 0 && len != 0 )
qWarning( "QStringBuffer::writeBlock: Null pointer error" );
#endif
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QStringBuffer::writeBlock: Buffer not open" );
return -1;
}
if ( !isWritable() ) { // writing not permitted
qWarning( "QStringBuffer::writeBlock: Write operation not permitted" );
return -1;
}
if ( ioIndex&1 ) {
qWarning( "QStringBuffer::writeBlock: non-even index - non Unicode" );
return -1;
}
if ( len&1 ) {
qWarning( "QStringBuffer::writeBlock: non-even length - non Unicode" );
return -1;
}
#endif
s->replace(ioIndex/2, len/2, (QChar*)p, len/2);
ioIndex += len;
return len;
}
int QStringBuffer::getch()
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QStringBuffer::getch: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QStringBuffer::getch: Read operation not permitted" );
return -1;
}
#endif
if ( (uint)ioIndex >= s->length()*2 ) { // overflow
setStatus( IO_ReadError );
return -1;
}
return (int) *( (const char *) s->unicode() + ioIndex++ );
}
int QStringBuffer::putch( int ch )
{
char c = ch;
if ( writeBlock(&c,1) < 0 )
return -1;
else
return ch;
}
int QStringBuffer::ungetch( int ch )
{
#if defined(QT_CHECK_STATE)
if ( !isOpen() ) { // buffer not open
qWarning( "QStringBuffer::ungetch: Buffer not open" );
return -1;
}
if ( !isReadable() ) { // reading not permitted
qWarning( "QStringBuffer::ungetch: Read operation not permitted" );
return -1;
}
#endif
if ( ch != -1 ) { // something to do with eof
if ( ioIndex )
ioIndex--;
else
ch = -1;
}
return ch;
}
/*!
Constructs a text stream that operates on the Unicode QString, \a
str, through an internal device. The \a filemode argument is
passed to the device's open() function; see \l{QIODevice::mode()}.
If you set an encoding or codec with setEncoding() or setCodec(),
this setting is ignored for text streams that operate on QString.
Example:
\code
QString str;
QTextStream ts( &str, IO_WriteOnly );
ts << "pi = " << 3.14; // str == "pi = 3.14"
\endcode
Writing data to the text stream will modify the contents of the
string. The string will be expanded when data is written beyond
the end of the string. Note that the string will not be truncated:
\code
QString str = "pi = 3.14";
QTextStream ts( &str, IO_WriteOnly );
ts << "2+2 = " << 2+2; // str == "2+2 = 414"
\endcode
Note that because QString is Unicode, you should not use
readRawBytes() or writeRawBytes() on such a stream.
*/
QTextStream::QTextStream( QString* str, int filemode )
{
// TODO: optimize for this case as it becomes more common
// (see QStringBuffer above)
init();
dev = new QStringBuffer( str );
((QStringBuffer *)dev)->open( filemode );
owndev = TRUE;
setEncoding(RawUnicode);
reset();
d->sourceType = QTextStreamPrivate::String;
}
/*! \obsolete
This constructor is equivalent to the constructor taking a QString*
parameter.
*/
QTextStream::QTextStream( QString& str, int filemode )
{
init();
dev = new QStringBuffer( &str );
((QStringBuffer *)dev)->open( filemode );
owndev = TRUE;
setEncoding(RawUnicode);
reset();
d->sourceType = QTextStreamPrivate::String;
}
/*!
Constructs a text stream that operates on the byte array, \a a,
through an internal QBuffer device. The \a mode argument is passed
to the device's open() function; see \l{QIODevice::mode()}.
Example:
\code
QByteArray array;
QTextStream ts( array, IO_WriteOnly );
ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14"
\endcode
Writing data to the text stream will modify the contents of the
array. The array will be expanded when data is written beyond the
end of the string.
Same example, using a QBuffer:
\code
QByteArray array;
QBuffer buf( array );
buf.open( IO_WriteOnly );
QTextStream ts( &buf );
ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14"
buf.close();
\endcode
*/
QTextStream::QTextStream( QByteArray a, int mode )
{
init();
dev = new QBuffer( a );
((QBuffer *)dev)->open( mode );
owndev = TRUE;
setEncoding( Latin1 ); //### Locale???
reset();
d->sourceType = QTextStreamPrivate::ByteArray;
}
/*!
Constructs a text stream that operates on an existing file handle
\a fh through an internal QFile device. The \a mode argument is
passed to the device's open() function; see \l{QIODevice::mode()}.
Note that if you create a QTextStream \c cout or another name that
is also used for another variable of a different type, some
linkers may confuse the two variables, which will often cause
crashes.
*/
QTextStream::QTextStream( FILE *fh, int mode )
{
init();
setEncoding( Locale ); //###
dev = new QFile;
((QFile *)dev)->open( mode, fh );
owndev = TRUE;
reset();
d->sourceType = QTextStreamPrivate::File;
}
/*!
Destroys the text stream.
The destructor does not affect the current IO device.
*/
QTextStream::~QTextStream()
{
if ( owndev )
delete dev;
delete d;
}
/*!
Positions the read pointer at the first non-whitespace character.
*/
void QTextStream::skipWhiteSpace()
{
ts_ungetc( eat_ws() );
}
/*!
Tries to read \a len characters from the stream and stores them in
\a buf. Returns the number of characters really read.
\warning There will no QEOF appended if the read reaches the end
of the file. EOF is reached when the return value does not equal
\a len.
*/
uint QTextStream::ts_getbuf( QChar* buf, uint len )
{
if( len < 1 )
return 0;
uint rnum=0; // the number of QChars really read
if ( d && d->ungetcBuf.length() ) {
while( rnum < len && rnum < d->ungetcBuf.length() ) {
*buf = d->ungetcBuf.constref( rnum );
buf++;
rnum++;
}
d->ungetcBuf = d->ungetcBuf.mid( rnum );
if ( rnum >= len )
return rnum;
}
// we use dev->ungetch() for one of the bytes of the unicode
// byte-order mark, but a local unget hack for the other byte:
int ungetHack = EOF;
if ( doUnicodeHeader ) {
doUnicodeHeader = FALSE; // only at the top
int c1 = dev->getch();
if ( c1 == EOF )
return rnum;
int c2 = dev->getch();
if ( c1 == 0xfe && c2 == 0xff ) {
mapper = 0;
latin1 = FALSE;
internalOrder = QChar::networkOrdered();
networkOrder = TRUE;
} else if ( c1 == 0xff && c2 == 0xfe ) {
mapper = 0;
latin1 = FALSE;
internalOrder = !QChar::networkOrdered();
networkOrder = FALSE;
} else {
if ( c2 != EOF ) {
dev->ungetch( c2 );
ungetHack = c1;
} else {
/*
A small bug might hide here. If only the first byte
of a file has made it so far, and that first byte
is half of the byte-order mark, then the utfness
will not be detected.
*/
dev->ungetch( c1 );
}
}
}
#ifndef QT_NO_TEXTCODEC
if ( mapper ) {
bool shortRead = FALSE;
if ( !d->decoder )
d->decoder = mapper->makeDecoder();
while( rnum < len ) {
QString s;
bool readBlock = !( len == 1+rnum );
for (;;) {
// for efficiency: normally read a whole block
if ( readBlock ) {
// guess buffersize; this may be wrong (too small or too
// big). But we can handle this (either iterate reading
// or use ungetcBuf).
// Note that this might cause problems for codecs where
// one byte can result in >1 Unicode Characters if bytes
// are written to the stream in the meantime (loss of
// synchronicity).
uint rlen = len - rnum;
char *cbuf = new char[ rlen ];
if ( ungetHack != EOF ) {
rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
cbuf[0] = (char)ungetHack;
ungetHack = EOF;
} else {
rlen = dev->readBlock( cbuf, rlen );
}
s += d->decoder->toUnicode( cbuf, rlen );
delete[] cbuf;
// use buffered reading only for the first time, because we
// have to get the stream synchronous again (this is easier
// with single character reading)
readBlock = FALSE;
}
// get stream (and codec) in sync
int c;
if ( ungetHack == EOF ) {
c = dev->getch();
} else {
c = ungetHack;
ungetHack = EOF;
}
if ( c == EOF ) {
shortRead = TRUE;
break;
}
char b = c;
uint lengthBefore = s.length();
s += d->decoder->toUnicode( &b, 1 );
if ( s.length() > lengthBefore )
break; // it seems we are in sync now
}
uint i = 0;
uint end = QMIN( len-rnum, s.length() );
while( i < end ) {
*buf = s.constref(i++);
buf++;
}
rnum += end;
if ( s.length() > i )
// could be = but append is clearer
d->ungetcBuf.append( s.mid( i ) );
if ( shortRead )
return rnum;
}
} else
#endif
if ( latin1 ) {
if ( len == 1+rnum ) {
// use this method for one character because it is more efficient
// (arnt doubts whether it makes a difference, but lets it stand)
int c = (ungetHack == EOF) ? dev->getch() : ungetHack;
if ( c != EOF ) {
*buf = (char)c;
buf++;
rnum++;
}
} else {
if ( ungetHack != EOF ) {
*buf = (char)ungetHack;
buf++;
rnum++;
ungetHack = EOF;
}
char *cbuf = new char[len - rnum];
while ( !dev->atEnd() && rnum < len ) {
uint rlen = len - rnum;
rlen = dev->readBlock( cbuf, rlen );
char *it = cbuf;
char *end = cbuf + rlen;
while ( it < end ) {
*buf = *it;
buf++;
it++;
}
rnum += rlen;
}
delete[] cbuf;
}
} else { // UCS-2 or UTF-16
if ( len == 1+rnum ) {
int c1 = (ungetHack == EOF) ? dev->getch() : ungetHack;
if ( c1 == EOF )
return rnum;
int c2 = dev->getch();
if ( c2 == EOF )
return rnum;
if ( networkOrder ) {
*buf = QChar( c2, c1 );
} else {
*buf = QChar( c1, c2 );
}
buf++;
rnum++;
} else {
char *cbuf = new char[ 2*( len - rnum ) ]; // for paranoids: overflow possible
while ( !dev->atEnd() && rnum < len ) {
uint rlen = 2 * ( len-rnum );
if ( ungetHack != EOF ) {
rlen = 1+dev->readBlock( cbuf+1, rlen-1 );
cbuf[0] = (char)ungetHack;
ungetHack = EOF;
} else {
rlen = dev->readBlock( cbuf, rlen );
}
// We can't use an odd number of bytes, so put it back. But
// do it only if we are capable of reading more -- normally
// there should not be an odd number, but the file might be
// truncated or not in UTF-16...
if ( (rlen & 1) == 1 )
if ( !dev->atEnd() )
dev->ungetch( cbuf[--rlen] );
uint i = 0;
if ( networkOrder ) {
while( i < rlen ) {
*buf = QChar( cbuf[i+1], cbuf[i] );
buf++;
i+=2;
}
} else {
while( i < rlen ) {
*buf = QChar( cbuf[i], cbuf[i+1] );
buf++;
i+=2;
}
}
rnum += i/2;
}
delete[] cbuf;
}
}
return rnum;
}
/*!
Tries to read one line, but at most len characters from the stream
and stores them in \a buf.
Returns the number of characters really read. Newlines are not
stripped.
There will be a QEOF appended if the read reaches the end of file;
this is different to ts_getbuf().
This function works only if a newline (as byte) is also a newline
(as resulting character) since it uses QIODevice::readLine(). So
use it only for such codecs where this is true!
This function is (almost) a no-op for UTF 16. Don't use it if
doUnicodeHeader is TRUE!
*/
uint QTextStream::ts_getline( QChar* buf )
{
uint rnum=0; // the number of QChars really read
char cbuf[ getline_buf_size+1 ];
if ( d && d->ungetcBuf.length() ) {
while( rnum < getline_buf_size && rnum < d->ungetcBuf.length() ) {
buf[rnum] = d->ungetcBuf.constref(rnum);
rnum++;
}
d->ungetcBuf = d->ungetcBuf.mid( rnum );
if ( rnum >= getline_buf_size )
return rnum;
}
#ifndef QT_NO_TEXTCODEC
if ( mapper ) {
if ( !d->decoder )
d->decoder = mapper->makeDecoder();
QString s;
bool readBlock = TRUE;
for (;;) {
// for efficiency: try to read a line
if ( readBlock ) {
int rlen = getline_buf_size - rnum;
rlen = dev->readLine( cbuf, rlen+1 );
if ( rlen == -1 )
rlen = 0;
s += d->decoder->toUnicode( cbuf, rlen );
readBlock = FALSE;
}
if ( dev->atEnd()
|| s.at( s.length()-1 ) == '\n'
|| s.at( s.length()-1 ) == '\r'
) {
break;
} else {
// get stream (and codec) in sync
int c;
c = dev->getch();
if ( c == EOF ) {
break;
}
char b = c;
uint lengthBefore = s.length();
s += d->decoder->toUnicode( &b, 1 );
if ( s.length() > lengthBefore )
break; // it seems we are in sync now
}
}
uint i = 0;
while( rnum < getline_buf_size && i < s.length() )
buf[rnum++] = s.constref(i++);
if ( s.length() > i )
// could be = but append is clearer
d->ungetcBuf.append( s.mid( i ) );
if ( rnum < getline_buf_size && dev->atEnd() )
buf[rnum++] = QEOF;
} else
#endif
if ( latin1 ) {
int rlen = getline_buf_size - rnum;
rlen = dev->readLine( cbuf, rlen+1 );
if ( rlen == -1 )
rlen = 0;
char *end = cbuf+rlen;
char *it = cbuf;
buf +=rnum;
while ( it != end ) {
buf->setCell( *(it++) );
buf->setRow( 0 );
buf++;
}
rnum += rlen;
if ( rnum < getline_buf_size && dev->atEnd() )
buf[1] = QEOF;
}
return rnum;
}
/*!
Puts one character into the stream.
*/
void QTextStream::ts_putc( QChar c )
{
#ifndef QT_NO_TEXTCODEC
if ( mapper ) {
if ( !d->encoder )
d->encoder = mapper->makeEncoder();
int len = 1;
QString s = c;
QCString block = d->encoder->fromUnicode( s, len );
dev->writeBlock( block, len );
} else
#endif
if ( latin1 ) {
if ( c.row() )
dev->putch( '?' ); // unknown character
else
dev->putch( c.cell() );
} else {
if ( doUnicodeHeader ) {
doUnicodeHeader = FALSE;
ts_putc( QChar::byteOrderMark );
}
if ( internalOrder ) {
// this case is needed by QStringBuffer
dev->writeBlock( (char*)&c, sizeof(QChar) );
} else if ( networkOrder ) {
dev->putch( c.row() );
dev->putch( c.cell() );
} else {
dev->putch( c.cell() );
dev->putch( c.row() );
}
}
}
/*!
Puts one character into the stream.
*/
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
*****************************************************************************/
/*!
\overload
Reads a char \a c from the stream and returns a reference to the
stream. Note that whitespace is skipped.
*/
QTextStream &QTextStream::operator>>( char &c )
{
CHECK_STREAM_PRECOND
c = eat_ws();
return *this;
}
/*!
Reads a char \a c from the stream and returns a reference to the
stream. Note that whitespace is \e not skipped.
*/
QTextStream &QTextStream::operator>>( QChar &c )
{
CHECK_STREAM_PRECOND
c = ts_getc();
return *this;
}
ulong QTextStream::input_bin()
{
ulong val = 0;
QChar ch = eat_ws();
int dv = ch.digitValue();
while ( dv == 0 || dv == 1 ) {
val = ( val << 1 ) + dv;
ch = ts_getc();
dv = ch.digitValue();
}
if ( ch != QEOF )
ts_ungetc( ch );
return val;
}
ulong QTextStream::input_oct()
{
ulong val = 0;
QChar ch = eat_ws();
int dv = ch.digitValue();
while ( dv >= 0 && dv <= 7 ) {
val = ( val << 3 ) + dv;
ch = ts_getc();
dv = ch.digitValue();
}
if ( dv == 8 || dv == 9 ) {
while ( ts_isdigit(ch) )
ch = ts_getc();
}
if ( ch != QEOF )
ts_ungetc( ch );
return val;
}
ulong QTextStream::input_dec()
{
ulong val = 0;
QChar ch = eat_ws();
int dv = ch.digitValue();
while ( ts_isdigit(ch) ) {
val = val * 10 + dv;
ch = ts_getc();
dv = ch.digitValue();
}
if ( ch != QEOF )
ts_ungetc( ch );
return val;
}
ulong QTextStream::input_hex()
{
ulong val = 0;
QChar ch = eat_ws();
char c = ch;
while ( isxdigit((uchar) c) ) {
val <<= 4;
if ( ts_isdigit(c) )
val += c - '0';
else
val += 10 + tolower( (uchar) c ) - 'a';
c = ch = ts_getc();
}
if ( ch != QEOF )
ts_ungetc( ch );
return val;
}
long QTextStream::input_int()
{
long val;
QChar ch;
char c;
switch ( flags() & basefield ) {
case bin:
val = (long)input_bin();
break;
case oct:
val = (long)input_oct();
break;
case dec:
c = ch = eat_ws();
if ( ch == QEOF ) {
val = 0;
} else {
if ( !(c == '-' || c == '+') )
ts_ungetc( ch );
if ( c == '-' ) {
ulong v = input_dec();
if ( v ) { // ensure that LONG_MIN can be read
v--;
val = -((long)v) - 1;
} else {
val = 0;
}
} else {
val = (long)input_dec();
}
}
break;
case hex:
val = (long)input_hex();
break;
default:
val = 0;
c = ch = eat_ws();
if ( c == '0' ) { // bin, oct or hex
c = ch = ts_getc();
if ( tolower((uchar) c) == 'x' )
val = (long)input_hex();
else if ( tolower((uchar) c) == 'b' )
val = (long)input_bin();
else { // octal
ts_ungetc( ch );
if ( c >= '0' && c <= '7' ) {
val = (long)input_oct();
} else {
val = 0;
}
}
} else if ( ts_isdigit(ch) ) {
ts_ungetc( ch );
val = (long)input_dec();
} else if ( c == '-' || c == '+' ) {
ulong v = input_dec();
if ( c == '-' ) {
if ( v ) { // ensure that LONG_MIN can be read
v--;
val = -((long)v) - 1;
} else {
val = 0;
}
} else {
val = (long)v;
}
}
}
return val;
}
//
// We use a table-driven FSM to parse floating point numbers
// strtod() cannot be used directly since we're reading from a QIODevice
//
double QTextStream::input_double()
{
const int Init = 0; // states
const int Sign = 1;
const int Mantissa = 2;
const int Dot = 3;
const int Abscissa = 4;
const int ExpMark = 5;
const int ExpSign = 6;
const int Exponent = 7;
const int Done = 8;
const int InputSign = 1; // input tokens
const int InputDigit = 2;
const int InputDot = 3;
const int InputExp = 4;
static const uchar table[8][5] = {
/* None InputSign InputDigit InputDot InputExp */
{ 0, Sign, Mantissa, Dot, 0, }, // Init
{ 0, 0, Mantissa, Dot, 0, }, // Sign
{ Done, Done, Mantissa, Dot, ExpMark,}, // Mantissa
{ 0, 0, Abscissa, 0, 0, }, // Dot
{ Done, Done, Abscissa, Done, ExpMark,}, // Abscissa
{ 0, ExpSign, Exponent, 0, 0, }, // ExpMark
{ 0, 0, Exponent, 0, 0, }, // ExpSign
{ Done, Done, Exponent, Done, Done } // Exponent
};
int state = Init; // parse state
int input; // input token
char buf[256];
int i = 0;
QChar c = eat_ws();
for (;;) {
switch ( c ) {
case '+':
case '-':
input = InputSign;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
input = InputDigit;
break;
case '.':
input = InputDot;
break;
case 'e':
case 'E':
input = InputExp;
break;
default:
input = 0;
break;
}
state = table[state][input];
if ( state == 0 || state == Done || i > 250 ) {
if ( i > 250 ) { // ignore rest of digits
do { c = ts_getc(); } while ( c != QEOF && ts_isdigit(c) );
}
if ( c != QEOF )
ts_ungetc( c );
buf[i] = '\0';
char *end;
return strtod( buf, &end );
}
buf[i++] = c;
c = ts_getc();
}
#if !defined(Q_CC_EDG)
return 0.0;
#endif
}
/*!
\overload
Reads a signed \c short integer \a i from the stream and returns a
reference to the stream. See flags() for an explanation of the
expected input format.
*/
QTextStream &QTextStream::operator>>( signed short &i )
{
CHECK_STREAM_PRECOND
i = (signed short)input_int();
return *this;
}
/*!
\overload
Reads an unsigned \c short integer \a i from the stream and
returns a reference to the stream. See flags() for an explanation
of the expected input format.
*/
QTextStream &QTextStream::operator>>( unsigned short &i )
{
CHECK_STREAM_PRECOND
i = (unsigned short)input_int();
return *this;
}
/*!
\overload
Reads a signed \c int \a i from the stream and returns a reference
to the stream. See flags() for an explanation of the expected
input format.
*/
QTextStream &QTextStream::operator>>( signed int &i )
{
CHECK_STREAM_PRECOND
i = (signed int)input_int();
return *this;
}
/*!
\overload
Reads an unsigned \c int \a i from the stream and returns a
reference to the stream. See flags() for an explanation of the
expected input format.
*/
QTextStream &QTextStream::operator>>( unsigned int &i )
{
CHECK_STREAM_PRECOND
i = (unsigned int)input_int();
return *this;
}
/*!
\overload
Reads a signed \c long int \a i from the stream and returns a
reference to the stream. See flags() for an explanation of the
expected input format.
*/
QTextStream &QTextStream::operator>>( signed long &i )
{
CHECK_STREAM_PRECOND
i = (signed long)input_int();
return *this;
}
/*!
\overload
Reads an unsigned \c long int \a i from the stream and returns a
reference to the stream. See flags() for an explanation of the
expected input format.
*/
QTextStream &QTextStream::operator>>( unsigned long &i )
{
CHECK_STREAM_PRECOND
i = (unsigned long)input_int();
return *this;
}
/*!
\overload
Reads a \c float \a f from the stream and returns a reference to
the stream. See flags() for an explanation of the expected input
format.
*/
QTextStream &QTextStream::operator>>( float &f )
{
CHECK_STREAM_PRECOND
f = (float)input_double();
return *this;
}
/*!
\overload
Reads a \c double \a f from the stream and returns a reference to
the stream. See flags() for an explanation of the expected input
format.
*/
QTextStream &QTextStream::operator>>( double &f )
{
CHECK_STREAM_PRECOND
f = input_double();
return *this;
}
/*!
\overload
Reads a "word" from the stream into \a s and returns a reference
to the stream.
A word consists of characters for which isspace() returns FALSE.
*/
QTextStream &QTextStream::operator>>( char *s )
{
CHECK_STREAM_PRECOND
int maxlen = width( 0 );
QChar c = eat_ws();
if ( !maxlen )
maxlen = -1;
while ( c != QEOF ) {
if ( ts_isspace(c) || maxlen-- == 0 ) {
ts_ungetc( c );
break;
}
*s++ = c;
c = ts_getc();
}
*s = '\0';
return *this;
}
/*!
\overload
Reads a "word" from the stream into \a str and returns a reference
to the stream.
A word consists of characters for which isspace() returns FALSE.
*/
QTextStream &QTextStream::operator>>( QString &str )
{
CHECK_STREAM_PRECOND
str=QString::fromLatin1("");
QChar c = eat_ws();
while ( c != QEOF ) {
if ( ts_isspace(c) ) {
ts_ungetc( c );
break;
}
str += c;
c = ts_getc();
}
return *this;
}
/*!
\overload
Reads a "word" from the stream into \a str and returns a reference
to the stream.
A word consists of characters for which isspace() returns FALSE.
*/
QTextStream &QTextStream::operator>>( QCString &str )
{
CHECK_STREAM_PRECOND
QCString *dynbuf = 0;
const int buflen = 256;
char buffer[buflen];
char *s = buffer;
int i = 0;
QChar c = eat_ws();
while ( c != QEOF ) {
if ( ts_isspace(c) ) {
ts_ungetc( c );
break;
}
if ( i >= buflen-1 ) {
if ( !dynbuf ) { // create dynamic buffer
dynbuf = new QCString(buflen*2);
memcpy( dynbuf->data(), s, i ); // copy old data
} else if ( i >= (int)dynbuf->size()-1 ) {
dynbuf->resize( dynbuf->size()*2 );
}
s = dynbuf->data();
}
s[i++] = c;
c = ts_getc();
}
str.resize( i+1 );
memcpy( str.data(), s, i );
delete dynbuf;
return *this;
}
/*!
Reads a line from the stream and returns a string containing the
text.
The returned string does not contain any trailing newline or
carriage return. Note that this is different from
QIODevice::readLine(), which does not strip the newline at the end
of the line.
On EOF you will get a QString that is null. On reading an empty
line the returned QString is empty but not null.
\sa QIODevice::readLine()
*/
QString QTextStream::readLine()
{
#if defined(QT_CHECK_STATE)
if ( !dev ) {
qWarning( "QTextStream::readLine: No device" );
return QString::null;
}
#endif
bool readCharByChar = TRUE;
QString result;
#if 0
if ( !doUnicodeHeader && (
(latin1) ||
(mapper != 0 && mapper->mibEnum() == 106 ) // UTF 8
) ) {
readCharByChar = FALSE;
// use optimized read line
QChar c[getline_buf_size];
int pos = 0;
bool eof = FALSE;
for (;;) {
pos = ts_getline( c );
if ( pos == 0 ) {
// something went wrong; try fallback
readCharByChar = TRUE;
//dev->resetStatus();
break;
}
if ( c[pos-1] == QEOF || c[pos-1] == '\n' ) {
if ( pos>2 && c[pos-1]==QEOF && c[pos-2]=='\n' ) {
result += QString( c, pos-2 );
} else if ( pos > 1 ) {
result += QString( c, pos-1 );
}
if ( pos == 1 && c[pos-1] == QEOF )
eof = TRUE;
break;
} else {
result += QString( c, pos );
}
}
if ( eof && result.isEmpty() )
return QString::null;
}
#endif
if ( readCharByChar ) {
// read character by character
const int buf_size = 256;
QChar c[buf_size];
int pos = 0;
c[pos] = ts_getc();
if ( c[pos] == QEOF ) {
return QString::null;
}
while ( c[pos] != QEOF && c[pos] != '\n' ) {
if ( c[pos] == '\r' ) { // ( handle mac and dos )
QChar nextc = ts_getc();
if ( nextc != '\n' )
ts_ungetc( nextc );
break;
}
pos++;
if ( pos >= buf_size ) {
result += QString( c, pos );
pos = 0;
}
c[pos] = ts_getc();
}
result += QString( c, pos );
}
return result;
}
/*!
Reads the entire stream and returns a string containing the text.
\sa QIODevice::readLine()
*/
QString QTextStream::read()
{
#if defined(QT_CHECK_STATE)
if ( !dev ) {
qWarning( "QTextStream::read: No device" );
return QString::null;
}
#endif
QString result;
const uint bufsize = 512;
QChar buf[bufsize];
uint i, num, start;
bool skipped_cr = FALSE;
for (;;) {
num = ts_getbuf(buf,bufsize);
// convert dos (\r\n) and mac (\r) style eol to unix style (\n)
start = 0;
for ( i=0; i<num; i++ ) {
if ( buf[i] == '\r' ) {
// Only skip single cr's preceding lf's
if ( skipped_cr ) {
result += buf[i];
start++;
} else {
result += QString( &buf[start], i-start );
start = i+1;
skipped_cr = TRUE;
}
} else {
if ( skipped_cr ) {
if ( buf[i] != '\n' ) {
// Should not have skipped it
result += '\n';
}
skipped_cr = FALSE;
}
}
}
if ( start < num )
result += QString( &buf[start], i-start );
if ( num != bufsize ) // if ( EOF )
break;
}
return result;
}
/*****************************************************************************
QTextStream write functions
*****************************************************************************/
/*!
Writes character \c char to the stream and returns a reference to
the stream.
The character \a c is assumed to be Latin1 encoded independent of
the Encoding set for the QTextStream.
*/
QTextStream &QTextStream::operator<<( QChar c )
{
CHECK_STREAM_PRECOND
ts_putc( c );
return *this;
}
/*!
\overload
Writes character \a c to the stream and returns a reference to the
stream.
*/
QTextStream &QTextStream::operator<<( char c )
{
CHECK_STREAM_PRECOND
unsigned char uc = (unsigned char) c;
ts_putc( uc );
return *this;
}
QTextStream &QTextStream::output_int( int format, ulong n, bool neg )
{
static const char hexdigits_lower[] = "0123456789abcdef";
static const char hexdigits_upper[] = "0123456789ABCDEF";
CHECK_STREAM_PRECOND
char buf[76];
register char *p;
int len;
const char *hexdigits;
switch ( flags() & I_BASE_MASK ) {
case I_BASE_2: // output binary number
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
@@ -1,668 +1,544 @@
/****************************************************************************
** $Id$
**
** Implementation of the QUcom classes
**
** Created : 990101
**
** 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 "qucom_p.h"
// Standard types
// {DE56510E-4E9F-4b76-A3C2-D1E2EF42F1AC}
const QUuid TID_QUType_Null( 0xde56510e, 0x4e9f, 0x4b76, 0xa3, 0xc2, 0xd1, 0xe2, 0xef, 0x42, 0xf1, 0xac );
const QUuid *QUType_Null::uuid() const { return &TID_QUType_Null; }
const char *QUType_Null::desc() const { return "null"; }
bool QUType_Null::canConvertFrom( QUObject *, QUType * ) { return FALSE; }
bool QUType_Null::canConvertTo( QUObject *, QUType * ) { return FALSE; }
bool QUType_Null::convertFrom( QUObject *, QUType * ) { return FALSE; }
bool QUType_Null::convertTo( QUObject *, QUType * ) { return FALSE; }
void QUType_Null::clear( QUObject *) {};
int QUType_Null::serializeTo( QUObject *, QUBuffer * ) { return 0; }
int QUType_Null::serializeFrom( QUObject *, QUBuffer * ) { return 0; };
QUType_Null static_QUType_Null;
// {7EE17B08-5419-47e2-9776-8EEA112DCAEC}
const QUuid TID_QUType_enum( 0x7ee17b08, 0x5419, 0x47e2, 0x97, 0x76, 0x8e, 0xea, 0x11, 0x2d, 0xca, 0xec );
QUType_enum static_QUType_enum;
const QUuid *QUType_enum::uuid() const { return &TID_QUType_enum; }
const char *QUType_enum::desc() const { return "enum"; }
void QUType_enum::set( QUObject *o, int v )
{
o->payload.i = v;
o->type = this;
}
bool QUType_enum::canConvertFrom( QUObject *o, QUType *t )
{
if ( isEqual( t, &static_QUType_int ) ) // ## todo unsigned int?
return TRUE;
return t->canConvertTo( o, this );
}
bool QUType_enum::canConvertTo( QUObject * /*o*/, QUType *t )
{
return isEqual( t, &static_QUType_int );
}
bool QUType_enum::convertFrom( QUObject *o, QUType *t )
{
if ( isEqual( t, &static_QUType_int ) ) // ## todo unsigned int?
;
else
return t->convertTo( o, this );
o->type = this;
return TRUE;
}
bool QUType_enum::convertTo( QUObject *o, QUType *t )
{
if ( isEqual( t, &static_QUType_int ) ) {
o->type = &static_QUType_int;
return TRUE;
}
return FALSE;
}
int QUType_enum::serializeTo( QUObject *, QUBuffer * )
{
return 0;
}
int QUType_enum::serializeFrom( QUObject *, QUBuffer * )
{
return 0;
}
// {8AC26448-5AB4-49eb-968C-8F30AB13D732}
const QUuid TID_QUType_ptr( 0x8ac26448, 0x5ab4, 0x49eb, 0x96, 0x8c, 0x8f, 0x30, 0xab, 0x13, 0xd7, 0x32 );
QUType_ptr static_QUType_ptr;
const QUuid *QUType_ptr::uuid() const { return &TID_QUType_ptr; }
const char *QUType_ptr::desc() const { return "ptr"; }
void QUType_ptr::set( QUObject *o, const void* v )
{
o->payload.ptr = (void*) v;
o->type = this;
}
bool QUType_ptr::canConvertFrom( QUObject *o, QUType *t )
{
return t->canConvertTo( o, this );
}
bool QUType_ptr::canConvertTo( QUObject *, QUType * )
{
return FALSE;
}
bool QUType_ptr::convertFrom( QUObject *o, QUType *t )
{
return t->convertTo( o, this );
}
bool QUType_ptr::convertTo( QUObject *, QUType * )
{
return FALSE;
}
int QUType_ptr::serializeTo( QUObject *, QUBuffer * )
{
return 0;
}
int QUType_ptr::serializeFrom( QUObject *, QUBuffer * )
{
return 0;
}
// {97A2594D-6496-4402-A11E-55AEF2D4D25C}
const QUuid TID_QUType_iface( 0x97a2594d, 0x6496, 0x4402, 0xa1, 0x1e, 0x55, 0xae, 0xf2, 0xd4, 0xd2, 0x5c );
QUType_iface static_QUType_iface;
const QUuid *QUType_iface::uuid() const { return &TID_QUType_iface; }
const char *QUType_iface::desc() const { return "UnknownInterface"; }
void QUType_iface::set( QUObject *o, QUnknownInterface* iface )
{
o->payload.iface = iface;
o->type = this;
}
bool QUType_iface::canConvertFrom( QUObject *o, QUType *t )
{
return t->canConvertTo( o, this );
}
bool QUType_iface::canConvertTo( QUObject *, QUType * )
{
return FALSE;
}
bool QUType_iface::convertFrom( QUObject *o, QUType *t )
{
return t->convertTo( o, this );
}
bool QUType_iface::convertTo( QUObject *, QUType * )
{
return FALSE;
}
int QUType_iface::serializeTo( QUObject *, QUBuffer * )
{
return 0;
}
int QUType_iface::serializeFrom( QUObject *, QUBuffer * )
{
return 0;
}
// {2F358164-E28F-4bf4-9FA9-4E0CDCABA50B}
const QUuid TID_QUType_idisp( 0x2f358164, 0xe28f, 0x4bf4, 0x9f, 0xa9, 0x4e, 0xc, 0xdc, 0xab, 0xa5, 0xb );
QUType_idisp static_QUType_idisp;
const QUuid *QUType_idisp::uuid() const { return &TID_QUType_idisp; }
const char *QUType_idisp::desc() const { return "DispatchInterface"; }
void QUType_idisp::set( QUObject *o, QDispatchInterface* idisp )
{
o->payload.idisp = 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
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
@@ -1,310 +1,315 @@
/****************************************************************************
** $Id$
**
** QWaitCondition 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;
#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