Warning, file /utilities/kdebugsettings/src/kdebugsettingsutil.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2015-2023 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 0006 */ 0007 0008 #include "kdebugsettingsutil.h" 0009 #include "kdebugsettings_debug.h" 0010 #include "loadgroupmenu.h" 0011 #include <KLocalizedString> 0012 #include <QDir> 0013 #include <QFile> 0014 #include <QRegularExpression> 0015 #include <QStandardPaths> 0016 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0017 #include <QTextCodec> 0018 #endif 0019 0020 RenameCategory KDebugSettingsUtil::parseRenameCategory(QString line, const QString &filename) 0021 { 0022 RenameCategory category; 0023 int pos = line.indexOf(QLatin1Char('#')); 0024 if (pos != -1) { 0025 line.truncate(pos); 0026 line = line.simplified(); 0027 } 0028 0029 if (line.isEmpty()) { 0030 return category; 0031 } 0032 line = line.simplified(); 0033 const int space = line.indexOf(QLatin1Char(' ')); 0034 if (space == -1) { 0035 qCWarning(KDEBUGSETTINGS_LOG) << "Invalid categories file. Missing space. Syntax is logname<space>description + optional element. Line: " << line 0036 << " from file:" << filename << Qt::endl; 0037 return category; 0038 } 0039 0040 const QString originalName = line.left(space); 0041 0042 const QString newName = line.mid(space).simplified(); 0043 category.originalName = originalName; 0044 category.newName = newName; 0045 return category; 0046 } 0047 0048 RenameCategory::List KDebugSettingsUtil::readRenameCategories(const QString &filename) 0049 { 0050 RenameCategory::List insertCategories; 0051 0052 QFile file(filename); 0053 if (!file.open(QIODevice::ReadOnly)) { 0054 qCWarning(KDEBUGSETTINGS_LOG) << "Couldn't open" << filename; 0055 } else { 0056 QString data; 0057 QTextStream ts(&file); 0058 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0059 ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); 0060 #else 0061 ts.setEncoding(QStringConverter::Encoding::Latin1); 0062 #endif 0063 while (!ts.atEnd()) { 0064 data = ts.readLine().simplified(); 0065 const RenameCategory category = parseRenameCategory(data, filename); 0066 if (category.isValid()) { 0067 insertCategories.append(category); 0068 } 0069 } 0070 } 0071 return insertCategories; 0072 } 0073 0074 KdeLoggingCategory KDebugSettingsUtil::parseLineKdeLoggingCategory(QString line, const QString &filename) 0075 { 0076 KdeLoggingCategory category; 0077 const int pos = line.indexOf(QLatin1Char('#')); 0078 if (pos != -1) { 0079 line.truncate(pos); 0080 line = line.simplified(); 0081 } 0082 0083 if (line.isEmpty()) { 0084 return category; 0085 } 0086 line = line.simplified(); 0087 const int space = line.indexOf(QLatin1Char(' ')); 0088 if (space == -1) { 0089 qCWarning(KDEBUGSETTINGS_LOG) << "Invalid categories file. Missing space. Syntax is logname<space>description + optional element. Line: " << line 0090 << " from file:" << filename << Qt::endl; 0091 return category; 0092 } 0093 QString logName; 0094 QString description; 0095 QString defaultSeverity; 0096 QString identifier; 0097 0098 // TODO create an unique regularexpression 0099 0100 static const QRegularExpression regularExpressionUser(QStringLiteral("^([\\w._-]+)\\s*(.*)$")); 0101 QRegularExpressionMatch match = regularExpressionUser.match(line); 0102 if (match.hasMatch()) { 0103 logName = match.captured(1); 0104 description = match.captured(2); 0105 } 0106 0107 bool newFormatFound = false; 0108 static const QRegularExpression regularExpressionDefaultSeverityNewFormat( 0109 QStringLiteral("^(.*)\\s+DEFAULT_SEVERITY\\s+\\[(DEBUG|INFO|WARNING|CRITICAL)\\](?:\\s+(.*))?")); 0110 QRegularExpressionMatch match3 = regularExpressionDefaultSeverityNewFormat.match(description); 0111 QString defaultSeverityCaptured; 0112 QString potentialIdentifier; 0113 if (match3.hasMatch()) { 0114 newFormatFound = true; 0115 const QString descriptionCaptured = match3.captured(1); 0116 defaultSeverityCaptured = match3.captured(2); 0117 potentialIdentifier = match3.captured(3); 0118 if (!descriptionCaptured.isEmpty() && !defaultSeverityCaptured.isEmpty()) { 0119 description = descriptionCaptured; 0120 defaultSeverity = defaultSeverityCaptured; 0121 // qDebug() << " match.captured(1);" << descriptionCaptured; 0122 // qDebug() << " match.captured(2);" << defaultCategoryCaptured; 0123 } 0124 } 0125 0126 if (potentialIdentifier.isEmpty()) { 0127 static const QRegularExpression regularExpressionDefaultIdentifierNewFormat(QStringLiteral("^(.*)\\s+IDENTIFIER\\s+\\[(.*)\\]")); 0128 QRegularExpressionMatch match4 = regularExpressionDefaultIdentifierNewFormat.match(description); 0129 if (match4.hasMatch()) { 0130 newFormatFound = true; 0131 const QString descriptionCaptured = match4.captured(1); 0132 const QString identifierCaptured = match4.captured(2); 0133 if (!descriptionCaptured.isEmpty() && !identifierCaptured.isEmpty()) { 0134 description = descriptionCaptured; 0135 identifier = identifierCaptured; 0136 // qDebug() << " match.captured(1);" << descriptionCaptured; 0137 // qDebug() << " match.captured(2);" << identifierCaptured; 0138 } 0139 } 0140 } else { 0141 static const QRegularExpression regularExpressionDefaultIdentifierNewFormat2(QStringLiteral("IDENTIFIER\\s+\\[(.*)\\]")); 0142 QRegularExpressionMatch match4 = regularExpressionDefaultIdentifierNewFormat2.match(potentialIdentifier); 0143 if (match4.hasMatch()) { 0144 newFormatFound = true; 0145 const QString identifierCaptured = match4.captured(1); 0146 if (!identifierCaptured.isEmpty()) { 0147 identifier = identifierCaptured; 0148 } 0149 } 0150 } 0151 0152 if (!newFormatFound) { 0153 // Old format. 0154 static const QRegularExpression regularExpressionDefaultSeverityOldFormat(QStringLiteral("^(.*)\\s+\\[(DEBUG|INFO|WARNING|CRITICAL)\\]")); 0155 QRegularExpressionMatch match2 = regularExpressionDefaultSeverityOldFormat.match(description); 0156 if (match2.hasMatch()) { 0157 const QString descriptionCaptured = match2.captured(1); 0158 defaultSeverityCaptured = match2.captured(2); 0159 if (!descriptionCaptured.isEmpty() && !defaultSeverityCaptured.isEmpty()) { 0160 description = descriptionCaptured; 0161 defaultSeverity = defaultSeverityCaptured; 0162 // qDebug() << " match.captured(1);" << descriptionCaptured; 0163 // qDebug() << " match.captured(2);" << defaultCategoryCaptured; 0164 qCWarning(KDEBUGSETTINGS_LOG) << "In this file: " << filename << " this line " << line << " still use old format. We need to port it"; 0165 } 0166 } else { 0167 qCWarning(KDEBUGSETTINGS_LOG) << "In this file: " << filename << " this line " << line << " still use old format. We need to port it"; 0168 } 0169 } 0170 category.categoryName = logName; 0171 category.description = description; 0172 category.defaultSeverity = defaultSeverity; 0173 category.identifierName = identifier; 0174 return category; 0175 } 0176 0177 KdeLoggingCategory::List KDebugSettingsUtil::readLoggingCategoriesForInserting(const QString &filename, KdeLoggingCategory::List &categoriesList) 0178 { 0179 KdeLoggingCategory::List insertCategories; 0180 0181 QFile file(filename); 0182 if (!file.open(QIODevice::ReadOnly)) { 0183 qCWarning(KDEBUGSETTINGS_LOG) << "Couldn't open" << filename; 0184 } else { 0185 QString data; 0186 QTextStream ts(&file); 0187 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0188 ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); 0189 #else 0190 ts.setEncoding(QStringConverter::Encoding::Latin1); 0191 #endif 0192 while (!ts.atEnd()) { 0193 data = ts.readLine().simplified(); 0194 const KdeLoggingCategory category = parseLineKdeLoggingCategory(data, filename); 0195 if (category.isValid()) { 0196 bool needToAppend = true; 0197 for (const KdeLoggingCategory &cat : std::as_const(categoriesList)) { 0198 if (cat == category) { 0199 needToAppend = false; 0200 break; 0201 } else if (cat.categoryName == category.categoryName) { 0202 qCWarning(KDEBUGSETTINGS_LOG) << "Duplicate categories, it's a bug. Please verify: category:" << cat.categoryName 0203 << " filename : " << filename; 0204 needToAppend = false; 0205 } 0206 } 0207 if (needToAppend) { 0208 categoriesList.append(category); 0209 insertCategories.append(category); 0210 } 0211 } 0212 } 0213 } 0214 return insertCategories; 0215 } 0216 0217 void KDebugSettingsUtil::readLoggingCategories(const QString &filename, KdeLoggingCategory::List &categoriesList, bool checkCategoryList) 0218 { 0219 QFile file(filename); 0220 if (!file.open(QIODevice::ReadOnly)) { 0221 qCWarning(KDEBUGSETTINGS_LOG) << "Couldn't open" << filename; 0222 } else { 0223 QString data; 0224 QTextStream ts(&file); 0225 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0226 ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); 0227 #else 0228 ts.setEncoding(QStringConverter::Encoding::Latin1); 0229 #endif 0230 while (!ts.atEnd()) { 0231 data = ts.readLine().simplified(); 0232 const KdeLoggingCategory category = parseLineKdeLoggingCategory(data, filename); 0233 if (category.isValid()) { 0234 if (checkCategoryList) { 0235 bool needToAppend = true; 0236 for (const KdeLoggingCategory &cat : std::as_const(categoriesList)) { 0237 if (cat == category) { 0238 needToAppend = false; 0239 break; 0240 } else if (cat.categoryName == category.categoryName) { 0241 qCWarning(KDEBUGSETTINGS_LOG) 0242 << "Duplicate categories, it's a bug. Please verify: category:" << cat.categoryName << " filename : " << filename; 0243 needToAppend = false; 0244 } 0245 } 0246 if (needToAppend) { 0247 categoriesList.append(category); 0248 } 0249 } else { 0250 categoriesList.append(category); 0251 } 0252 } 0253 } 0254 } 0255 } 0256 0257 KDebugSettingsUtil::LineLoggingQtCategory KDebugSettingsUtil::parseLineLoggingQtCategory(const QString &line) 0258 { 0259 LineLoggingQtCategory lineCategory; 0260 int equalPos = line.indexOf(QLatin1Char('=')); 0261 if ((equalPos != -1) && (line.lastIndexOf(QLatin1Char('=')) == equalPos)) { 0262 const QString pattern = line.left(equalPos); 0263 const QString valueStr = line.mid(equalPos + 1); 0264 if (valueStr == QLatin1String("true")) { 0265 lineCategory.enabled = true; 0266 } else { 0267 lineCategory.enabled = false; 0268 } 0269 QString p; 0270 if (pattern.endsWith(QLatin1String(".debug"))) { 0271 p = pattern.left(pattern.length() - 6); // strlen(".debug") 0272 lineCategory.logName = p; 0273 lineCategory.type = LineLoggingQtCategory::Debug; 0274 } else if (pattern.endsWith(QLatin1String(".warning"))) { 0275 p = pattern.left(pattern.length() - 8); // strlen(".warning") 0276 lineCategory.logName = p; 0277 lineCategory.type = LineLoggingQtCategory::Warning; 0278 } else if (pattern.endsWith(QLatin1String(".critical"))) { 0279 p = pattern.left(pattern.length() - 9); // strlen(".critical") 0280 lineCategory.logName = p; 0281 lineCategory.type = LineLoggingQtCategory::Critical; 0282 } else if (pattern.endsWith(QLatin1String(".info"))) { 0283 p = pattern.left(pattern.length() - 5); // strlen(".info") 0284 lineCategory.logName = p; 0285 lineCategory.type = LineLoggingQtCategory::Info; 0286 } else { 0287 p = pattern; 0288 lineCategory.logName = p; 0289 lineCategory.type = LineLoggingQtCategory::All; 0290 } 0291 } else { 0292 lineCategory.enabled = false; 0293 } 0294 return lineCategory; 0295 } 0296 0297 QList<KDebugSettingsUtil::LoadLoggingCategory> KDebugSettingsUtil::readLoggingQtCategories(const QString &filename) 0298 { 0299 if (filename.isEmpty()) { 0300 qCWarning(KDEBUGSETTINGS_LOG) << "Empty file name"; 0301 return {}; 0302 } 0303 // Code based on src/corelib/io/qloggingregistry.cpp 0304 QFile file(filename); 0305 QMap<QString, KDebugSettingsUtil::LoadLoggingCategory> hashLoadLoggingCategories; 0306 if (file.open(QIODevice::ReadOnly)) { 0307 QTextStream ts(&file); 0308 QString _section; 0309 bool rulesSections = false; 0310 while (!ts.atEnd()) { 0311 QString line = ts.readLine(); 0312 0313 // Remove all whitespace from line 0314 line = line.simplified(); 0315 line.remove(QLatin1Char(' ')); 0316 0317 // comment 0318 if (line.startsWith(QLatin1Char(';'))) { 0319 continue; 0320 } 0321 0322 if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) { 0323 // new section 0324 _section = line.mid(1, line.size() - 2); 0325 rulesSections = (_section == QLatin1String("Rules")); 0326 continue; 0327 } 0328 if (rulesSections) { 0329 KDebugSettingsUtil::LineLoggingQtCategory cat = parseLineLoggingQtCategory(line); 0330 // qDebug() << " line " << line; 0331 // qDebug() << "enable " << cat.enabled << " valid : " << cat.isValid(); 0332 if (cat.isValid()) { 0333 KDebugSettingsUtil::LoadLoggingCategory nextCat = hashLoadLoggingCategories.value(cat.logName); 0334 if (nextCat.isValid()) { 0335 LoadLoggingCategory::LogType type; 0336 switch (cat.type) { 0337 case LineLoggingQtCategory::Unknown: 0338 type = LoadLoggingCategory::Unknown; 0339 break; 0340 case LineLoggingQtCategory::Info: 0341 type = LoadLoggingCategory::Info; 0342 break; 0343 case LineLoggingQtCategory::Warning: 0344 type = LoadLoggingCategory::Warning; 0345 break; 0346 case LineLoggingQtCategory::Debug: 0347 type = LoadLoggingCategory::Debug; 0348 break; 0349 case LineLoggingQtCategory::Critical: 0350 type = LoadLoggingCategory::Critical; 0351 break; 0352 case LineLoggingQtCategory::All: 0353 type = LoadLoggingCategory::All; 0354 break; 0355 } 0356 0357 if (nextCat.loggingTypes.contains(type)) { 0358 nextCat.loggingTypes[type] = cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled; 0359 } else { 0360 nextCat.loggingTypes.insert(type, cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0361 } 0362 hashLoadLoggingCategories[cat.logName] = nextCat; 0363 } else { 0364 nextCat.logName = cat.logName; 0365 switch (cat.type) { 0366 case LineLoggingQtCategory::Unknown: 0367 nextCat.loggingTypes.insert(LoadLoggingCategory::Unknown, 0368 cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0369 break; 0370 case LineLoggingQtCategory::Info: 0371 nextCat.loggingTypes.insert(LoadLoggingCategory::Info, cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0372 break; 0373 case LineLoggingQtCategory::Warning: 0374 nextCat.loggingTypes.insert(LoadLoggingCategory::Warning, 0375 cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0376 break; 0377 case LineLoggingQtCategory::Debug: 0378 nextCat.loggingTypes.insert(LoadLoggingCategory::Debug, cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0379 break; 0380 case LineLoggingQtCategory::Critical: 0381 nextCat.loggingTypes.insert(LoadLoggingCategory::Critical, 0382 cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0383 break; 0384 case LineLoggingQtCategory::All: 0385 nextCat.loggingTypes.insert(LoadLoggingCategory::All, cat.enabled ? LoadLoggingCategory::Enabled : LoadLoggingCategory::Disabled); 0386 break; 0387 } 0388 hashLoadLoggingCategories.insert(cat.logName, nextCat); 0389 } 0390 } 0391 } 0392 } 0393 } else { 0394 qCWarning(KDEBUGSETTINGS_LOG) << "Impossible to open file: " << filename; 0395 } 0396 0397 return hashLoadLoggingCategories.values(); 0398 } 0399 0400 LoggingCategory::LoggingType KDebugSettingsUtil::convertCategoryTypeFromString(const QString &str) 0401 { 0402 if (str.isEmpty()) { 0403 return LoggingCategory::Info; // Default 0404 } else if (str == QLatin1String("DEBUG")) { 0405 return LoggingCategory::Debug; 0406 } else if (str == QLatin1String("INFO")) { 0407 return LoggingCategory::Info; 0408 } else if (str == QLatin1String("WARNING")) { 0409 return LoggingCategory::Warning; 0410 } else if (str == QLatin1String("CRITICAL")) { 0411 return LoggingCategory::Critical; 0412 } 0413 qCWarning(KDEBUGSETTINGS_LOG) << "Default category is unknown: " << str; 0414 return LoggingCategory::Info; 0415 } 0416 0417 QString KDebugSettingsUtil::convertCategoryTypeToString(LoggingCategory::LoggingType type) 0418 { 0419 QString str; 0420 switch (type) { 0421 case LoggingCategory::All: 0422 str = i18n("All Debug Messages"); 0423 break; 0424 case LoggingCategory::Info: 0425 str = i18n("Info Messages"); 0426 break; 0427 case LoggingCategory::Warning: 0428 str = i18n("Warning Messages"); 0429 break; 0430 case LoggingCategory::Debug: 0431 str = i18n("Debug Messages"); 0432 break; 0433 case LoggingCategory::Critical: 0434 str = i18n("Critical Messages"); 0435 break; 0436 case LoggingCategory::Off: 0437 str = i18n("No Debug Messages"); 0438 break; 0439 case LoggingCategory::Undefined: 0440 str = i18n("Undefined"); 0441 break; 0442 } 0443 return str; 0444 } 0445 0446 QString KDebugSettingsUtil::qtFileName() 0447 { 0448 const QString envPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/QtProject"); 0449 QDir().mkpath(envPath); 0450 const QString qtloggingFileName = envPath + QStringLiteral("/qtlogging.ini"); 0451 return qtloggingFileName; 0452 } 0453 0454 QStringList KDebugSettingsUtil::groupFileList() 0455 { 0456 const QString groupPath = LoadGroupMenu::defaultWritableGroupPath(); 0457 if (groupPath.isEmpty()) { 0458 return {}; 0459 } 0460 QDir dir(groupPath); 0461 const QStringList groups = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); 0462 return groups; 0463 } 0464 0465 bool KDebugSettingsUtil::hasWritableGroups() 0466 { 0467 return !groupFileList().isEmpty(); 0468 }