xca/lib/debug_info.cpp
Christian Hohnstaedt d256da3858 Fix debugging-info on Windows
The file separator bite again
2024-09-08 11:42:57 +02:00

167 lines
4.0 KiB
C++

/* vi: set sw=4 ts=4:
*
* Copyright (C) 2023 Christian Hohnstaedt.
*
* All rights reserved.
*/
#include <QStringList>
#include <QDebug>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QDir>
#include <stdlib.h>
#include "debug_info.h"
#include "base.h"
#include "func.h"
QList<dbg_pattern> debug_info::patternlist;
bool debug_info::all = false;
dbg_pattern::dbg_pattern(QString part)
: first(0), last(INT_MAX), inv(false)
{
bool ok;
if (part[0] == '-') {
inv = true;
part.remove(0, 1);
}
file = func = part;
QStringList file_num = part.split(":");
if (file_num.size() == 2) {
file = file_num[0];
file_num = file_num[1].split("-");
if (file_num.size() == 1) {
first = last = file_num[0].toUInt();
} else {
if (!file_num[0].isEmpty()) {
first = file_num[0].toUInt(&ok);
Q_ASSERT(ok);
}
if (!file_num[1].isEmpty()) {
last = file_num[1].toUInt(&ok);
Q_ASSERT(ok);
}
}
}
file = QDir::cleanPath(file);
qDebug() << "New debug match" << (inv ? "Not" : "") << file << func << first << last;
}
bool dbg_pattern::match(const QString &curr_file, const QString &curr_func,
unsigned line) const
{
// QTextStream out(stdout);
// out << QString("MATCH %1:%2(%3)\n").arg(curr_file).arg(curr_func).arg(line);
if (curr_func == func)
return true;
if (curr_func.endsWith(QString("::%1").arg(func)))
return true;
if (curr_file != file && !file.endsWith(QString("/%1").arg(curr_file)))
return false;
if (line >= first && line <= last)
return true;
return false;
}
void debug_info::set_debug(const QString &dbg)
{
bool local_all = false;
all = true;
if (isEmpty()) {
foreach(QString part, dbg.split(",")) {
if (part.toLower() == "all") {
local_all = true;
continue;
}
dbg_pattern d(part);
patternlist.insert(d.invert() ? 0 : patternlist.size(), d);
}
}
all = local_all;
}
debug_info::debug_info(const QMessageLogContext &ctx)
: line(0)
{
line = ctx.line;
if (ctx.file && ctx.line) {
QFileInfo f(ctx.file);
short_file = f.fileName();
short_func = ctx.function;
int pos = short_func.indexOf("(");
short_func.remove(pos, short_func.size());
pos = short_func.lastIndexOf(" ");
short_func.remove(0, pos +1);
}
//std::cerr << "DBG '" << (ctx.function ?: "(NULL)" )<< "' '" << CCHAR(short_func) << "' " << short_file << std::endl;
}
QString debug_info::log_prefix() const
{
if (short_file == nullptr && line == 0)
return QString();
return QString(" " COL_MAGENTA "%1" COL_GREEN COL_BOLD ":%2 " COL_BLUE "%3")
.arg(short_file).arg(line).arg(short_func);
}
bool debug_info::do_debug() const
{
foreach(dbg_pattern pattern, patternlist) {
if (pattern.match(short_file, short_func, line))
return !pattern.invert();
}
return all;
}
static void myMessageOutput(QtMsgType type, const QMessageLogContext &ctx,
const QString &msg)
{
static QElapsedTimer *t;
static int abort_on_warning = -1;
const char *severity = "Unknown", *warn_msg = NULL;
int el;
if (!t) {
t = new QElapsedTimer();
t->start();
}
if (abort_on_warning == -1) {
char *a = getenv("XCA_ABORT_ON_WARNING");
abort_on_warning = a && *a;
}
debug_info dinfo(ctx);
el = t->elapsed();
switch (type) {
case QtDebugMsg:
if (!dinfo.do_debug())
return;
severity = COL_CYAN "Debug";
break;
case QtWarningMsg: warn_msg = "WARNING"; severity = COL_LRED "Warning"; break;
case QtCriticalMsg: warn_msg = "CRITICAL"; severity = COL_RED "Critical"; break;
case QtFatalMsg: warn_msg = "FATAL"; severity = COL_RED "Fatal"; break;
case QtInfoMsg: severity = COL_CYAN "Info"; break;
default: severity = COL_CYAN "Default"; break;
}
console_write(stderr, QString(COL_YELL "%1%2 %3:%5" COL_RESET " %4\n")
.arg(el/1000, 4)
.arg((el%1000)/100, 2, 10, QChar('0'))
.arg(severity).arg(msg)
.arg(dinfo.log_prefix()).toUtf8());
if (abort_on_warning == 1 && warn_msg) {
qFatal("Abort on %s", warn_msg);
}
}
void debug_info::init()
{
qInstallMessageHandler(myMessageOutput);
const char *d = getenv("XCA_DEBUG");
if (d && *d)
debug_info::set_debug(QString(d));
}