File indexing completed on 2024-05-12 15:34:15
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 "../../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("size")) { 0216 return QStringLiteral("const QSize &"); 0217 } else if (type == QLatin1String("color")) { 0218 return QStringLiteral("const QColor &"); 0219 } else if (type == QLatin1String("point")) { 0220 return QStringLiteral("const QPoint &"); 0221 } else if (type == QLatin1String("int")) { 0222 return QStringLiteral("int"); 0223 } else if (type == QLatin1String("uint")) { 0224 return QStringLiteral("uint"); 0225 } else if (type == QLatin1String("bool")) { 0226 return QStringLiteral("bool"); 0227 } else if (type == QLatin1String("double")) { 0228 return QStringLiteral("double"); 0229 } else if (type == QLatin1String("datetime")) { 0230 return QStringLiteral("const QDateTime &"); 0231 } else if (type == QLatin1String("longlong")) { 0232 return QStringLiteral("qint64"); 0233 } else if (type == QLatin1String("ulonglong")) { 0234 return QStringLiteral("quint64"); 0235 } else if (type == QLatin1String("intlist")) { 0236 return QStringLiteral("const QList<int> &"); 0237 } else if (type == QLatin1String("enum")) { 0238 return QStringLiteral("int"); 0239 } else if (type == QLatin1String("path")) { 0240 return QStringLiteral("const QString &"); 0241 } else if (type == QLatin1String("pathlist")) { 0242 return QStringLiteral("const QStringList &"); 0243 } else if (type == QLatin1String("password")) { 0244 return QStringLiteral("const QString &"); 0245 } else if (type == QLatin1String("url")) { 0246 return QStringLiteral("const QUrl &"); 0247 } else if (type == QLatin1String("urllist")) { 0248 return QStringLiteral("const QList<QUrl> &"); 0249 } else { 0250 std::cerr << "kconfig_compiler_kf5 does not support type \"" << qPrintable(type) << "\"" << std::endl; 0251 return QStringLiteral("QString"); // For now, but an assert would be better 0252 } 0253 } 0254 0255 /** 0256 Actual C++ storage type for given type. 0257 */ 0258 QString cppType(const QString &t) 0259 { 0260 const QString type = t.toLower(); 0261 if (type == QLatin1String("string")) { 0262 return QStringLiteral("QString"); 0263 } else if (type == QLatin1String("stringlist")) { 0264 return QStringLiteral("QStringList"); 0265 } else if (type == QLatin1String("font")) { 0266 return QStringLiteral("QFont"); 0267 } else if (type == QLatin1String("rect")) { 0268 return QStringLiteral("QRect"); 0269 } else if (type == QLatin1String("size")) { 0270 return QStringLiteral("QSize"); 0271 } else if (type == QLatin1String("color")) { 0272 return QStringLiteral("QColor"); 0273 } else if (type == QLatin1String("point")) { 0274 return QStringLiteral("QPoint"); 0275 } else if (type == QLatin1String("int")) { 0276 return QStringLiteral("int"); 0277 } else if (type == QLatin1String("uint")) { 0278 return QStringLiteral("uint"); 0279 } else if (type == QLatin1String("bool")) { 0280 return QStringLiteral("bool"); 0281 } else if (type == QLatin1String("double")) { 0282 return QStringLiteral("double"); 0283 } else if (type == QLatin1String("datetime")) { 0284 return QStringLiteral("QDateTime"); 0285 } else if (type == QLatin1String("longlong")) { 0286 return QStringLiteral("qint64"); 0287 } else if (type == QLatin1String("ulonglong")) { 0288 return QStringLiteral("quint64"); 0289 } else if (type == QLatin1String("intlist")) { 0290 return QStringLiteral("QList<int>"); 0291 } else if (type == QLatin1String("enum")) { 0292 return QStringLiteral("int"); 0293 } else if (type == QLatin1String("path")) { 0294 return QStringLiteral("QString"); 0295 } else if (type == QLatin1String("pathlist")) { 0296 return QStringLiteral("QStringList"); 0297 } else if (type == QLatin1String("password")) { 0298 return QStringLiteral("QString"); 0299 } else if (type == QLatin1String("url")) { 0300 return QStringLiteral("QUrl"); 0301 } else if (type == QLatin1String("urllist")) { 0302 return QStringLiteral("QList<QUrl>"); 0303 } else { 0304 std::cerr << "kconfig_compiler_kf5 does not support type \"" << qPrintable(type) << "\"" << std::endl; 0305 return QStringLiteral("QString"); // For now, but an assert would be better 0306 } 0307 } 0308 0309 QString defaultValue(const QString &t) 0310 { 0311 const QString type = t.toLower(); 0312 if (type == QLatin1String("string")) { 0313 return QStringLiteral("\"\""); // Use empty string, not null string! 0314 } else if (type == QLatin1String("stringlist")) { 0315 return QStringLiteral("QStringList()"); 0316 } else if (type == QLatin1String("font")) { 0317 return QStringLiteral("QFont()"); 0318 } else if (type == QLatin1String("rect")) { 0319 return QStringLiteral("QRect()"); 0320 } else if (type == QLatin1String("size")) { 0321 return QStringLiteral("QSize()"); 0322 } else if (type == QLatin1String("color")) { 0323 return QStringLiteral("QColor(128, 128, 128)"); 0324 } else if (type == QLatin1String("point")) { 0325 return QStringLiteral("QPoint()"); 0326 } else if (type == QLatin1String("int")) { 0327 return QStringLiteral("0"); 0328 } else if (type == QLatin1String("uint")) { 0329 return QStringLiteral("0"); 0330 } else if (type == QLatin1String("bool")) { 0331 return QStringLiteral("false"); 0332 } else if (type == QLatin1String("double")) { 0333 return QStringLiteral("0.0"); 0334 } else if (type == QLatin1String("datetime")) { 0335 return QStringLiteral("QDateTime()"); 0336 } else if (type == QLatin1String("longlong")) { 0337 return QStringLiteral("0"); 0338 } else if (type == QLatin1String("ulonglong")) { 0339 return QStringLiteral("0"); 0340 } else if (type == QLatin1String("intlist")) { 0341 return QStringLiteral("QList<int>()"); 0342 } else if (type == QLatin1String("enum")) { 0343 return QStringLiteral("0"); 0344 } else if (type == QLatin1String("path")) { 0345 return QStringLiteral("\"\""); // Use empty string, not null string! 0346 } else if (type == QLatin1String("pathlist")) { 0347 return QStringLiteral("QStringList()"); 0348 } else if (type == QLatin1String("password")) { 0349 return QStringLiteral("\"\""); // Use empty string, not null string! 0350 } else if (type == QLatin1String("url")) { 0351 return QStringLiteral("QUrl()"); 0352 } else if (type == QLatin1String("urllist")) { 0353 return QStringLiteral("QList<QUrl>()"); 0354 } else { 0355 std::cerr << "Error, kconfig_compiler_kf5 does not support the \"" << qPrintable(type) << "\" type!" << std::endl; 0356 return QStringLiteral("QString"); // For now, but an assert would be better 0357 } 0358 } 0359 0360 QString itemType(const QString &type) 0361 { 0362 if (type.isEmpty()) { 0363 return QString{}; 0364 } 0365 0366 QString str = type; 0367 str[0] = str.at(0).toUpper(); 0368 0369 return str; 0370 } 0371 0372 QString itemDeclaration(const CfgEntry *e, const KConfigParameters &cfg) 0373 { 0374 if (e->name.isEmpty()) { 0375 return QString{}; 0376 } 0377 0378 const QString type = cfg.inherits + QLatin1String{"::Item"} + itemType(e->type); 0379 0380 QString fCap = e->name; 0381 fCap[0] = fCap.at(0).toUpper(); 0382 const QString argSuffix = (!e->param.isEmpty()) ? (QStringLiteral("[%1]").arg(e->paramMax + 1)) : QString(); 0383 QString result; 0384 0385 if (!cfg.itemAccessors && !cfg.dpointer) { 0386 result += QLatin1String{" "} + (!e->signalList.isEmpty() ? QStringLiteral("KConfigCompilerSignallingItem") : type); 0387 result += QLatin1String(" *item%1;\n").arg(fCap + argSuffix); 0388 } 0389 0390 if (!e->signalList.isEmpty()) { 0391 result += QLatin1String(" %1 *%2;\n").arg(type, innerItemVar(e, cfg) + argSuffix); 0392 } 0393 0394 return result; 0395 } 0396 0397 // returns the name of an item variable 0398 // use itemPath to know the full path 0399 // like using d-> in case of dpointer 0400 QString itemVar(const CfgEntry *e, const KConfigParameters &cfg) 0401 { 0402 QString result; 0403 if (cfg.itemAccessors) { 0404 if (!cfg.dpointer) { 0405 result = QLatin1String("m%1Item").arg(e->name); 0406 result[1] = result.at(1).toUpper(); 0407 } else { 0408 result = e->name + QLatin1String{"Item"}; 0409 result[0] = result.at(0).toLower(); 0410 } 0411 } else { 0412 result = QLatin1String{"item"} + e->name; 0413 result[4] = result.at(4).toUpper(); 0414 } 0415 return result; 0416 } 0417 0418 // returns the name of the local inner item if there is one 0419 // (before wrapping with KConfigCompilerSignallingItem) 0420 // Otherwise return itemVar() 0421 QString innerItemVar(const CfgEntry *e, const KConfigParameters &cfg) 0422 { 0423 if (e->signalList.isEmpty()) { 0424 return itemPath(e, cfg); 0425 } 0426 0427 QString result = QLatin1String{"innerItem"} + e->name; 0428 result[9] = result.at(9).toUpper(); 0429 return result; 0430 } 0431 0432 QString itemPath(const CfgEntry *e, const KConfigParameters &cfg) 0433 { 0434 return cfg.dpointer ? QLatin1String{"d->"} + itemVar(e, cfg) : itemVar(e, cfg); 0435 } 0436 0437 QString newInnerItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString ¶m) 0438 { 0439 QString str = QLatin1String("new %1::Item%2").arg(cfg.inherits, itemType(entry->type)); 0440 str += QLatin1String("( currentGroup(), %1, %2").arg(key, varPath(entry->name, cfg) + param); 0441 0442 if (entry->type == QLatin1String("Enum")) { 0443 str += QLatin1String{", values"} + entry->name; 0444 } 0445 if (!defaultValue.isEmpty()) { 0446 str += QLatin1String(", ") + defaultValue; 0447 } 0448 str += QLatin1String(" );"); 0449 0450 return str; 0451 } 0452 0453 QString newItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString ¶m) 0454 { 0455 const QList<Signal> sigs = entry->signalList; 0456 if (sigs.isEmpty()) { 0457 return newInnerItem(entry, key, defaultValue, cfg, param); 0458 } 0459 0460 QString str; 0461 str += QLatin1String("new KConfigCompilerSignallingItem(%1, this, notifyFunction, ").arg(innerItemVar(entry, cfg) + param); 0462 // Append the signal flags 0463 const int listSize = sigs.size(); 0464 for (int i = 0; i < listSize; ++i) { 0465 if (i != 0) { 0466 str += QLatin1String(" | "); 0467 } 0468 str += signalEnumName(sigs[i].name); 0469 } 0470 str += QLatin1String(");"); 0471 0472 return str; 0473 } 0474 0475 QString paramString(const QString &s, const CfgEntry *e, int i) 0476 { 0477 QString result = s; 0478 const QString needle = QLatin1String("$(%1)").arg(e->param); 0479 if (result.contains(needle)) { 0480 const QString tmp = e->paramType == QLatin1String{"Enum"} ? e->paramValues.at(i) : QString::number(i); 0481 0482 result.replace(needle, tmp); 0483 } 0484 return result; 0485 } 0486 0487 QString paramString(const QString &group, const QList<Param> ¶meters) 0488 { 0489 QString paramString = group; 0490 QString arguments; 0491 int i = 1; 0492 bool firstArg = true; 0493 for (const auto ¶m : parameters) { 0494 const QString paramName = param.name; 0495 const QString str = QLatin1String("$(%1)").arg(paramName); 0496 if (paramString.contains(str)) { 0497 const QString tmp = QStringLiteral("%%1").arg(i++); 0498 paramString.replace(str, tmp); 0499 0500 if (firstArg) { 0501 arguments += QLatin1String{".arg( "}; 0502 firstArg = false; 0503 } 0504 0505 arguments += QLatin1String("mParam%1, ").arg(paramName); 0506 } 0507 } 0508 0509 if (!arguments.isEmpty()) { 0510 // Remove the last ", " 0511 arguments.chop(2); 0512 0513 // Close the ".arg( " 0514 arguments += QLatin1String{" )"}; 0515 } else { 0516 return QLatin1String("QStringLiteral( \"%1\" )").arg(group); 0517 } 0518 0519 return QLatin1String("QStringLiteral( \"%1\" )%2").arg(paramString, arguments); 0520 } 0521 0522 QString translatedString(const KConfigParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) 0523 { 0524 QString result; 0525 0526 switch (cfg.translationSystem) { 0527 case KConfigParameters::QtTranslation: 0528 if (!context.isEmpty()) { 0529 result += QLatin1String("/*: %1 */ QCoreApplication::translate(\"").arg(context); 0530 } else { 0531 result += QLatin1String{"QCoreApplication::translate(\""}; 0532 } 0533 result += QLatin1String("%1\", ").arg(cfg.className); 0534 break; 0535 0536 case KConfigParameters::KdeTranslation: 0537 if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) { 0538 result += QLatin1String("i18ndc(%1, %2, ").arg(quoteString(cfg.translationDomain), quoteString(context)); 0539 } else if (!cfg.translationDomain.isEmpty()) { 0540 result += QLatin1String("i18nd(%1, ").arg(quoteString(cfg.translationDomain)); 0541 } else if (!context.isEmpty()) { 0542 result += QLatin1String("i18nc(%1, ").arg(quoteString(context)); 0543 } else { 0544 result += QLatin1String{"i18n("}; 0545 } 0546 break; 0547 } 0548 0549 if (!param.isEmpty()) { 0550 QString resolvedString = string; 0551 resolvedString.replace(QLatin1String("$(%1)").arg(param), paramValue); 0552 result += quoteString(resolvedString); 0553 } else { 0554 result += quoteString(string); 0555 } 0556 0557 result += QLatin1Char{')'}; 0558 0559 return result; 0560 } 0561 0562 /* int i is the value of the parameter */ 0563 QString userTextsFunctions(const CfgEntry *e, const KConfigParameters &cfg, QString itemVarStr, const QString &i) 0564 { 0565 QString txt; 0566 if (itemVarStr.isNull()) { 0567 itemVarStr = itemPath(e, cfg); 0568 } 0569 if (!e->label.isEmpty()) { 0570 txt += QLatin1String(" %1->setLabel( %2 );\n").arg(itemVarStr, translatedString(cfg, e->label, e->labelContext, e->param, i)); 0571 } 0572 if (!e->toolTip.isEmpty()) { 0573 txt += QLatin1String(" %1->setToolTip( %2 );\n").arg(itemVarStr, translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i)); 0574 } 0575 if (!e->whatsThis.isEmpty()) { 0576 txt += QLatin1String(" %1->setWhatsThis( %2 );\n").arg(itemVarStr, translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i)); 0577 } 0578 return txt; 0579 } 0580 0581 // returns the member mutator implementation 0582 // which should go in the h file if inline 0583 // or the cpp file if not inline 0584 // TODO: Fix add Debug Method, it should also take the debug string. 0585 void addDebugMethod(QTextStream &out, const KConfigParameters &cfg, const QString &n) 0586 { 0587 if (cfg.qCategoryLoggingName.isEmpty()) { 0588 out << " qDebug() << \"" << setFunction(n); 0589 } else { 0590 out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n); 0591 } 0592 } 0593 0594 // returns the member get default implementation 0595 // which should go in the h file if inline 0596 // or the cpp file if not inline 0597 QString memberGetDefaultBody(const CfgEntry *e) 0598 { 0599 QString result = e->code; 0600 QTextStream out(&result, QIODevice::WriteOnly); 0601 out << '\n'; 0602 0603 if (!e->param.isEmpty()) { 0604 out << " switch (i) {\n"; 0605 for (int i = 0; i <= e->paramMax; ++i) { 0606 if (!e->paramDefaultValues[i].isEmpty()) { 0607 out << " case " << i << ": return " << e->paramDefaultValues[i] << ";\n"; 0608 } 0609 } 0610 QString defaultValue = e->defaultValue; 0611 0612 out << " default:\n"; 0613 out << " return " << defaultValue.replace(QLatin1String("$(%1)").arg(e->param), QLatin1String("i")) << ";\n"; 0614 out << " }\n"; 0615 } else { 0616 out << " return " << e->defaultValue << ';'; 0617 } 0618 0619 return result; 0620 } 0621 0622 // returns the item accessor implementation 0623 // which should go in the h file if inline 0624 // or the cpp file if not inline 0625 QString itemAccessorBody(const CfgEntry *e, const KConfigParameters &cfg) 0626 { 0627 QString result; 0628 QTextStream out(&result, QIODevice::WriteOnly); 0629 0630 out << "return " << itemPath(e, cfg); 0631 if (!e->param.isEmpty()) { 0632 out << "[i]"; 0633 } 0634 out << ";\n"; 0635 0636 return result; 0637 } 0638 0639 // indents text adding X spaces per line 0640 QString indent(QString text, int spaces) 0641 { 0642 QString result; 0643 QTextStream out(&result, QIODevice::WriteOnly); 0644 QTextStream in(&text, QIODevice::ReadOnly); 0645 QString currLine; 0646 while (!in.atEnd()) { 0647 currLine = in.readLine(); 0648 if (!currLine.isEmpty()) { 0649 for (int i = 0; i < spaces; ++i) { 0650 out << " "; 0651 } 0652 } 0653 out << currLine << '\n'; 0654 } 0655 return result; 0656 } 0657 0658 bool hasErrors(KConfigXmlParser &parser, const ParseResult &parseResult, const KConfigParameters &cfg) 0659 { 0660 Q_UNUSED(parser) 0661 0662 if (cfg.className.isEmpty()) { 0663 std::cerr << "Class name missing" << std::endl; 0664 return true; 0665 } 0666 0667 if (cfg.singleton && !parseResult.parameters.isEmpty()) { 0668 std::cerr << "Singleton class can not have parameters" << std::endl; 0669 return true; 0670 } 0671 0672 if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) { 0673 std::cerr << "Having both a fixed filename and a filename as argument is not possible." << std::endl; 0674 return true; 0675 } 0676 0677 /* TODO: For some reason some configuration files prefer to have *no* entries 0678 * at all in it, and the generated code is mostly bogus as KConfigXT will not 0679 * handle save / load / properties, etc, nothing. 0680 * 0681 * The first of those files that I came across are qmakebuilderconfig.kcfg from the KDevelop 0682 * project. 0683 * I think we should remove the possibility of creating configuration classes from configuration 0684 * files that don't really have configuration in it. but I'm changing this right now to allow 0685 * kdevelop files to pass. 0686 * 0687 * Remove for KDE 6 0688 * (to make things more interesting, it failed in a code that's never used within KDevelop... ) 0689 */ 0690 if (parseResult.entries.isEmpty()) { 0691 std::cerr << "No entries." << std::endl; 0692 return false; 0693 } 0694 0695 return false; 0696 } 0697 0698 int main(int argc, char **argv) 0699 { 0700 QCoreApplication app(argc, argv); 0701 app.setApplicationName(QStringLiteral("kconfig_compiler")); 0702 app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); 0703 0704 QString inputFilename; 0705 QString codegenFilename; 0706 0707 QCommandLineOption targetDirectoryOption(QStringList{QStringLiteral("d"), QStringLiteral("directory")}, 0708 QCoreApplication::translate("main", "Directory to generate files in [.]"), 0709 QCoreApplication::translate("main", "directory"), 0710 QStringLiteral(".")); 0711 0712 QCommandLineOption licenseOption(QStringList{QStringLiteral("l"), QStringLiteral("license")}, 0713 QCoreApplication::translate("main", "Display software license.")); 0714 0715 QCommandLineParser parser; 0716 0717 parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file")); 0718 parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file")); 0719 0720 parser.addOption(targetDirectoryOption); 0721 parser.addOption(licenseOption); 0722 0723 parser.addVersionOption(); 0724 parser.addHelpOption(); 0725 parser.process(app); 0726 0727 if (parser.isSet(licenseOption)) { 0728 std::cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << std::endl; 0729 std::cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << std::endl; 0730 std::cout << "This program comes with ABSOLUTELY NO WARRANTY." << std::endl; 0731 std::cout << "You may redistribute copies of this program" << std::endl; 0732 std::cout << "under the terms of the GNU Library Public License." << std::endl; 0733 std::cout << "For more information about these matters, see the file named COPYING." << std::endl; 0734 return 0; 0735 } 0736 0737 const QStringList args = parser.positionalArguments(); 0738 if (args.count() < 2) { 0739 std::cerr << "Too few arguments." << std::endl; 0740 return 1; 0741 } 0742 0743 if (args.count() > 2) { 0744 std::cerr << "Too many arguments." << std::endl; 0745 return 1; 0746 } 0747 inputFilename = args.at(0); 0748 codegenFilename = args.at(1); 0749 0750 // TODO: Transform baseDir into a helper. 0751 QString baseDir = parser.value(targetDirectoryOption); 0752 0753 #ifdef Q_OS_WIN 0754 if (!baseDir.endsWith(QLatin1Char{'/'}) && !baseDir.endsWith(QLatin1Char{'\\'})) { 0755 #else 0756 if (!baseDir.endsWith(QLatin1Char{'/'})) { 0757 #endif 0758 baseDir.append(QLatin1Char{'/'}); 0759 } 0760 0761 KConfigParameters cfg(codegenFilename); 0762 0763 KConfigXmlParser xmlParser(cfg, inputFilename); 0764 0765 // The Xml Parser aborts in the case of an error, so if we get 0766 // to parseResult, we have a working Xml file. 0767 xmlParser.start(); 0768 0769 ParseResult parseResult = xmlParser.getParseResult(); 0770 0771 if (hasErrors(xmlParser, parseResult, cfg)) { 0772 return 1; 0773 } 0774 0775 // TODO: Move this to somewhere saner. 0776 for (const auto &signal : std::as_const(parseResult.signalList)) { 0777 parseResult.hasNonModifySignals |= !signal.modify; 0778 } 0779 0780 // remove '.kcfg' from the name. 0781 const QString baseName = inputFilename.mid(0, inputFilename.size() - 5); 0782 KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); 0783 headerGenerator.start(); 0784 headerGenerator.save(); 0785 0786 KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); 0787 sourceGenerator.start(); 0788 sourceGenerator.save(); 0789 0790 qDeleteAll(parseResult.entries); 0791 }