File indexing completed on 2024-05-12 03:54:29
0001 /* 0002 This file is part of KDE. 0003 0004 SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org> 0005 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0006 SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org> 0007 SPDX-FileCopyrightText: 2006 MichaĆ«l Larouche <michael.larouche@kdemail.net> 0008 SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org> 0009 0010 SPDX-License-Identifier: LGPL-2.0-or-later 0011 */ 0012 0013 #include <QCommandLineOption> 0014 #include <QCommandLineParser> 0015 #include <QCoreApplication> 0016 #include <QDomAttr> 0017 #include <QFile> 0018 #include <QFileInfo> 0019 #include <QRegularExpression> 0020 #include <QSettings> 0021 #include <QStringList> 0022 #include <QTextStream> 0023 0024 #include <algorithm> 0025 #include <iostream> 0026 #include <ostream> 0027 #include <stdlib.h> 0028 0029 #include "../core/kconfig_version.h" 0030 #include "KConfigCommonStructs.h" 0031 #include "KConfigHeaderGenerator.h" 0032 #include "KConfigParameters.h" 0033 #include "KConfigSourceGenerator.h" 0034 #include "KConfigXmlParser.h" 0035 0036 QString varName(const QString &n, const KConfigParameters &cfg) 0037 { 0038 QString result; 0039 if (!cfg.dpointer) { 0040 result = QChar::fromLatin1('m') + n; 0041 result[1] = result.at(1).toUpper(); 0042 } else { 0043 result = n; 0044 result[0] = result.at(0).toLower(); 0045 } 0046 return result; 0047 } 0048 0049 QString varPath(const QString &n, const KConfigParameters &cfg) 0050 { 0051 QString result; 0052 if (cfg.dpointer) { 0053 result = QLatin1String{"d->"} + varName(n, cfg); 0054 } else { 0055 result = varName(n, cfg); 0056 } 0057 return result; 0058 } 0059 0060 QString enumName(const QString &n) 0061 { 0062 QString result = QLatin1String("Enum") + n; 0063 result[4] = result.at(4).toUpper(); 0064 return result; 0065 } 0066 0067 QString enumName(const QString &n, const CfgEntry::Choices &c) 0068 { 0069 QString result = c.name(); 0070 if (result.isEmpty()) { 0071 result = QLatin1String("Enum") + n; 0072 result[4] = result.at(4).toUpper(); 0073 } 0074 return result; 0075 } 0076 0077 QString enumType(const CfgEntry *e, bool globalEnums) 0078 { 0079 QString result = e->choices.name(); 0080 if (result.isEmpty()) { 0081 result = QLatin1String("Enum") + e->name; 0082 if (!globalEnums) { 0083 result += QLatin1String("::type"); 0084 } 0085 result[4] = result.at(4).toUpper(); 0086 } 0087 return result; 0088 } 0089 0090 QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) 0091 { 0092 QString result = c.name(); 0093 if (result.isEmpty()) { 0094 result = QLatin1String("Enum") + n + QLatin1String("::"); 0095 result[4] = result.at(4).toUpper(); 0096 } else if (c.external()) { 0097 result = c.externalQualifier(); 0098 } else { 0099 result.clear(); 0100 } 0101 return result; 0102 } 0103 0104 QString setFunction(const QString &n, const QString &className) 0105 { 0106 QString result = QLatin1String("set") + n; 0107 result[3] = result.at(3).toUpper(); 0108 0109 if (!className.isEmpty()) { 0110 result = className + QLatin1String("::") + result; 0111 } 0112 return result; 0113 } 0114 0115 QString changeSignalName(const QString &n) 0116 { 0117 return n + QLatin1String{"Changed"}; 0118 } 0119 0120 QString getDefaultFunction(const QString &n, const QString &className) 0121 { 0122 QString result = QLatin1String("default%1Value").arg(n); 0123 result[7] = result.at(7).toUpper(); 0124 0125 if (!className.isEmpty()) { 0126 result.prepend(className + QLatin1String("::")); 0127 } 0128 return result; 0129 } 0130 0131 QString getFunction(const QString &n, const QString &className) 0132 { 0133 QString result = n; 0134 result[0] = result.at(0).toLower(); 0135 0136 if (!className.isEmpty()) { 0137 result.prepend(className + QLatin1String("::")); 0138 } 0139 return result; 0140 } 0141 0142 QString immutableFunction(const QString &n, const QString &className) 0143 { 0144 QString result = QLatin1String("is") + n; 0145 result[2] = result.at(2).toUpper(); 0146 result += QLatin1String{"Immutable"}; 0147 0148 if (!className.isEmpty()) { 0149 result.prepend(className + QLatin1String("::")); 0150 } 0151 return result; 0152 } 0153 0154 void addQuotes(QString &s) 0155 { 0156 if (!s.startsWith(QLatin1Char('"'))) { 0157 s.prepend(QLatin1Char('"')); 0158 } 0159 if (!s.endsWith(QLatin1Char('"'))) { 0160 s.append(QLatin1Char('"')); 0161 } 0162 } 0163 0164 static QString quoteString(const QString &s) 0165 { 0166 QString r = s; 0167 r.replace(QLatin1Char('\\'), QLatin1String("\\\\")); 0168 r.replace(QLatin1Char('\"'), QLatin1String("\\\"")); 0169 r.remove(QLatin1Char('\r')); 0170 r.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\"")); 0171 return QLatin1Char('\"') + r + QLatin1Char('\"'); 0172 } 0173 0174 QString literalString(const QString &str) 0175 { 0176 const bool isAscii = std::none_of(str.cbegin(), str.cend(), [](const QChar ch) { 0177 return ch.unicode() > 127; 0178 }); 0179 0180 if (isAscii) { 0181 return QLatin1String("QStringLiteral( %1 )").arg(quoteString(str)); 0182 } else { 0183 return QLatin1String("QString::fromUtf8( %1 )").arg(quoteString(str)); 0184 } 0185 } 0186 0187 QString signalEnumName(const QString &signalName) 0188 { 0189 QString result; 0190 result = QLatin1String("signal") + signalName; 0191 result[6] = result.at(6).toUpper(); 0192 0193 return result; 0194 } 0195 0196 bool isUnsigned(const QString &type) 0197 { 0198 return type == QLatin1String("UInt") || type == QLatin1String("ULongLong"); 0199 } 0200 0201 /** 0202 Return parameter declaration for given type. 0203 */ 0204 QString param(const QString &t) 0205 { 0206 const QString type = t.toLower(); 0207 if (type == QLatin1String("string")) { 0208 return QStringLiteral("const QString &"); 0209 } else if (type == QLatin1String("stringlist")) { 0210 return QStringLiteral("const QStringList &"); 0211 } else if (type == QLatin1String("font")) { 0212 return QStringLiteral("const QFont &"); 0213 } else if (type == QLatin1String("rect")) { 0214 return QStringLiteral("const QRect &"); 0215 } else if (type == QLatin1String("rectf")) { 0216 return QStringLiteral("const QRectF &"); 0217 } else if (type == QLatin1String("size")) { 0218 return QStringLiteral("const QSize &"); 0219 } else if (type == QLatin1String("sizef")) { 0220 return QStringLiteral("const QSizeF &"); 0221 } else if (type == QLatin1String("color")) { 0222 return QStringLiteral("const QColor &"); 0223 } else if (type == QLatin1String("point")) { 0224 return QStringLiteral("const QPoint &"); 0225 } else if (type == QLatin1String("pointf")) { 0226 return QStringLiteral("const QPointF &"); 0227 } else if (type == QLatin1String("int")) { 0228 return QStringLiteral("int"); 0229 } else if (type == QLatin1String("uint")) { 0230 return QStringLiteral("uint"); 0231 } else if (type == QLatin1String("bool")) { 0232 return QStringLiteral("bool"); 0233 } else if (type == QLatin1String("double")) { 0234 return QStringLiteral("double"); 0235 } else if (type == QLatin1String("datetime")) { 0236 return QStringLiteral("const QDateTime &"); 0237 } else if (type == QLatin1String("longlong")) { 0238 return QStringLiteral("qint64"); 0239 } else if (type == QLatin1String("ulonglong")) { 0240 return QStringLiteral("quint64"); 0241 } else if (type == QLatin1String("intlist")) { 0242 return QStringLiteral("const QList<int> &"); 0243 } else if (type == QLatin1String("enum")) { 0244 return QStringLiteral("int"); 0245 } else if (type == QLatin1String("path")) { 0246 return QStringLiteral("const QString &"); 0247 } else if (type == QLatin1String("pathlist")) { 0248 return QStringLiteral("const QStringList &"); 0249 } else if (type == QLatin1String("password")) { 0250 return QStringLiteral("const QString &"); 0251 } else if (type == QLatin1String("url")) { 0252 return QStringLiteral("const QUrl &"); 0253 } else if (type == QLatin1String("urllist")) { 0254 return QStringLiteral("const QList<QUrl> &"); 0255 } else { 0256 std::cerr << "kconfig_compiler_kf6 does not support type \"" << qPrintable(type) << "\"" << std::endl; 0257 return QStringLiteral("QString"); // For now, but an assert would be better 0258 } 0259 } 0260 0261 /** 0262 Actual C++ storage type for given type. 0263 */ 0264 QString cppType(const QString &t) 0265 { 0266 const QString type = t.toLower(); 0267 if (type == QLatin1String("string")) { 0268 return QStringLiteral("QString"); 0269 } else if (type == QLatin1String("stringlist")) { 0270 return QStringLiteral("QStringList"); 0271 } else if (type == QLatin1String("font")) { 0272 return QStringLiteral("QFont"); 0273 } else if (type == QLatin1String("rect")) { 0274 return QStringLiteral("QRect"); 0275 } else if (type == QLatin1String("rectf")) { 0276 return QStringLiteral("QRectF"); 0277 } else if (type == QLatin1String("size")) { 0278 return QStringLiteral("QSize"); 0279 } else if (type == QLatin1String("sizef")) { 0280 return QStringLiteral("QSizeF"); 0281 } else if (type == QLatin1String("color")) { 0282 return QStringLiteral("QColor"); 0283 } else if (type == QLatin1String("point")) { 0284 return QStringLiteral("QPoint"); 0285 } else if (type == QLatin1String("pointf")) { 0286 return QStringLiteral("QPointF"); 0287 } else if (type == QLatin1String("int")) { 0288 return QStringLiteral("int"); 0289 } else if (type == QLatin1String("uint")) { 0290 return QStringLiteral("uint"); 0291 } else if (type == QLatin1String("bool")) { 0292 return QStringLiteral("bool"); 0293 } else if (type == QLatin1String("double")) { 0294 return QStringLiteral("double"); 0295 } else if (type == QLatin1String("datetime")) { 0296 return QStringLiteral("QDateTime"); 0297 } else if (type == QLatin1String("longlong")) { 0298 return QStringLiteral("qint64"); 0299 } else if (type == QLatin1String("ulonglong")) { 0300 return QStringLiteral("quint64"); 0301 } else if (type == QLatin1String("intlist")) { 0302 return QStringLiteral("QList<int>"); 0303 } else if (type == QLatin1String("enum")) { 0304 return QStringLiteral("int"); 0305 } else if (type == QLatin1String("path")) { 0306 return QStringLiteral("QString"); 0307 } else if (type == QLatin1String("pathlist")) { 0308 return QStringLiteral("QStringList"); 0309 } else if (type == QLatin1String("password")) { 0310 return QStringLiteral("QString"); 0311 } else if (type == QLatin1String("url")) { 0312 return QStringLiteral("QUrl"); 0313 } else if (type == QLatin1String("urllist")) { 0314 return QStringLiteral("QList<QUrl>"); 0315 } else { 0316 std::cerr << "kconfig_compiler_kf6 does not support type \"" << qPrintable(type) << "\"" << std::endl; 0317 return QStringLiteral("QString"); // For now, but an assert would be better 0318 } 0319 } 0320 0321 QString defaultValue(const QString &t) 0322 { 0323 const QString type = t.toLower(); 0324 if (type == QLatin1String("string")) { 0325 return QStringLiteral("\"\""); // Use empty string, not null string! 0326 } else if (type == QLatin1String("stringlist")) { 0327 return QStringLiteral("QStringList()"); 0328 } else if (type == QLatin1String("font")) { 0329 return QStringLiteral("QFont()"); 0330 } else if (type == QLatin1String("rect")) { 0331 return QStringLiteral("QRect()"); 0332 } else if (type == QLatin1String("rectf")) { 0333 return QStringLiteral("QRectF()"); 0334 } else if (type == QLatin1String("size")) { 0335 return QStringLiteral("QSize()"); 0336 } else if (type == QLatin1String("sizef")) { 0337 return QStringLiteral("QSizeF()"); 0338 } else if (type == QLatin1String("color")) { 0339 return QStringLiteral("QColor(128, 128, 128)"); 0340 } else if (type == QLatin1String("point")) { 0341 return QStringLiteral("QPoint()"); 0342 } else if (type == QLatin1String("pointf")) { 0343 return QStringLiteral("QPointF()"); 0344 } else if (type == QLatin1String("int")) { 0345 return QStringLiteral("0"); 0346 } else if (type == QLatin1String("uint")) { 0347 return QStringLiteral("0"); 0348 } else if (type == QLatin1String("bool")) { 0349 return QStringLiteral("false"); 0350 } else if (type == QLatin1String("double")) { 0351 return QStringLiteral("0.0"); 0352 } else if (type == QLatin1String("datetime")) { 0353 return QStringLiteral("QDateTime()"); 0354 } else if (type == QLatin1String("longlong")) { 0355 return QStringLiteral("0"); 0356 } else if (type == QLatin1String("ulonglong")) { 0357 return QStringLiteral("0"); 0358 } else if (type == QLatin1String("intlist")) { 0359 return QStringLiteral("QList<int>()"); 0360 } else if (type == QLatin1String("enum")) { 0361 return QStringLiteral("0"); 0362 } else if (type == QLatin1String("path")) { 0363 return QStringLiteral("\"\""); // Use empty string, not null string! 0364 } else if (type == QLatin1String("pathlist")) { 0365 return QStringLiteral("QStringList()"); 0366 } else if (type == QLatin1String("password")) { 0367 return QStringLiteral("\"\""); // Use empty string, not null string! 0368 } else if (type == QLatin1String("url")) { 0369 return QStringLiteral("QUrl()"); 0370 } else if (type == QLatin1String("urllist")) { 0371 return QStringLiteral("QList<QUrl>()"); 0372 } else { 0373 std::cerr << "Error, kconfig_compiler_kf6 does not support the \"" << qPrintable(type) << "\" type!" << std::endl; 0374 return QStringLiteral("QString"); // For now, but an assert would be better 0375 } 0376 } 0377 0378 QString itemType(const QString &type) 0379 { 0380 if (type.isEmpty()) { 0381 return QString{}; 0382 } 0383 0384 QString str = type; 0385 str[0] = str.at(0).toUpper(); 0386 0387 return str; 0388 } 0389 0390 QString itemDeclaration(const CfgEntry *e, const KConfigParameters &cfg) 0391 { 0392 if (e->name.isEmpty()) { 0393 return QString{}; 0394 } 0395 0396 const QString type = cfg.inherits + QLatin1String{"::Item"} + itemType(e->type); 0397 0398 QString fCap = e->name; 0399 fCap[0] = fCap.at(0).toUpper(); 0400 const QString argSuffix = (!e->param.isEmpty()) ? (QStringLiteral("[%1]").arg(e->paramMax + 1)) : QString(); 0401 QString result; 0402 0403 if (!cfg.itemAccessors && !cfg.dpointer) { 0404 result += QLatin1String{" "} + (!e->signalList.isEmpty() ? QStringLiteral("KConfigCompilerSignallingItem") : type); 0405 result += QLatin1String(" *item%1;\n").arg(fCap + argSuffix); 0406 } 0407 0408 if (!e->signalList.isEmpty()) { 0409 result += QLatin1String(" %1 *%2;\n").arg(type, innerItemVar(e, cfg) + argSuffix); 0410 } 0411 0412 return result; 0413 } 0414 0415 // returns the name of an item variable 0416 // use itemPath to know the full path 0417 // like using d-> in case of dpointer 0418 QString itemVar(const CfgEntry *e, const KConfigParameters &cfg) 0419 { 0420 QString result; 0421 if (cfg.itemAccessors) { 0422 if (!cfg.dpointer) { 0423 result = QLatin1String("m%1Item").arg(e->name); 0424 result[1] = result.at(1).toUpper(); 0425 } else { 0426 result = e->name + QLatin1String{"Item"}; 0427 result[0] = result.at(0).toLower(); 0428 } 0429 } else { 0430 result = QLatin1String{"item"} + e->name; 0431 result[4] = result.at(4).toUpper(); 0432 } 0433 return result; 0434 } 0435 0436 // returns the name of the local inner item if there is one 0437 // (before wrapping with KConfigCompilerSignallingItem) 0438 // Otherwise return itemVar() 0439 QString innerItemVar(const CfgEntry *e, const KConfigParameters &cfg) 0440 { 0441 if (e->signalList.isEmpty()) { 0442 return itemPath(e, cfg); 0443 } 0444 0445 QString result = QLatin1String{"innerItem"} + e->name; 0446 result[9] = result.at(9).toUpper(); 0447 return result; 0448 } 0449 0450 QString itemPath(const CfgEntry *e, const KConfigParameters &cfg) 0451 { 0452 return cfg.dpointer ? QLatin1String{"d->"} + itemVar(e, cfg) : itemVar(e, cfg); 0453 } 0454 0455 QString newInnerItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString ¶m) 0456 { 0457 QString str = QLatin1String("new %1::Item%2").arg(cfg.inherits, itemType(entry->type)); 0458 str += QLatin1String("( currentGroup(), %1, %2").arg(key, varPath(entry->name, cfg) + param); 0459 0460 if (entry->type == QLatin1String("Enum")) { 0461 str += QLatin1String{", values"} + entry->name; 0462 } 0463 if (!defaultValue.isEmpty()) { 0464 str += QLatin1String(", ") + defaultValue; 0465 } 0466 str += QLatin1String(" );"); 0467 0468 return str; 0469 } 0470 0471 QString newItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString ¶m) 0472 { 0473 const QList<Signal> sigs = entry->signalList; 0474 if (sigs.isEmpty()) { 0475 return newInnerItem(entry, key, defaultValue, cfg, param); 0476 } 0477 0478 QString str; 0479 str += QLatin1String("new KConfigCompilerSignallingItem(%1, this, notifyFunction, ").arg(innerItemVar(entry, cfg) + param); 0480 // Append the signal flags 0481 const int listSize = sigs.size(); 0482 for (int i = 0; i < listSize; ++i) { 0483 if (i != 0) { 0484 str += QLatin1String(" | "); 0485 } 0486 str += signalEnumName(sigs[i].name); 0487 } 0488 str += QLatin1String(");"); 0489 0490 return str; 0491 } 0492 0493 QString paramString(const QString &s, const CfgEntry *e, int i) 0494 { 0495 QString result = s; 0496 const QString needle = QLatin1String("$(%1)").arg(e->param); 0497 if (result.contains(needle)) { 0498 const QString tmp = e->paramType == QLatin1String{"Enum"} ? e->paramValues.at(i) : QString::number(i); 0499 0500 result.replace(needle, tmp); 0501 } 0502 return result; 0503 } 0504 0505 QString paramString(const QString &group, const QList<Param> ¶meters) 0506 { 0507 QString paramString = group; 0508 QString arguments; 0509 int i = 1; 0510 bool firstArg = true; 0511 for (const auto ¶m : parameters) { 0512 const QString paramName = param.name; 0513 const QString str = QLatin1String("$(%1)").arg(paramName); 0514 if (paramString.contains(str)) { 0515 const QString tmp = QStringLiteral("%%1").arg(i++); 0516 paramString.replace(str, tmp); 0517 0518 if (firstArg) { 0519 arguments += QLatin1String{".arg( "}; 0520 firstArg = false; 0521 } 0522 0523 arguments += QLatin1String("mParam%1, ").arg(paramName); 0524 } 0525 } 0526 0527 if (!arguments.isEmpty()) { 0528 // Remove the last ", " 0529 arguments.chop(2); 0530 0531 // Close the ".arg( " 0532 arguments += QLatin1String{" )"}; 0533 } else { 0534 return QLatin1String("QStringLiteral( \"%1\" )").arg(group); 0535 } 0536 0537 return QLatin1String("QStringLiteral( \"%1\" )%2").arg(paramString, arguments); 0538 } 0539 0540 QString translatedString(const KConfigParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) 0541 { 0542 QString result; 0543 0544 switch (cfg.translationSystem) { 0545 case KConfigParameters::QtTranslation: 0546 if (!context.isEmpty()) { 0547 result += QLatin1String("/*: %1 */ QCoreApplication::translate(\"").arg(context); 0548 } else { 0549 result += QLatin1String{"QCoreApplication::translate(\""}; 0550 } 0551 result += QLatin1String("%1\", ").arg(cfg.className); 0552 break; 0553 0554 case KConfigParameters::KdeTranslation: 0555 if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { 0556 result += QLatin1String("i18ndc(%1, %2, ").arg(quoteString(cfg.translationDomain), quoteString(context)); 0557 } else if (!cfg.translationDomain.isEmpty()) { 0558 result += QLatin1String("i18nd(%1, ").arg(quoteString(cfg.translationDomain)); 0559 } else if (!context.isEmpty()) { 0560 result += QLatin1String("i18nc(%1, ").arg(quoteString(context)); 0561 } else { 0562 result += QLatin1String{"i18n("}; 0563 } 0564 break; 0565 } 0566 0567 if (!param.isEmpty()) { 0568 QString resolvedString = string; 0569 resolvedString.replace(QLatin1String("$(%1)").arg(param), paramValue); 0570 result += quoteString(resolvedString); 0571 } else { 0572 result += quoteString(string); 0573 } 0574 0575 result += QLatin1Char{')'}; 0576 0577 return result; 0578 } 0579 0580 /* int i is the value of the parameter */ 0581 QString userTextsFunctions(const CfgEntry *e, const KConfigParameters &cfg, QString itemVarStr, const QString &i) 0582 { 0583 QString txt; 0584 if (itemVarStr.isNull()) { 0585 itemVarStr = itemPath(e, cfg); 0586 } 0587 if (!e->label.isEmpty()) { 0588 txt += QLatin1String(" %1->setLabel( %2 );\n").arg(itemVarStr, translatedString(cfg, e->label, e->labelContext, e->param, i)); 0589 } 0590 if (!e->toolTip.isEmpty()) { 0591 txt += QLatin1String(" %1->setToolTip( %2 );\n").arg(itemVarStr, translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i)); 0592 } 0593 if (!e->whatsThis.isEmpty()) { 0594 txt += QLatin1String(" %1->setWhatsThis( %2 );\n").arg(itemVarStr, translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i)); 0595 } 0596 return txt; 0597 } 0598 0599 // returns the member mutator implementation 0600 // which should go in the h file if inline 0601 // or the cpp file if not inline 0602 // TODO: Fix add Debug Method, it should also take the debug string. 0603 void addDebugMethod(QTextStream &out, const KConfigParameters &cfg, const QString &n) 0604 { 0605 if (cfg.qCategoryLoggingName.isEmpty()) { 0606 out << " qDebug() << \"" << setFunction(n); 0607 } else { 0608 out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n); 0609 } 0610 } 0611 0612 // returns the member get default implementation 0613 // which should go in the h file if inline 0614 // or the cpp file if not inline 0615 QString memberGetDefaultBody(const CfgEntry *e) 0616 { 0617 QString result = e->code; 0618 QTextStream out(&result, QIODevice::WriteOnly); 0619 out << '\n'; 0620 0621 if (!e->param.isEmpty()) { 0622 out << " switch (i) {\n"; 0623 for (int i = 0; i <= e->paramMax; ++i) { 0624 if (!e->paramDefaultValues[i].isEmpty()) { 0625 out << " case " << i << ": return " << e->paramDefaultValues[i] << ";\n"; 0626 } 0627 } 0628 QString defaultValue = e->defaultValue; 0629 0630 out << " default:\n"; 0631 out << " return " << defaultValue.replace(QLatin1String("$(%1)").arg(e->param), QLatin1String("i")) << ";\n"; 0632 out << " }\n"; 0633 } else { 0634 out << " return " << e->defaultValue << ';'; 0635 } 0636 0637 return result; 0638 } 0639 0640 // returns the item accessor implementation 0641 // which should go in the h file if inline 0642 // or the cpp file if not inline 0643 QString itemAccessorBody(const CfgEntry *e, const KConfigParameters &cfg) 0644 { 0645 QString result; 0646 QTextStream out(&result, QIODevice::WriteOnly); 0647 0648 out << "return " << itemPath(e, cfg); 0649 if (!e->param.isEmpty()) { 0650 out << "[i]"; 0651 } 0652 out << ";\n"; 0653 0654 return result; 0655 } 0656 0657 // indents text adding X spaces per line 0658 QString indent(QString text, int spaces) 0659 { 0660 QString result; 0661 QTextStream out(&result, QIODevice::WriteOnly); 0662 QTextStream in(&text, QIODevice::ReadOnly); 0663 QString currLine; 0664 while (!in.atEnd()) { 0665 currLine = in.readLine(); 0666 if (!currLine.isEmpty()) { 0667 for (int i = 0; i < spaces; ++i) { 0668 out << " "; 0669 } 0670 } 0671 out << currLine << '\n'; 0672 } 0673 return result; 0674 } 0675 0676 bool hasErrors(KConfigXmlParser &parser, const ParseResult &parseResult, const KConfigParameters &cfg) 0677 { 0678 Q_UNUSED(parser) 0679 0680 if (cfg.className.isEmpty()) { 0681 std::cerr << "Class name missing" << std::endl; 0682 return true; 0683 } 0684 0685 if (cfg.singleton && !parseResult.parameters.isEmpty()) { 0686 std::cerr << "Singleton class can not have parameters" << std::endl; 0687 return true; 0688 } 0689 0690 if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) { 0691 std::cerr << "Having both a fixed filename and a filename as argument is not possible." << std::endl; 0692 return true; 0693 } 0694 0695 /* TODO: For some reason some configuration files prefer to have *no* entries 0696 * at all in it, and the generated code is mostly bogus as KConfigXT will not 0697 * handle save / load / properties, etc, nothing. 0698 * 0699 * The first of those files that I came across are qmakebuilderconfig.kcfg from the KDevelop 0700 * project. 0701 * I think we should remove the possibility of creating configuration classes from configuration 0702 * files that don't really have configuration in it. but I'm changing this right now to allow 0703 * kdevelop files to pass. 0704 * 0705 * Remove for KDE 6 0706 * (to make things more interesting, it failed in a code that's never used within KDevelop... ) 0707 */ 0708 if (parseResult.entries.isEmpty()) { 0709 std::cerr << "No entries." << std::endl; 0710 return false; 0711 } 0712 0713 return false; 0714 } 0715 0716 int main(int argc, char **argv) 0717 { 0718 QCoreApplication app(argc, argv); 0719 app.setApplicationName(QStringLiteral("kconfig_compiler")); 0720 app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); 0721 0722 QString inputFilename; 0723 QString codegenFilename; 0724 0725 QCommandLineOption targetDirectoryOption(QStringList{QStringLiteral("d"), QStringLiteral("directory")}, 0726 QCoreApplication::translate("main", "Directory to generate files in [.]"), 0727 QCoreApplication::translate("main", "directory"), 0728 QStringLiteral(".")); 0729 0730 QCommandLineOption licenseOption(QStringList{QStringLiteral("l"), QStringLiteral("license")}, 0731 QCoreApplication::translate("main", "Display software license.")); 0732 0733 QCommandLineParser parser; 0734 0735 parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file")); 0736 parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file")); 0737 0738 parser.addOption(targetDirectoryOption); 0739 parser.addOption(licenseOption); 0740 0741 parser.addVersionOption(); 0742 parser.addHelpOption(); 0743 parser.process(app); 0744 0745 if (parser.isSet(licenseOption)) { 0746 std::cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << std::endl; 0747 std::cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << std::endl; 0748 std::cout << "This program comes with ABSOLUTELY NO WARRANTY." << std::endl; 0749 std::cout << "You may redistribute copies of this program" << std::endl; 0750 std::cout << "under the terms of the GNU Library Public License." << std::endl; 0751 std::cout << "For more information about these matters, see the file named COPYING." << std::endl; 0752 return 0; 0753 } 0754 0755 const QStringList args = parser.positionalArguments(); 0756 if (args.count() < 2) { 0757 std::cerr << "Too few arguments." << std::endl; 0758 return 1; 0759 } 0760 0761 if (args.count() > 2) { 0762 std::cerr << "Too many arguments." << std::endl; 0763 return 1; 0764 } 0765 inputFilename = args.at(0); 0766 codegenFilename = args.at(1); 0767 0768 // TODO: Transform baseDir into a helper. 0769 QString baseDir = parser.value(targetDirectoryOption); 0770 0771 #ifdef Q_OS_WIN 0772 if (!baseDir.endsWith(QLatin1Char{'/'}) && !baseDir.endsWith(QLatin1Char{'\\'})) { 0773 #else 0774 if (!baseDir.endsWith(QLatin1Char{'/'})) { 0775 #endif 0776 baseDir.append(QLatin1Char{'/'}); 0777 } 0778 0779 KConfigParameters cfg(codegenFilename); 0780 0781 KConfigXmlParser xmlParser(cfg, inputFilename); 0782 0783 // The Xml Parser aborts in the case of an error, so if we get 0784 // to parseResult, we have a working Xml file. 0785 xmlParser.start(); 0786 0787 ParseResult parseResult = xmlParser.getParseResult(); 0788 0789 if (hasErrors(xmlParser, parseResult, cfg)) { 0790 return 1; 0791 } 0792 0793 // TODO: Move this to somewhere saner. 0794 for (const auto &signal : std::as_const(parseResult.signalList)) { 0795 parseResult.hasNonModifySignals |= !signal.modify; 0796 } 0797 0798 // remove '.kcfg' from the name. 0799 const QString baseName = inputFilename.mid(0, inputFilename.size() - 5); 0800 KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); 0801 headerGenerator.start(); 0802 headerGenerator.save(); 0803 0804 KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); 0805 sourceGenerator.start(); 0806 sourceGenerator.save(); 0807 0808 qDeleteAll(parseResult.entries); 0809 }