diff options
Diffstat (limited to 'src/corelib')
23 files changed, 763 insertions, 75 deletions
diff --git a/src/corelib/doc/snippets/qtracer/ftracer.cpp b/src/corelib/doc/snippets/qtracer/ftracer.cpp new file mode 100644 index 0000000000..b12e3ed9c3 --- /dev/null +++ b/src/corelib/doc/snippets/qtracer/ftracer.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> + +#include <QCoreApplication> +#include <QLoggingCategory> + + +//![1] +QLoggingCategory theFooArea("foo"); +QLoggingCategory theBarArea("bar"); +QLoggingCategory theBazArea("baz"); +//![1] + +// Note: These locations are Ubuntu specific. + +// Note: To make the example work with user permissions, make sure +// the files are user-writable and the path leading there accessible. + +const char traceSwitch[] = "/sys/kernel/debug/tracing/tracing_on"; +const char traceSink[] = "/sys/kernel/debug/tracing/trace_marker"; + +// The base class only serves as a facility to share code +// between the "single line" data logging aspect and the +// scoped "measuring" aspect. + +// Both aspects and the base class could be combined into +// a single tracer serving both purposes, but are split +// here for clarity. + +// Error handling is left as an exercise. + +//![2] +class MyTracerBase : public QTracer +{ +public: + MyTracerBase() { + enable = ::open(traceSwitch, O_WRONLY); + marker = ::open(traceSink, O_WRONLY); + } + + ~MyTracerBase() { + ::close(enable); + ::close(marker); + } + +protected: + int enable; + int marker; +}; +//![2] + + +//![2] +class MyTracer : public MyTracerBase +{ +public: + void start() { ::write(marker, "B", 1); } + void end() { ::write(marker, "E", 1); } +}; +//![2] + + +//![3] +class MyDataLogger : public MyTracerBase +{ +public: + MyDataLogger() { + buf[0] = 0; + pos = 0; + } + + void record(int i) { pos += sprintf(buf + pos, "%d", i); } + void record(const char *msg) { pos += sprintf(buf + pos, "%s", msg); } + void end() { ::write(marker, buf, pos); pos = 0; } + +private: + char buf[100]; + int pos; +}; +//![3] + +// Simplest possible example for "measuring". +//![4] +int foo(int i) +{ + qCTraceGuard(theFooArea); + // Here could be some lengthy code. + return i * i; +} +//![4] + +// We can switch on/off tracing dynamically. +// The tracer will be temporarily switched off at the third call +// and re-enabled at the eighth. +//![5] +int bar(int i) +{ + static int n = 0; + ++n; + if (n == 3) + theBarArea.setEnabled(QtTraceMsg, false); + if (n == 8) + theBarArea.setEnabled(QtTraceMsg, true); + + qCTraceGuard(theBarArea); + return i * i; +} +//![5] + +// An example to create "complex" log messages. +//![6] +int baz(int i) +{ + qCTrace(theBazArea) << 32 << "some stuff"; + + return i * i; +} +//![6] + + + +//![7] +namespace { +static struct Init +{ + Init() { + tracer.addToCategory(theFooArea); + tracer.addToCategory(theBarArea); + logger.addToCategory(theBazArea); + } + + MyTracer tracer; + MyDataLogger logger; + +} initializer; +} +//![7] diff --git a/src/corelib/doc/snippets/qtracer/main.cpp b/src/corelib/doc/snippets/qtracer/main.cpp new file mode 100644 index 0000000000..758a2bbdb8 --- /dev/null +++ b/src/corelib/doc/snippets/qtracer/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +int foo(int i); +int bar(int i); +int baz(int i); + +int main() +{ + int s = 0; + for (int i = 0; i != 10; ++i) + s += foo(i); + + for (int i = 0; i != 10; ++i) + s += bar(i); + + for (int i = 0; i != 10; ++i) + s += baz(i); + + return s; +} + diff --git a/src/corelib/doc/snippets/qtracer/qtracer.pro b/src/corelib/doc/snippets/qtracer/qtracer.pro new file mode 100644 index 0000000000..254e22be76 --- /dev/null +++ b/src/corelib/doc/snippets/qtracer/qtracer.pro @@ -0,0 +1,2 @@ + +SOURCES += ftracer.cpp main.cpp diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc index d1c7eb5d1b..a4f1b8723a 100644 --- a/src/corelib/doc/src/external-resources.qdoc +++ b/src/corelib/doc/src/external-resources.qdoc @@ -47,26 +47,6 @@ */ /*! - \externalpage http://www.ietf.org/rfc/rfc3986.txt - \title RFC 3986 -*/ - -/*! - \externalpage http://www.ietf.org/rfc/rfc1738.txt - \title RFC 1738 -*/ - -/*! - \externalpage http://www.ietf.org/rfc/rfc3941.txt - \title RFC 3491 -*/ - -/*! - \externalpage http://www.ietf.org/rfc/rfc2045.txt - \title RFC 2045 -*/ - -/*! \externalpage http://www.ietf.org/rfc/rfc4648.txt \title RFC 4648 */ diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 5b1a7dbbcb..41a9c0d950 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -717,6 +717,10 @@ Q_CORE_EXPORT void *qMemSet(void *dest, int c, size_t n); A message generated by the qCritical() function. \value QtFatalMsg A message generated by the qFatal() function. + \value QtTraceMsg + Used by the qCTrace() macro. Trace events are usually passed only + to dedicated \a QTracer objects, and do not appear in the installed + message handler. \value QtSystemMsg diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 4d564b09c3..c0709ce258 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -814,6 +814,7 @@ Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogCont case QtWarningMsg: message.append(QLatin1String("warning")); break; case QtCriticalMsg:message.append(QLatin1String("critical")); break; case QtFatalMsg: message.append(QLatin1String("fatal")); break; + case QtTraceMsg: message.append(QLatin1String("trace")); break; } } else if (token == fileTokenC) { if (context.file) diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h index 2b798f9ea0..68a24d0397 100644 --- a/src/corelib/global/qlogging.h +++ b/src/corelib/global/qlogging.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QDebug; class QNoDebug; -enum QtMsgType { QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, QtSystemMsg = QtCriticalMsg }; +enum QtMsgType { QtDebugMsg, QtWarningMsg, QtCriticalMsg, QtFatalMsg, QtTraceMsg, QtSystemMsg = QtCriticalMsg }; class QMessageLogContext { diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index a7517b4c7f..46d8101e20 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -511,7 +511,14 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea if (slash) { const QByteArray chunk = QFile::encodeName(dirName.left(slash)); if (QT_MKDIR(chunk.constData(), 0777) != 0) { - if (errno == EEXIST) { + if (errno == EEXIST +#if defined(Q_OS_QNX) + // On QNX the QNet (VFS paths of other hosts mounted under a directory + // such as /net) mountpoint returns ENOENT, despite existing. stat() + // on the QNet mountpoint returns successfully and reports S_IFDIR. + || errno == ENOENT +#endif + ) { QT_STATBUF st; if (QT_STAT(chunk.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) continue; diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 562cf25964..80acee6ad1 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -107,7 +107,8 @@ QLoggingCategory::QLoggingCategory(const char *category) : name(0), enabledDebug(false), enabledWarning(true), - enabledCritical(true) + enabledCritical(true), + enabledTrace(false) { bool isDefaultCategory = (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0); @@ -122,7 +123,8 @@ QLoggingCategory::QLoggingCategory(const char *category) } if (QLoggingRegistry *reg = QLoggingRegistry::instance()) - reg->registerCategory(this);} + reg->registerCategory(this); +} /*! Destructs a QLoggingCategory object @@ -164,6 +166,7 @@ bool QLoggingCategory::isEnabled(QtMsgType msgtype) const case QtDebugMsg: return enabledDebug; case QtWarningMsg: return enabledWarning; case QtCriticalMsg: return enabledCritical; + case QtTraceMsg: return enabledTrace; case QtFatalMsg: return true; default: break; } @@ -177,6 +180,10 @@ bool QLoggingCategory::isEnabled(QtMsgType msgtype) const change e.g. the settings of another objects for the same category name. \note QtFatalMsg cannot be changed. It will always return true. + + Example: + + \snippet qtracer/ftracer.cpp 5 */ void QLoggingCategory::setEnabled(QtMsgType type, bool enable) { @@ -184,6 +191,7 @@ void QLoggingCategory::setEnabled(QtMsgType type, bool enable) case QtDebugMsg: enabledDebug = enable; break; case QtWarningMsg: enabledWarning = enable; break; case QtCriticalMsg: enabledCritical = enable; break; + case QtTraceMsg: enabledTrace = enable; break; case QtFatalMsg: default: break; } @@ -319,12 +327,61 @@ void QLoggingCategory::setFilterRules(const QString &rules) \snippet qloggingcategory/main.cpp 12 \note Arguments are not processed if critical output for the category is not - enabled, so do not reply on any side effects. + enabled, so do not rely on any side effects. \sa qCritical() */ /*! + \relates QLoggingCategory + \macro qCTrace(category) + \since 5.2 + + Returns an output stream for trace messages in the logging category + \a category. + + The macro expands to code that first checks whether + \l QLoggingCategory::isEnabled() evaluates for trace output to \c{true}. + If so, the stream arguments are processed and sent to the tracers + registered with the category. + + \note Arguments are not processed if trace output for the category is not + enabled, so do not rely on any side effects. + + Example: + + \snippet qtracer/ftracer.cpp 6 + + \sa qCTraceGuard() +*/ + +/*! + \relates QLoggingCategory + \macro qCTraceGuard(category) + \since 5.2 + + The macro expands to code that creates a guard object with automatic + storage. The guard constructor checks whether + \l QLoggingCategory::isEnabled() evaluates for trace output to \c{true}. + If so, the stream arguments are processed and the \c{start()} + functions of the tracers registered with the \a category are called. + + The guard destructor also checks whether the category is enabled for + tracing and if so, the \c{end()} + functions of the tracers registered with the \a category are called. + + \note Arguments are always processed, even if trace output for the + category is disabled. They will, however, in that case not be passed + to the \c{record()} functions of the registered tracers. + + Example: + + \snippet qtracer/ftracer.cpp 4 + + \sa qCTrace() +*/ + +/*! \macro Q_DECLARE_LOGGING_CATEGORY(name) \relates QLoggingCategory \since 5.2 @@ -349,4 +406,234 @@ void QLoggingCategory::setFilterRules(const QString &rules) This macro must be used outside of a class or method. */ + +/*! + \class QTracer + \inmodule QtCore + \since 5.2 + + \brief The QTracer class provides an interface for handling + trace events associated with a logging category. + + \c QTracer objects are registered with logging categories. + Multiple \c QTracer objects + can be registered with the same category, and the same + \c QTracer object can be registered with different categories. + + If code containing \c qCTrace is executed, and the associated + logging category is enabled for tracing, all \c QTracer objects + that are registered with the category are notified. + + \c QTracer objects +*/ + +/*! + \fn QTracer::QTracer() + + Constructs a tracer object. + + Example: + + \snippet qtracer/ftracer.cpp 2 +*/ + +/*! + \fn QTracer::~QTracer() + + Destroys the tracer object. +*/ + +/*! + Registers this tracer for the \a category. + + The tracer will later be notified of messages of type + \c QtTraceMsg, as long as that message type + is enabled in the category. + + Example: + + \snippet qtracer/ftracer.cpp 1 + \codeline + \snippet qtracer/ftracer.cpp 7 +*/ + +void QTracer::addToCategory(QLoggingCategory &category) +{ + category.tracers.append(this); +} + +/*! + \fn void QTracer::start() + + This function is invoked when a tracing activity starts, + typically from the constructor of a \c QTraceGuard object + defined by \c qCTrace() or \c qCTraceGuard(). + + The base implementation does nothing. \c QTracer subclasses + are advised to override it if needed. + + \sa qCTrace(), qCTraceGuard() +*/ + +/*! + \fn void QTracer::end() + + This function is invoked when a tracing activity ends, + typically from the destructor of a \c QTraceGuard object + defined by \c qCTrace() or \c qCTraceGuard(). + + The base implementation does nothing. It is common for + \c QTracer subclasses to override it to perform flushing + of collected data. + + \sa qCTrace(), qCTraceGuard() +*/ + +/*! + \fn void QTracer::record(int data) + + This function is invoked during a tracing activity to + pass integer \a data to the \c QTracer object. + + Example: + + \snippet qtracer/ftracer.cpp 3 +*/ + +/*! + \fn void QTracer::record(const char *data) + + This function is invoked during a tracing activity to + pass string \a data to the \c QTracer object. +*/ + +/*! + \fn void QTracer::record(const QVariant &data) + + This function is invoked during a tracing activity to + pass abitrary (non-integer, non-string) \a data to + the \c QTracer object. +*/ + +/*! + \class QTraceGuard + \since 5.2 + \inmodule QtCore + + \brief The QTraceGuard class facilitates notifications to + \c QTracer objects. + + \c QTraceGuard objects are typically implicitly created on the + stack when using the \c qCTrace or \c qCTraceGuard macros and + are associated to a \c QLoggingCategory. + + The constructor of a \c QTraceGuard objects checks whether + its associated category is enabled, and if so, informs all + \c QTracer objects registered with the category that a + tracing activity starts. + + The destructor of a \c QTraceGuard objects checks whether + its associated category is enabled, and if so, informs all + \c QTracer objects registered with the category that a + tracing activity ended. + + A \c QTraceGuard object created by \c qCTrace will be destroyed + at the end of the full expression, a guard created by + \c qCTraceGuard at the end of the block containing the macro. + + During the lifetime of a QTraceGuard object, its \c operator<<() + can be used to pass additional data to the active tracers. + The fast path handles only \c int and \c{const char *} data, + but it is possible to use arbitrary values wrapped in \c QVariants. + + \sa QTracer +*/ + +/*! + \fn QTraceGuard::QTraceGuard(QLoggingCategory &category) + \internal + + Constructs a trace guard object relaying to \a category. +*/ + +/*! + \fn QTraceGuard::~QTraceGuard() + \internal + + Destroys the trace guard object. +*/ + +/*! + \internal + + Calls \c start() on all registered tracers. +*/ + +void QTraceGuard::start() +{ + QLoggingCategory::Tracers &tracers = target->tracers; + for (int i = tracers.size(); --i >= 0; ) + tracers.at(i)->start(); +} + +/*! + \internal + + Calls \c end() on all registered tracers. +*/ + +void QTraceGuard::end() +{ + QLoggingCategory::Tracers &tracers = target->tracers; + for (int i = tracers.size(); --i >= 0; ) + tracers.at(i)->end(); +} + + +/*! + \internal + + This function is called for int parameters passed to the + qCTrace stream. +*/ + +QTraceGuard &QTraceGuard::operator<<(int msg) +{ + QLoggingCategory::Tracers &tracers = target->tracers; + for (int i = tracers.size(); --i >= 0; ) + tracers.at(i)->record(msg); + return *this; +} + +/*! + \internal + + This function is called for string parameters passed to the + qCTrace stream. +*/ + +QTraceGuard &QTraceGuard::operator<<(const char *msg) +{ + QLoggingCategory::Tracers &tracers = target->tracers; + for (int i = tracers.size(); --i >= 0; ) + tracers.at(i)->record(msg); + return *this; +} + + +/*! + \internal + + This function is called for QVariant parameters passed to the + qCTrace stream. +*/ + +QTraceGuard &QTraceGuard::operator<<(const QVariant &msg) +{ + QLoggingCategory::Tracers &tracers = target->tracers; + for (int i = tracers.size(); --i >= 0; ) + tracers.at(i)->record(msg); + return *this; +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h index 90111c96fa..23b25b5e3f 100644 --- a/src/corelib/io/qloggingcategory.h +++ b/src/corelib/io/qloggingcategory.h @@ -44,9 +44,13 @@ #include <QtCore/qglobal.h> #include <QtCore/qdebug.h> +#include <QtCore/qvector.h> QT_BEGIN_NAMESPACE +class QTracer; +class QTraceGuard; + class Q_CORE_EXPORT QLoggingCategory { Q_DISABLE_COPY(QLoggingCategory) @@ -76,13 +80,18 @@ public: static void setFilterRules(const QString &rules); private: + friend class QLoggingRegistry; + friend class QTraceGuard; + friend class QTracer; + const char *name; bool enabledDebug; bool enabledWarning; bool enabledCritical; - - friend class QLoggingRegistry; + bool enabledTrace; + typedef QVector<QTracer *> Tracers; + Tracers tracers; }; template <> @@ -103,6 +112,56 @@ inline bool QLoggingCategory::isEnabled<QtCriticalMsg>() const return enabledCritical; } +template <> +inline bool QLoggingCategory::isEnabled<QtTraceMsg>() const +{ + return enabledTrace; +} + +class Q_CORE_EXPORT QTracer +{ + Q_DISABLE_COPY(QTracer) +public: + QTracer() {} + virtual ~QTracer() {} + + void addToCategory(QLoggingCategory &category); + + virtual void start() {} + virtual void end() {} + virtual void record(int) {} + virtual void record(const char *) {} + virtual void record(const QVariant &) {} +}; + +class Q_CORE_EXPORT QTraceGuard +{ + Q_DISABLE_COPY(QTraceGuard) +public: + QTraceGuard(QLoggingCategory &category) + { + target = category.isEnabled<QtTraceMsg>() ? &category : 0; + if (target) + start(); + } + + ~QTraceGuard() + { + if (target) + end(); + } + + QTraceGuard &operator<<(int msg); + QTraceGuard &operator<<(const char *msg); + QTraceGuard &operator<<(const QVariant &msg); + +private: + void start(); + void end(); + + QLoggingCategory *target; +}; + #define Q_DECLARE_LOGGING_CATEGORY(name) \ extern QLoggingCategory &name(); @@ -123,6 +182,17 @@ inline bool QLoggingCategory::isEnabled<QtCriticalMsg>() const #define qCCritical(category) \ for (bool enabled = category().isEnabled<QtCriticalMsg>(); enabled; enabled = false) \ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical() +#define qCTrace(category) \ + for (bool enabled = category.isEnabled<QtTraceMsg>(); enabled; enabled = false) \ + QTraceGuard(category) + + +#define Q_TRACE_GUARD_NAME_HELPER(line) qTraceGuard ## line +#define Q_TRACE_GUARD_NAME(line) Q_TRACE_GUARD_NAME_HELPER(line) + +#define qCTraceGuard(category) \ + QTraceGuard Q_TRACE_GUARD_NAME(__LINE__)(category); + #if defined(QT_NO_DEBUG_OUTPUT) # undef qCDebug diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index a82e6f65f4..885b51709d 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -86,6 +86,9 @@ int QLoggingRule::pass(const QString &categoryName, QtMsgType msgType) const case QtCriticalMsg: fullCategory += QLatin1String(".critical"); break; + case QtTraceMsg: + fullCategory += QLatin1String(".trace"); + break; default: break; } @@ -288,6 +291,7 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat) bool debug = (cat->categoryName() == qtDefaultCategoryName); bool warning = true; bool critical = true; + bool trace = true; QString categoryName = QLatin1String(cat->categoryName()); QLoggingRegistry *reg = QLoggingRegistry::instance(); @@ -301,11 +305,15 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat) filterpass = item.pass(categoryName, QtCriticalMsg); if (filterpass != 0) critical = (filterpass > 0); + filterpass = item.pass(categoryName, QtTraceMsg); + if (filterpass != 0) + trace = (filterpass > 0); } cat->setEnabled(QtDebugMsg, debug); cat->setEnabled(QtWarningMsg, warning); cat->setEnabled(QtCriticalMsg, critical); + cat->setEnabled(QtTraceMsg, trace); } diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index eab3890beb..3c6d294916 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -141,7 +141,8 @@ static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context) if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) { void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction; - oldAction(signum, info, context); + if (oldAction) + oldAction(signum, info, context); } else { void (*oldAction)(int) = vsa->sa_handler; diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp index ee95e590f9..988d076025 100644 --- a/src/corelib/io/qurlidna.cpp +++ b/src/corelib/io/qurlidna.cpp @@ -61,6 +61,11 @@ struct NameprepCaseFoldingEntry { ushort mapping[4]; }; +#if defined(Q_CC_MSVC) && _MSC_VER < 1600 +inline bool operator<(const NameprepCaseFoldingEntry &one, const NameprepCaseFoldingEntry &other) +{ return one.uc < other.uc; } +#endif + inline bool operator<(uint one, const NameprepCaseFoldingEntry &other) { return one < other.uc; } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 1799cf6a24..8617b17419 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -150,15 +150,20 @@ QString QCoreApplicationPrivate::macMenuBarName() #endif QString QCoreApplicationPrivate::appName() const { - static QString applName; + static QBasicMutex applicationNameMutex; + QMutexLocker locker(&applicationNameMutex); + + if (applicationName.isNull()) { #ifdef Q_OS_MAC - applName = macMenuBarName(); + applicationName = macMenuBarName(); #endif - if (applName.isEmpty() && argv[0]) { - char *p = strrchr(argv[0], '/'); - applName = QString::fromLocal8Bit(p ? p + 1 : argv[0]); + if (applicationName.isEmpty() && argv[0]) { + char *p = strrchr(argv[0], '/'); + applicationName = QString::fromLocal8Bit(p ? p + 1 : argv[0]); + } } - return applName; + + return applicationName; } #endif diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 6a3bea9c9e..477b8cfcfe 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -83,6 +83,7 @@ public: ~QCoreApplicationPrivate(); QString appName() const; + mutable QString applicationName; #ifdef Q_OS_MAC static QString macMenuBarName(); diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 17678fcbba..d1113e4eae 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -70,16 +70,24 @@ static jclass getCachedClass(JNIEnv *env, const char *className) QString key = QLatin1String(className); QHash<QString, jclass>::iterator it = cachedClasses->find(key); if (it == cachedClasses->end()) { - jclass c = env->FindClass(className); + QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader(); + if (!classLoader.isValid()) + return 0; + + QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(QLatin1String(className)); + QJNIObjectPrivate classObject = classLoader.callObjectMethod("loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;", + stringName.object()); if (env->ExceptionCheck()) { - c = 0; #ifdef QT_DEBUG env->ExceptionDescribe(); #endif // QT_DEBUG env->ExceptionClear(); } - if (c) - clazz = static_cast<jclass>(env->NewGlobalRef(c)); + + if (classObject.isValid()) + clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object())); + cachedClasses->insert(key, clazz); } else { clazz = it.value(); @@ -160,10 +168,12 @@ QJNIEnvironmentPrivate::QJNIEnvironmentPrivate() : jniEnv(0) { JavaVM *vm = QtAndroidPrivate::javaVM(); - if (vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) != JNI_EDETACHED) - return; + if (vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) == JNI_EDETACHED) { + if (vm->AttachCurrentThread(&jniEnv, 0) < 0) + return; + } - if (vm->AttachCurrentThread(&jniEnv, 0) < 0) + if (!jniEnv) return; if (!refCount->hasLocalData()) diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index a95194b66a..fbcd0606e6 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE static JavaVM *g_javaVM = Q_NULLPTR; static jobject g_jActivity = Q_NULLPTR; +static jobject g_jClassLoader = Q_NULLPTR; static inline bool exceptionCheck(JNIEnv *env) { @@ -79,6 +80,20 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) if (exceptionCheck(env)) return JNI_ERR; + + + jmethodID classLoaderMethodID = env->GetStaticMethodID(jQtNative, + "classLoader", + "()Ljava/lang/ClassLoader;"); + + if (exceptionCheck(env)) + return JNI_ERR; + + jobject classLoader = env->CallStaticObjectMethod(jQtNative, classLoaderMethodID); + if (exceptionCheck(env)) + return JNI_ERR; + + g_jClassLoader = env->NewGlobalRef(classLoader); g_jActivity = env->NewGlobalRef(activity); g_javaVM = vm; @@ -96,4 +111,9 @@ JavaVM *QtAndroidPrivate::javaVM() return g_javaVM; } +jobject QtAndroidPrivate::classLoader() +{ + return g_jClassLoader; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 8719ae044b..39059db215 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -63,6 +63,7 @@ namespace QtAndroidPrivate Q_CORE_EXPORT jobject activity(); Q_CORE_EXPORT JavaVM *javaVM(); Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); + jobject classLoader(); } QT_END_NAMESPACE diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index a61147ad9c..825b3289c7 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -91,7 +91,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, // Allocate additional space if array is growing if (options & Grow) - capacity = qAllocMore(objectSize * capacity, headerSize) / int(objectSize); + capacity = qAllocMore(int(objectSize * capacity), int(headerSize)) / int(objectSize); size_t allocSize = headerSize + objectSize * capacity; diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm index 43a0d67e74..deb5d5eb1d 100644 --- a/src/corelib/tools/qlocale_mac.mm +++ b/src/corelib/tools/qlocale_mac.mm @@ -166,6 +166,11 @@ static QString macTimeToString(const QTime &time, bool short_format) return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); } +// Mac uses the Unicode CLDR format codes +// http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table +// See also qtbase/util/local_database/dateconverter.py +// Makes the assumption that input formats are always well formed and consecutive letters +// never exceed the maximum for the format code. static QString macToQtFormat(const QString &sys_fmt) { QString result; @@ -185,55 +190,97 @@ static QString macToQtFormat(const QString &sys_fmt) int repeat = qt_repeatCount(sys_fmt, i); switch (c.unicode()) { - case 'G': // Qt doesn't support these :( - case 'Y': - case 'D': - case 'F': - case 'w': - case 'W': - case 'g': + // Qt does not support the following options + case 'G': // Era (1..5): 4 = long, 1..3 = short, 5 = narrow + case 'Y': // Year of Week (1..n): 1..n = padded number + case 'U': // Cyclic Yar Name (1..5): 4 = long, 1..3 = short, 5 = narrow + case 'Q': // Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number + case 'q': // Standalone Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number + case 'w': // Week of Year (1..2): 1..2 = padded number + case 'W': // Week of Month (1): 1 = number + case 'D': // Day of Year (1..3): 1..3 = padded number + case 'F': // Day of Week in Month (1): 1 = number + case 'g': // Modified Julian Day (1..n): 1..n = padded number + case 'A': // Milliseconds in Day (1..n): 1..n = padded number break; - case 'u': // extended year - use 'y' - if (repeat < 4) + case 'y': // Year (1..n): 2 = short year, 1 & 3..n = padded number + case 'u': // Extended Year (1..n): 2 = short year, 1 & 3..n = padded number + // Qt only supports long (4) or short (2) year, use long for all others + if (repeat == 2) result += QLatin1String("yy"); else result += QLatin1String("yyyy"); break; - case 'S': // fractional second - if (repeat < 3) - result += QLatin1Char('z'); + case 'M': // Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow + case 'L': // Standalone Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow + // Qt only supports long, short and number, use short for narrow + if (repeat == 5) + result += QLatin1String("MMM"); else - result += QLatin1String("zzz"); + result += QString(repeat, QLatin1Char('M')); break; - case 'E': - if (repeat <= 3) - result += QLatin1String("ddd"); - else + case 'd': // Day of Month (1..2): 1..2 padded number + result += QString(repeat, c); + break; + case 'E': // Day of Week (1..6): 4 = long, 1..3 = short, 5..6 = narrow + // Qt only supports long, short and padded number, use short for narrow + if (repeat == 4) result += QLatin1String("dddd"); + else + result += QLatin1String("ddd"); break; - case 'e': - if (repeat >= 2) - result += QLatin1String("dd"); + case 'e': // Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number + case 'c': // Standalone Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number + // Qt only supports long, short and padded number, use short for narrow + if (repeat >= 5) + result += QLatin1String("ddd"); else - result += QLatin1Char('d'); + result += QString(repeat, QLatin1Char('d')); break; - case 'a': + case 'a': // AM/PM (1): 1 = short + // Translate to Qt uppercase AM/PM result += QLatin1String("AP"); break; - case 'k': + case 'h': // Hour [1..12] (1..2): 1..2 = padded number + case 'K': // Hour [0..11] (1..2): 1..2 = padded number + case 'j': // Local Hour [12 or 24] (1..2): 1..2 = padded number + // Qt h is local hour + result += QString(repeat, QLatin1Char('h')); + break; + case 'H': // Hour [0..23] (1..2): 1..2 = padded number + case 'k': // Hour [1..24] (1..2): 1..2 = padded number + // Qt H is 0..23 hour result += QString(repeat, QLatin1Char('H')); break; - case 'K': - result += QString(repeat, QLatin1Char('h')); + case 'm': // Minutes (1..2): 1..2 = padded number + case 's': // Seconds (1..2): 1..2 = padded number + result += QString(repeat, c); + break; + case 'S': // Fractional second (1..n): 1..n = tuncates to decimal places + // Qt uses msecs either unpadded or padded to 3 places + if (repeat < 3) + result += QLatin1Char('z'); + else + result += QLatin1String("zzz"); break; - case 'z': - case 'Z': - case 'v': + case 'z': // Time Zone (1..4) + case 'Z': // Time Zone (1..5) + case 'O': // Time Zone (1, 4) + case 'v': // Time Zone (1, 4) + case 'V': // Time Zone (1..4) + case 'X': // Time Zone (1..5) + case 'x': // Time Zone (1..5) result += QLatin1Char('t'); break; default: - result += QString(repeat, c); + // a..z and A..Z are reserved for format codes, so any occurrence of these not + // already processed are not known and so unsupported formats to be ignored. + // All other chars are allowed as literals. + if (c < QLatin1Char('A') || c > QLatin1Char('z') || + (c > QLatin1Char('Z') && c < QLatin1Char('a'))) { + result += QString(repeat, c); + } break; } diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9625737d7f..239cf0446a 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3895,7 +3895,7 @@ static inline __m128i mergeQuestionMarks(__m128i chunk) # else // SSE has no compare instruction for unsigned comparison. // The variables must be shiffted + 0x8000 to be compared - const __m128i signedBitOffset = _mm_set1_epi16(0x8000); + const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000)); const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000)); const __m128i signedChunk = _mm_add_epi16(chunk, signedBitOffset); diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 701082c7e6..2eaed65148 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -934,8 +934,8 @@ inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); } inline void QString::reserve(int asize) { - if (d->ref.isShared() || uint(asize) + 1u > d->alloc) - reallocData(uint(asize) + 1u); + if (d->ref.isShared() || uint(asize) >= d->alloc) + reallocData(qMax(asize, d->size) + 1u); if (!d->capacityReserved) { // cannot set unconditionally, since d could be the shared_null/shared_empty (which is const) diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index d8b8ee81da..62b8f5f7b6 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -618,7 +618,7 @@ void QTzTimeZonePrivate::init(const QByteArray &olsenId) // Offsets are stored as total offset, want to know separate UTC and DST offsets // so find the first non-dst transition to use as base UTC Offset - int utcOffset; + int utcOffset = 0; foreach (const QTzTransition &tran, tranList) { if (!typeList.at(tran.tz_typeind).tz_isdst) { utcOffset = typeList.at(tran.tz_typeind).tz_gmtoff; |