summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2014-11-18 14:32:38 -0800
committerThiago Macieira <thiago.macieira@intel.com>2015-01-11 03:40:38 +0100
commit2c01d402e19b6137cf24794cbc4533a2b8b2d816 (patch)
treed0c0aaa93128a007b604fa3fcd25b8d9c5008723 /src/corelib/io
parente00d8ad86b8961e514fc91534127f5aa62c3b22f (diff)
QDebug: pretty-print QStrings and QStringRefs
[ChangeLog][QtCore][QDebug] Printing of QStrings and QStringRefs whenever "noquote" is not active now prints the strings in a format that can be copied back to C++ code. All characters that aren't printable in US-ASCII are escaped (this includes printable Unicode characters outside of US-ASCII). Pretty-printing will not respect QTextFormat padding or field widths. Change-Id: I169a8a0508e24693f5652f0129defe7f709e5d08 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qdebug.cpp103
-rw-r--r--src/corelib/io/qdebug.h5
-rw-r--r--src/corelib/io/qtextstream.cpp4
-rw-r--r--src/corelib/io/qtextstream.h1
4 files changed, 109 insertions, 4 deletions
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 050a48bd65..d8b77dd603 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Intel Corporation.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,9 +41,12 @@
#include "qdebug.h"
#include <private/qtextstream_p.h>
+#include <private/qtools_p.h>
QT_BEGIN_NAMESPACE
+using QtMiscUtils::toHexUpper;
+
// This file is needed to force compilation of QDebug into the kernel library.
/*!
@@ -168,6 +172,105 @@ void QDebug::putUcs4(uint ucs4)
maybeQuote('\'');
}
+template <typename Char>
+static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, int length)
+{
+ QChar quote(QLatin1Char('"'));
+ d->write(&quote, 1);
+
+ const Char *end = begin + length;
+ for (const Char *p = begin; p != end; ++p) {
+ if (sizeof(Char) == sizeof(QChar)) {
+ int runLength = 0;
+ while (p + runLength != end &&
+ p[runLength] < 0x7f && p[runLength] >= 0x20 && p[runLength] != '\\' && p[runLength] != '"')
+ ++runLength;
+ if (runLength) {
+ d->write(reinterpret_cast<const QChar *>(p), runLength);
+ p += runLength - 1;
+ continue;
+ }
+ }
+
+ // print as an escape sequence
+ int buflen = 2;
+ ushort buf[sizeof "\\U12345678" - 1];
+ buf[0] = '\\';
+
+ switch (*p) {
+ case '"':
+ case '\\':
+ buf[1] = *p;
+ break;
+ case '\b':
+ buf[1] = 'b';
+ break;
+ case '\f':
+ buf[1] = 'f';
+ break;
+ case '\n':
+ buf[1] = 'n';
+ break;
+ case '\r':
+ buf[1] = 'r';
+ break;
+ case '\t':
+ buf[1] = 't';
+ break;
+ default:
+ if (QChar::isHighSurrogate(*p)) {
+ if ((p + 1) != end && QChar::isLowSurrogate(p[1])) {
+ // properly-paired surrogates
+ uint ucs4 = QChar::surrogateToUcs4(*p, p[1]);
+ ++p;
+ buf[1] = 'U';
+ buf[2] = '0'; // toHexUpper(ucs4 >> 32);
+ buf[3] = '0'; // toHexUpper(ucs4 >> 28);
+ buf[4] = toHexUpper(ucs4 >> 20);
+ buf[5] = toHexUpper(ucs4 >> 16);
+ buf[6] = toHexUpper(ucs4 >> 12);
+ buf[7] = toHexUpper(ucs4 >> 8);
+ buf[8] = toHexUpper(ucs4 >> 4);
+ buf[9] = toHexUpper(ucs4);
+ buflen = 10;
+ break;
+ }
+ // improperly-paired surrogates, fall through
+ }
+ buf[1] = 'u';
+ if (sizeof(Char) == 1) {
+ buf[2] = buf[3] = '0';
+ } else {
+ buf[2] = toHexUpper(*p >> 12);
+ buf[3] = toHexUpper(*p >> 8);
+ }
+ buf[4] = toHexUpper(*p >> 4);
+ buf[5] = toHexUpper(*p);
+ buflen = 6;
+ }
+ d->write(reinterpret_cast<QChar *>(buf), buflen);
+ }
+
+ d->write(&quote, 1);
+}
+
+/*!
+ \internal
+ Duplicated from QtTest::toPrettyUnicode().
+*/
+void QDebug::putString(const QChar *begin, size_t length)
+{
+ if (stream->testFlag(Stream::NoQuotes)) {
+ // no quotes, write the string directly too (no pretty-printing)
+ // this respects the QTextStream state, though
+ stream->ts.d_ptr->putString(begin, length);
+ } else {
+ // we'll reset the QTextStream formatting mechanisms, so save the state
+ QDebugStateSaver saver(*this);
+ stream->ts.d_ptr->params.reset();
+ putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), length);
+ }
+}
/*!
\fn QDebug::swap(QDebug &other)
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 99c2909aa0..a2d6598bce 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -78,6 +78,7 @@ class Q_CORE_EXPORT QDebug
} *stream;
void putUcs4(uint ucs4);
+ void putString(const QChar *begin, size_t length);
public:
inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
inline QDebug(QString *string) : stream(new Stream(string)) {}
@@ -118,8 +119,8 @@ public:
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
- inline QDebug &operator<<(const QString & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
- inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
+ inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
inline QDebug &operator<<(QLatin1String t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const QByteArray & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 5f3177e58f..771067fa14 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -806,7 +806,7 @@ inline void QTextStreamPrivate::restoreToSavedConverterState()
/*!
\internal
*/
-inline void QTextStreamPrivate::write(const QChar *data, int len)
+void QTextStreamPrivate::write(const QChar *data, int len)
{
if (string) {
// ### What about seek()??
@@ -885,7 +885,7 @@ inline void QTextStreamPrivate::putChar(QChar ch)
/*!
\internal
*/
-inline void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
+void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
{
QString pad;
int padLeft = 0, padRight = 0;
diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h
index 5c75a006af..b15e7772e2 100644
--- a/src/corelib/io/qtextstream.h
+++ b/src/corelib/io/qtextstream.h
@@ -185,6 +185,7 @@ public:
private:
Q_DISABLE_COPY(QTextStream)
friend class QDebugStateSaverPrivate;
+ friend class QDebug;
QScopedPointer<QTextStreamPrivate> d_ptr;
};