From 123ce761c058acc0222792e96c9aba22d06e619c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 5 Feb 2013 13:20:31 +0100 Subject: QT_MESSAGE_OUTPUT: add support for condition depending on the type The motivation is to enable coloration the way KDE currently does. It can now be achieved with a QT_MESSAGE_OUTPUT set to "%{appname}(%{category}) \033[31m%{if-debug}\033[34m%{endif}%{function}\033[0m: %{message}" I was thinking about supporting directly color using something like %{begin-category-color} that would be smart and detect if we are running on a terminal, but it would be less flexible in the way the colors van be configured. Changelog: QT_MESSAGE_OUTPUT can contain conditionals based on the type of the message Change-Id: Icd8de04734a94a3afcbf542a5b78b290a1914960 Reviewed-by: David Faure (KDE) --- src/corelib/global/qlogging.cpp | 87 +++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 16 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index c3ce405156..7204efc752 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -523,6 +523,11 @@ static const char functionTokenC[] = "%{function}"; static const char pidTokenC[] = "%{pid}"; static const char appnameTokenC[] = "%{appname}"; static const char threadidTokenC[] = "%{threadid}"; +static const char ifDebugTokenC[] = "%{if-debug}"; +static const char ifWarningTokenC[] = "%{if-warning}"; +static const char ifCriticalTokenC[] = "%{if-critical}"; +static const char ifFatalTokenC[] = "%{if-fatal}"; +static const char endifTokenC[] = "%{endif}"; static const char emptyTokenC[] = ""; static const char defaultPattern[] = "%{message}"; @@ -609,6 +614,10 @@ void QMessagePattern::setPattern(const QString &pattern) tokens = new const char*[lexemes.size() + 1]; tokens[lexemes.size()] = 0; + bool nestedIfError = false; + bool inIf = false; + QString error; + for (int i = 0; i < lexemes.size(); ++i) { const QString lexeme = lexemes.at(i); if (lexeme.startsWith(QLatin1String("%{")) @@ -632,23 +641,28 @@ void QMessagePattern::setPattern(const QString &pattern) tokens[i] = appnameTokenC; else if (lexeme == QLatin1String(threadidTokenC)) tokens[i] = threadidTokenC; - else { - tokens[i] = emptyTokenC; - QString error = QStringLiteral("QT_MESSAGE_PATTERN: Unknown placeholder %1\n") +#define IF_TOKEN(LEVEL) \ + else if (lexeme == QLatin1String(LEVEL)) { \ + if (inIf) \ + nestedIfError = true; \ + tokens[i] = LEVEL; \ + inIf = true; \ + } + IF_TOKEN(ifDebugTokenC) + IF_TOKEN(ifWarningTokenC) + IF_TOKEN(ifCriticalTokenC) + IF_TOKEN(ifFatalTokenC) +#undef IF_TOKEN + else if (lexeme == QLatin1String(endifTokenC)) { + tokens[i] = endifTokenC; + if (!inIf && !nestedIfError) + error += QStringLiteral("QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n"); + inIf = false; + } else { + tokens[i] = emptyTokenC; + error += QStringLiteral("QT_MESSAGE_PATTERN: Unknown placeholder %1\n") .arg(lexeme); - -#if defined(Q_OS_WINCE) - OutputDebugString(reinterpret_cast(error.utf16())); - continue; -#elif defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) - if (usingWinMain) { - OutputDebugString(reinterpret_cast(error.utf16())); - continue; - } -#endif - fprintf(stderr, "%s", error.toLocal8Bit().constData()); - fflush(stderr); } } else { char *literal = new char[lexeme.size() + 1]; @@ -658,6 +672,24 @@ void QMessagePattern::setPattern(const QString &pattern) tokens[i] = literal; } } + if (nestedIfError) + error += QStringLiteral("QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n"); + else if (inIf) + error += QStringLiteral("QT_MESSAGE_PATTERN: missing %{endif}\n"); + if (!error.isEmpty()) { +#if defined(Q_OS_WINCE) + OutputDebugString(reinterpret_cast(error.utf16())); + if (0) +#elif defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) + if (usingWinMain) { + OutputDebugString(reinterpret_cast(error.utf16())); + } else +#endif + { + fprintf(stderr, "%s", error.toLocal8Bit().constData()); + fflush(stderr); + } + } literals = new const char*[literalsVar.size() + 1]; literals[literalsVar.size()] = 0; memcpy(literals, literalsVar.constData(), literalsVar.size() * sizeof(const char*)); @@ -737,10 +769,16 @@ Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogCont if (pattern->tokens[0] == 0) return message; + bool skip = false; + // we do not convert file, function, line literals to local encoding due to overhead for (int i = 0; pattern->tokens[i] != 0; ++i) { const char *token = pattern->tokens[i]; - if (token == messageTokenC) { + if (token == endifTokenC) { + skip = false; + } else if (skip) { + // do nothing + } else if (token == messageTokenC) { message.append(str); } else if (token == categoryTokenC) { message.append(QLatin1String(context.category)); @@ -772,6 +810,14 @@ Q_CORE_EXPORT QString qMessageFormatString(QtMsgType type, const QMessageLogCont message.append(QLatin1String("0x")); message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16)); #endif +#define HANDLE_IF_TOKEN(LEVEL) \ + } else if (token == if##LEVEL##TokenC) { \ + skip = type != Qt##LEVEL##Msg; + HANDLE_IF_TOKEN(Debug) + HANDLE_IF_TOKEN(Warning) + HANDLE_IF_TOKEN(Critical) + HANDLE_IF_TOKEN(Fatal) +#undef HANDLE_IF_TOKEN } else { message.append(QLatin1String(token)); } @@ -1011,6 +1057,15 @@ void qErrnoWarning(int code, const char *msg, ...) \row \li \c %{type} \li "debug", "warning", "critical" or "fatal" \endtable + You can also use conditionals on the type of the message using \c %{if-debug}, + \c %{if-warning}, \c %{if-critical} or \c %{if-fatal} followed by an \c %{endif}. + What is inside the \c %{if-*} and \c %{endif} will only be printed if the type matches. + + Example: + \code + QT_MESSAGE_PATTERN="[%{if-debug}D%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}" + \endcode + The default \a pattern is "%{message}". The \a pattern can also be changed at runtime by setting the QT_MESSAGE_PATTERN -- cgit v1.2.3