Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qdebug.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifdef QT_NO_DEBUG
6#undef QT_NO_DEBUG
7#endif
8#ifdef qDebug
9#undef qDebug
10#endif
11
12#include "qdebug.h"
13#include "private/qdebug_p.h"
14#include "qmetaobject.h"
15#include <private/qtextstream_p.h>
16#include <private/qtools_p.h>
17
18#include <q20chrono.h>
19
21
22using namespace QtMiscUtils;
23
24/*
25 Returns a human readable representation of the first \a maxSize
26 characters in \a data. The size, \a len, is a 64-bit quantity to
27 avoid truncation due to implicit conversions in callers.
28*/
30{
31 if (!data)
32 return "(null)";
33
35 for (qsizetype i = 0; i < qMin(len, maxSize); ++i) {
36 char c = data[i];
37 if (isAsciiPrintable(c)) {
38 out += c;
39 } else {
40 switch (c) {
41 case '\n':
42 out += "\\n";
43 break;
44 case '\r':
45 out += "\\r";
46 break;
47 case '\t':
48 out += "\\t";
49 break;
50 default: {
51 const char buf[] = {
52 '\\',
53 'x',
54 toHexLower(uchar(c) / 16),
55 toHexLower(uchar(c) % 16),
56 0
57 };
58 out += buf;
59 }
60 }
61 }
62 }
63
64 if (maxSize < len)
65 out += "...";
66
67 return out;
68}
69
70// This file is needed to force compilation of QDebug into the kernel library.
71
159// Has been defined in the header / inlined before Qt 5.4
160QDebug::~QDebug()
161{
162 if (stream && !--stream->ref) {
163 if (stream->space && stream->buffer.endsWith(u' '))
164 stream->buffer.chop(1);
165 if (stream->message_output) {
167 stream->context,
168 stream->buffer);
169 }
170 delete stream;
171 }
172}
173
177void QDebug::putUcs4(uint ucs4)
178{
179 maybeQuote('\'');
180 if (ucs4 < 0x20) {
181 stream->ts << "\\x" << Qt::hex << ucs4 << Qt::reset;
182 } else if (ucs4 < 0x80) {
183 stream->ts << char(ucs4);
184 } else {
185 if (ucs4 < 0x10000)
186 stream->ts << "\\u" << qSetFieldWidth(4);
187 else
188 stream->ts << "\\U" << qSetFieldWidth(8);
189 stream->ts << Qt::hex << qSetPadChar(u'0') << ucs4 << Qt::reset;
190 }
191 maybeQuote('\'');
192}
193
194// These two functions return true if the character should be printed by QDebug.
195// For QByteArray, this is technically identical to US-ASCII isprint();
196// for QString, we use QChar::isPrint, which requires a full UCS-4 decode.
197static inline bool isPrintable(char32_t ucs4) { return QChar::isPrint(ucs4); }
198static inline bool isPrintable(char16_t uc) { return QChar::isPrint(uc); }
199static inline bool isPrintable(uchar c)
200{ return isAsciiPrintable(c); }
201
202template <typename Char>
203static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, size_t length, bool isUnicode = true)
204{
205 QChar quote(u'"');
206 d->write(&quote, 1);
207
208 bool lastWasHexEscape = false;
209 const Char *end = begin + length;
210 for (const Char *p = begin; p != end; ++p) {
211 // check if we need to insert "" to break an hex escape sequence
212 if (Q_UNLIKELY(lastWasHexEscape)) {
213 if (fromHex(*p) != -1) {
214 // yes, insert it
215 QChar quotes[] = { quote, quote };
216 d->write(quotes, 2);
217 }
218 lastWasHexEscape = false;
219 }
220
221 if (sizeof(Char) == sizeof(QChar)) {
222 // Surrogate characters are category Cs (Other_Surrogate), so isPrintable = false for them
223 qsizetype runLength = 0;
224 while (p + runLength != end &&
225 isPrintable(p[runLength]) && p[runLength] != '\\' && p[runLength] != '"')
226 ++runLength;
227 if (runLength) {
228 d->write(reinterpret_cast<const QChar *>(p), runLength);
229 p += runLength - 1;
230 continue;
231 }
232 } else if (isPrintable(*p) && *p != '\\' && *p != '"') {
233 QChar c = QLatin1Char(*p);
234 d->write(&c, 1);
235 continue;
236 }
237
238 // print as an escape sequence (maybe, see below for surrogate pairs)
239 qsizetype buflen = 2;
240 char16_t buf[std::char_traits<char>::length("\\U12345678")];
241 buf[0] = '\\';
242
243 switch (*p) {
244 case '"':
245 case '\\':
246 buf[1] = *p;
247 break;
248 case '\b':
249 buf[1] = 'b';
250 break;
251 case '\f':
252 buf[1] = 'f';
253 break;
254 case '\n':
255 buf[1] = 'n';
256 break;
257 case '\r':
258 buf[1] = 'r';
259 break;
260 case '\t':
261 buf[1] = 't';
262 break;
263 default:
264 if (!isUnicode) {
265 // print as hex escape
266 buf[1] = 'x';
267 buf[2] = toHexUpper(uchar(*p) >> 4);
268 buf[3] = toHexUpper(uchar(*p));
269 buflen = 4;
270 lastWasHexEscape = true;
271 break;
272 }
274 if ((p + 1) != end && QChar::isLowSurrogate(p[1])) {
275 // properly-paired surrogates
276 char32_t ucs4 = QChar::surrogateToUcs4(*p, p[1]);
277 if (isPrintable(ucs4)) {
278 buf[0] = *p;
279 buf[1] = p[1];
280 buflen = 2;
281 } else {
282 buf[1] = 'U';
283 buf[2] = '0'; // toHexUpper(ucs4 >> 32);
284 buf[3] = '0'; // toHexUpper(ucs4 >> 28);
285 buf[4] = toHexUpper(ucs4 >> 20);
286 buf[5] = toHexUpper(ucs4 >> 16);
287 buf[6] = toHexUpper(ucs4 >> 12);
288 buf[7] = toHexUpper(ucs4 >> 8);
289 buf[8] = toHexUpper(ucs4 >> 4);
290 buf[9] = toHexUpper(ucs4);
291 buflen = 10;
292 }
293 ++p;
294 break;
295 }
296 // improperly-paired surrogates, fall through
297 }
298 buf[1] = 'u';
299 buf[2] = toHexUpper(char16_t(*p) >> 12);
300 buf[3] = toHexUpper(char16_t(*p) >> 8);
301 buf[4] = toHexUpper(*p >> 4);
302 buf[5] = toHexUpper(*p);
303 buflen = 6;
304 }
305 d->write(reinterpret_cast<QChar *>(buf), buflen);
306 }
307
308 d->write(&quote, 1);
309}
310
315void QDebug::putString(const QChar *begin, size_t length)
316{
317 if (stream->noQuotes) {
318 // no quotes, write the string directly too (no pretty-printing)
319 // this respects the QTextStream state, though
320 stream->ts.d_ptr->putString(begin, qsizetype(length));
321 } else {
322 // we'll reset the QTextStream formatting mechanisms, so save the state
323 QDebugStateSaver saver(*this);
324 stream->ts.d_ptr->params.reset();
325 putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const char16_t *>(begin), length);
326 }
327}
328
333void QDebug::putByteArray(const char *begin, size_t length, Latin1Content content)
334{
335 if (stream->noQuotes) {
336 // no quotes, write the string directly too (no pretty-printing)
337 // this respects the QTextStream state, though
338 QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, qsizetype(length))
340 stream->ts.d_ptr->putString(string);
341 } else {
342 // we'll reset the QTextStream formatting mechanisms, so save the state
343 QDebugStateSaver saver(*this);
344 stream->ts.d_ptr->params.reset();
345 putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const uchar *>(begin),
346 length, content == ContainsLatin1);
347 }
348}
349
351{
352 using namespace std::chrono;
353 using namespace q20::chrono;
354
355 if (num == 1 && den > 1) {
356 // sub-multiple of seconds
357 char prefix = '\0';
358 auto tryprefix = [&](auto d, char c) {
359 static_assert(decltype(d)::num == 1, "not an SI prefix");
360 if (den == decltype(d)::den)
361 prefix = c;
362 };
363
364 // "u" should be "µ", but debugging output is not always UTF-8-safe
365 tryprefix(std::milli{}, 'm');
366 tryprefix(std::micro{}, 'u');
367 tryprefix(std::nano{}, 'n');
368 tryprefix(std::pico{}, 'p');
369 tryprefix(std::femto{}, 'f');
370 tryprefix(std::atto{}, 'a');
371 // uncommon ones later
372 tryprefix(std::centi{}, 'c');
373 tryprefix(std::deci{}, 'd');
374 if (prefix) {
375 char unit[3] = { prefix, 's' };
376 return QByteArray(unit, sizeof(unit) - 1);
377 }
378 }
379
380 const char *unit = nullptr;
381 if (num > 1 && den == 1) {
382 // multiple of seconds - but we don't use SI prefixes
383 auto tryunit = [&](auto d, const char *name) {
384 static_assert(decltype(d)::period::den == 1, "not a multiple of a second");
385 if (unit || num % decltype(d)::period::num)
386 return;
387 unit = name;
388 num /= decltype(d)::period::num;
389 };
390 tryunit(years{}, "yr");
391 tryunit(weeks{}, "wk");
392 tryunit(days{}, "d");
393 tryunit(hours{}, "h");
394 tryunit(minutes{}, "min");
395 }
396 if (!unit)
397 unit = "s";
398
399 if (num == 1 && den == 1)
400 return unit;
401 if (Q_UNLIKELY(num < 1 || den < 1))
402 return QString::asprintf("<invalid time unit %lld/%lld>", num, den).toLatin1();
403
404 // uncommon units: will return something like "[2/3]s"
405 // strlen("[/]min") = 6
406 char buf[2 * (std::numeric_limits<qint64>::digits10 + 2) + 10];
407 size_t len = 0;
408 auto appendChar = [&](char c) {
409 Q_ASSERT(len < sizeof(buf));
410 buf[len++] = c;
411 };
412 auto appendNumber = [&](qint64 value) {
413 if (value >= 10'000 && (value % 1000) == 0)
414 len += qsnprintf(buf + len, sizeof(buf) - len, "%.6g", double(value)); // "1e+06"
415 else
416 len += qsnprintf(buf + len, sizeof(buf) - len, "%lld", value);
417 };
418 appendChar('[');
419 appendNumber(num);
420 if (den != 1) {
421 appendChar('/');
422 appendNumber(den);
423 }
424 appendChar(']');
425 memcpy(buf + len, unit, strlen(unit));
426 return QByteArray(buf, len + strlen(unit));
427}
428
434void QDebug::putTimeUnit(qint64 num, qint64 den)
435{
436 stream->ts << timeUnit(num, den); // ### optimize
437}
438
453QDebug &QDebug::resetFormat()
454{
455 stream->ts.reset();
456 stream->space = true;
457 stream->noQuotes = false;
458 stream->verbosity = DefaultVerbosity;
459 return *this;
460}
461
1077{
1078public:
1080 : m_stream(stream),
1081 m_spaces(stream->space),
1082 m_noQuotes(stream->noQuotes),
1083 m_verbosity(stream->verbosity),
1084 m_streamParams(stream->ts.d_ptr->params)
1085 {
1086 }
1088 {
1089 const bool currentSpaces = m_stream->space;
1090 if (currentSpaces && !m_spaces)
1091 if (m_stream->buffer.endsWith(u' '))
1092 m_stream->buffer.chop(1);
1093
1094 m_stream->space = m_spaces;
1095 m_stream->noQuotes = m_noQuotes;
1096 m_stream->ts.d_ptr->params = m_streamParams;
1097 m_stream->verbosity = m_verbosity;
1098
1099 if (!currentSpaces && m_spaces)
1100 m_stream->ts << ' ';
1101 }
1102
1103 QDebug::Stream *m_stream;
1104
1105 // QDebug state
1106 const bool m_spaces;
1107 const bool m_noQuotes;
1108 const int m_verbosity;
1109
1110 // QTextStream state
1112};
1113
1114
1121QDebugStateSaver::QDebugStateSaver(QDebug &dbg)
1122 : d(new QDebugStateSaverPrivate(dbg.stream))
1123{
1124}
1125
1132QDebugStateSaver::~QDebugStateSaver()
1133{
1134 d->restoreState();
1135}
1136
1146{
1147 qt_QMetaEnum_flagDebugOperator<int>(debug, sizeofT, value);
1148}
1149
1150#ifndef QT_NO_QOBJECT
1187{
1188 QDebugStateSaver saver(dbg);
1189 dbg.nospace();
1190 QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
1191
1192 const int verbosity = dbg.verbosity();
1193 if (verbosity >= QDebug::DefaultVerbosity) {
1194 if (const char *scope = me.scope())
1195 dbg << scope << u"::";
1196 }
1197
1198 const char *key = me.valueToKey(static_cast<int>(value));
1199 const bool scoped = me.isScoped() || verbosity & 1;
1200 if (scoped || !key)
1201 dbg << me.enumName() << (!key ? u"(" : u"::");
1202
1203 if (key)
1204 dbg << key;
1205 else
1206 dbg << value << ')';
1207
1208 return dbg;
1209}
1210
1241{
1242 const int verbosity = debug.verbosity();
1243
1244 QDebugStateSaver saver(debug);
1245 debug.resetFormat();
1246 debug.noquote();
1247 debug.nospace();
1248
1249 const QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
1250
1251 const bool classScope = verbosity >= QDebug::DefaultVerbosity;
1252 if (classScope) {
1253 debug << u"QFlags<";
1254
1255 if (const char *scope = me.scope())
1256 debug << scope << u"::";
1257 }
1258
1259 const bool enumScope = me.isScoped() || verbosity > QDebug::MinimumVerbosity;
1260 if (enumScope) {
1261 debug << me.enumName();
1262 if (classScope)
1263 debug << '>';
1264 debug << '(';
1265 }
1266
1267 debug << me.valueToKeys(static_cast<int>(value));
1268
1269 if (enumScope)
1270 debug << ')';
1271
1272 return debug;
1273}
1274#endif // !QT_NO_QOBJECT
1275
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
static constexpr char32_t surrogateToUcs4(char16_t high, char16_t low) noexcept
Converts a UTF16 surrogate pair with the given high and low values to it's UCS-4-encoded code point.
Definition qchar.h:508
constexpr bool isLowSurrogate() const noexcept
Returns true if the QChar is the low part of a UTF16 surrogate (for example if its code point is in r...
Definition qchar.h:480
bool isPrint() const noexcept
Returns true if the character is a printable character; otherwise returns false.
Definition qchar.h:465
constexpr bool isHighSurrogate() const noexcept
Returns true if the QChar is the high part of a UTF16 surrogate (for example if its code point is in ...
Definition qchar.h:479
const QTextStreamPrivate::Params m_streamParams
Definition qdebug.cpp:1111
QDebug::Stream * m_stream
Definition qdebug.cpp:1103
QDebugStateSaverPrivate(QDebug::Stream *stream)
Definition qdebug.cpp:1079
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
const char * valueToKey(int value) const
Returns the string that is used as the name of the given enumeration value, or \nullptr if value is n...
QByteArray valueToKeys(int value) const
Returns a byte array of '|'-separated keys that represents the given value.
bool isScoped() const
const char * enumName() const
Returns the enum name of the flag (without the scope).
const char * scope() const
Returns the scope this enumerator was declared in.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
Combined button and popup list for selecting options.
qsizetype fromUtf8(uchar b, OutputPtr &dst, InputPtr &src, InputPtr end)
Q_CORE_EXPORT QByteArray toPrintable(const char *data, qint64 len, qsizetype maxSize)
Definition qdebug.cpp:29
constexpr int isAsciiPrintable(char32_t ch) noexcept
Definition qtools_p.h:104
constexpr char toHexUpper(char32_t value) noexcept
Definition qtools_p.h:27
constexpr char toHexLower(char32_t value) noexcept
Definition qtools_p.h:32
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & reset(QTextStream &stream)
Calls QTextStream::reset() on stream and returns stream.
std::chrono::duration< IntRep, std::ratio< 86400 > > days
Definition q20chrono.h:52
std::chrono::duration< IntRep, std::ratio_multiply< std::ratio< 146097, 400 >, days::period > > years
Definition q20chrono.h:54
std::chrono::duration< IntRep, std::ratio_multiply< std::ratio< 7 >, days::period > > weeks
Definition q20chrono.h:53
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
#define Q_UNLIKELY(x)
QDebug qt_QMetaEnum_debugOperator(QDebug &dbg, qint64 value, const QMetaObject *meta, const char *name)
Definition qdebug.cpp:1186
void qt_QMetaEnum_flagDebugOperator(QDebug &debug, size_t sizeofT, int value)
Definition qdebug.cpp:1145
static void putEscapedString(QTextStreamPrivate *d, const Char *begin, size_t length, bool isUnicode=true)
Definition qdebug.cpp:203
static QByteArray timeUnit(qint64 num, qint64 den)
Definition qdebug.cpp:350
static bool isPrintable(char32_t ucs4)
Definition qdebug.cpp:197
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLuint64 key
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
void ** params
const GLubyte * c
GLenum GLsizei len
GLfloat GLfloat p
[1]
GLuint num
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
char Char
QTextStreamManipulator qSetPadChar(QChar ch)
QTextStreamManipulator qSetFieldWidth(int width)
unsigned char uchar
Definition qtypes.h:27
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
static QString quote(const QString &str)
QTextStream out(stdout)
[7]
\inmodule QtCore \reentrant
Definition qchar.h:17
\inmodule QtCore
int indexOfEnumerator(const char *name) const
Finds enumerator name and returns its index; otherwise returns -1.
QMetaEnum enumerator(int index) const
Returns the meta-data for the enumerator with the given index.