KConfig

kconfig_compiler.cpp
1 /*
2  This file is part of KDE.
3 
4  SPDX-FileCopyrightText: 2003 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2003 Waldo Bastian <[email protected]>
6  SPDX-FileCopyrightText: 2003 Zack Rusin <[email protected]>
7  SPDX-FileCopyrightText: 2006 MichaĆ«l Larouche <[email protected]>
8  SPDX-FileCopyrightText: 2008 Allen Winter <[email protected]>
9 
10  SPDX-License-Identifier: LGPL-2.0-or-later
11 */
12 
13 #include <QCommandLineOption>
14 #include <QCommandLineParser>
15 #include <QCoreApplication>
16 #include <QDomAttr>
17 #include <QFile>
18 #include <QFileInfo>
19 #include <QRegularExpression>
20 #include <QSettings>
21 #include <QStringList>
22 #include <QTextStream>
23 
24 #include <algorithm>
25 #include <iostream>
26 #include <ostream>
27 #include <stdlib.h>
28 
29 #include "../../kconfig_version.h"
30 #include "KConfigCommonStructs.h"
31 #include "KConfigHeaderGenerator.h"
32 #include "KConfigParameters.h"
33 #include "KConfigSourceGenerator.h"
34 #include "KConfigXmlParser.h"
35 
36 QString varName(const QString &n, const KConfigParameters &cfg)
37 {
38  QString result;
39  if (!cfg.dpointer) {
40  result = QChar::fromLatin1('m') + n;
41  result[1] = result.at(1).toUpper();
42  } else {
43  result = n;
44  result[0] = result.at(0).toLower();
45  }
46  return result;
47 }
48 
49 QString varPath(const QString &n, const KConfigParameters &cfg)
50 {
51  QString result;
52  if (cfg.dpointer) {
53  result = QLatin1String{"d->"} + varName(n, cfg);
54  } else {
55  result = varName(n, cfg);
56  }
57  return result;
58 }
59 
60 QString enumName(const QString &n)
61 {
62  QString result = QLatin1String("Enum") + n;
63  result[4] = result.at(4).toUpper();
64  return result;
65 }
66 
67 QString enumName(const QString &n, const CfgEntry::Choices &c)
68 {
69  QString result = c.name();
70  if (result.isEmpty()) {
71  result = QLatin1String("Enum") + n;
72  result[4] = result.at(4).toUpper();
73  }
74  return result;
75 }
76 
77 QString enumType(const CfgEntry *e, bool globalEnums)
78 {
79  QString result = e->choices.name();
80  if (result.isEmpty()) {
81  result = QLatin1String("Enum") + e->name;
82  if (!globalEnums) {
83  result += QLatin1String("::type");
84  }
85  result[4] = result.at(4).toUpper();
86  }
87  return result;
88 }
89 
90 QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
91 {
92  QString result = c.name();
93  if (result.isEmpty()) {
94  result = QLatin1String("Enum") + n + QLatin1String("::");
95  result[4] = result.at(4).toUpper();
96  } else if (c.external()) {
97  result = c.externalQualifier();
98  } else {
99  result.clear();
100  }
101  return result;
102 }
103 
104 QString setFunction(const QString &n, const QString &className)
105 {
106  QString result = QLatin1String("set") + n;
107  result[3] = result.at(3).toUpper();
108 
109  if (!className.isEmpty()) {
110  result = className + QLatin1String("::") + result;
111  }
112  return result;
113 }
114 
115 QString changeSignalName(const QString &n)
116 {
117  return n + QLatin1String{"Changed"};
118 }
119 
120 QString getDefaultFunction(const QString &n, const QString &className)
121 {
122  QString result = QLatin1String("default%1Value").arg(n);
123  result[7] = result.at(7).toUpper();
124 
125  if (!className.isEmpty()) {
126  result.prepend(className + QLatin1String("::"));
127  }
128  return result;
129 }
130 
131 QString getFunction(const QString &n, const QString &className)
132 {
133  QString result = n;
134  result[0] = result.at(0).toLower();
135 
136  if (!className.isEmpty()) {
137  result.prepend(className + QLatin1String("::"));
138  }
139  return result;
140 }
141 
142 QString immutableFunction(const QString &n, const QString &className)
143 {
144  QString result = QLatin1String("is") + n;
145  result[2] = result.at(2).toUpper();
146  result += QLatin1String{"Immutable"};
147 
148  if (!className.isEmpty()) {
149  result.prepend(className + QLatin1String("::"));
150  }
151  return result;
152 }
153 
154 void addQuotes(QString &s)
155 {
156  if (!s.startsWith(QLatin1Char('"'))) {
157  s.prepend(QLatin1Char('"'));
158  }
159  if (!s.endsWith(QLatin1Char('"'))) {
160  s.append(QLatin1Char('"'));
161  }
162 }
163 
164 static QString quoteString(const QString &s)
165 {
166  QString r = s;
167  r.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
168  r.replace(QLatin1Char('\"'), QLatin1String("\\\""));
169  r.remove(QLatin1Char('\r'));
170  r.replace(QLatin1Char('\n'), QLatin1String("\\n\"\n\""));
171  return QLatin1Char('\"') + r + QLatin1Char('\"');
172 }
173 
174 QString literalString(const QString &str)
175 {
176  const bool isAscii = std::none_of(str.cbegin(), str.cend(), [](const QChar ch) {
177  return ch.unicode() > 127;
178  });
179 
180  if (isAscii) {
181  return QLatin1String("QStringLiteral( %1 )").arg(quoteString(str));
182  } else {
183  return QLatin1String("QString::fromUtf8( %1 )").arg(quoteString(str));
184  }
185 }
186 
187 QString signalEnumName(const QString &signalName)
188 {
189  QString result;
190  result = QLatin1String("signal") + signalName;
191  result[6] = result.at(6).toUpper();
192 
193  return result;
194 }
195 
196 bool isUnsigned(const QString &type)
197 {
198  return type == QLatin1String("UInt") || type == QLatin1String("ULongLong");
199 }
200 
201 /**
202  Return parameter declaration for given type.
203 */
204 QString param(const QString &t)
205 {
206  const QString type = t.toLower();
207  if (type == QLatin1String("string")) {
208  return QStringLiteral("const QString &");
209  } else if (type == QLatin1String("stringlist")) {
210  return QStringLiteral("const QStringList &");
211  } else if (type == QLatin1String("font")) {
212  return QStringLiteral("const QFont &");
213  } else if (type == QLatin1String("rect")) {
214  return QStringLiteral("const QRect &");
215  } else if (type == QLatin1String("size")) {
216  return QStringLiteral("const QSize &");
217  } else if (type == QLatin1String("color")) {
218  return QStringLiteral("const QColor &");
219  } else if (type == QLatin1String("point")) {
220  return QStringLiteral("const QPoint &");
221  } else if (type == QLatin1String("int")) {
222  return QStringLiteral("int");
223  } else if (type == QLatin1String("uint")) {
224  return QStringLiteral("uint");
225  } else if (type == QLatin1String("bool")) {
226  return QStringLiteral("bool");
227  } else if (type == QLatin1String("double")) {
228  return QStringLiteral("double");
229  } else if (type == QLatin1String("datetime")) {
230  return QStringLiteral("const QDateTime &");
231  } else if (type == QLatin1String("longlong")) {
232  return QStringLiteral("qint64");
233  } else if (type == QLatin1String("ulonglong")) {
234  return QStringLiteral("quint64");
235  } else if (type == QLatin1String("intlist")) {
236  return QStringLiteral("const QList<int> &");
237  } else if (type == QLatin1String("enum")) {
238  return QStringLiteral("int");
239  } else if (type == QLatin1String("path")) {
240  return QStringLiteral("const QString &");
241  } else if (type == QLatin1String("pathlist")) {
242  return QStringLiteral("const QStringList &");
243  } else if (type == QLatin1String("password")) {
244  return QStringLiteral("const QString &");
245  } else if (type == QLatin1String("url")) {
246  return QStringLiteral("const QUrl &");
247  } else if (type == QLatin1String("urllist")) {
248  return QStringLiteral("const QList<QUrl> &");
249  } else {
250  std::cerr << "kconfig_compiler_kf5 does not support type \"" << qPrintable(type) << "\"" << std::endl;
251  return QStringLiteral("QString"); // For now, but an assert would be better
252  }
253 }
254 
255 /**
256  Actual C++ storage type for given type.
257 */
258 QString cppType(const QString &t)
259 {
260  const QString type = t.toLower();
261  if (type == QLatin1String("string")) {
262  return QStringLiteral("QString");
263  } else if (type == QLatin1String("stringlist")) {
264  return QStringLiteral("QStringList");
265  } else if (type == QLatin1String("font")) {
266  return QStringLiteral("QFont");
267  } else if (type == QLatin1String("rect")) {
268  return QStringLiteral("QRect");
269  } else if (type == QLatin1String("size")) {
270  return QStringLiteral("QSize");
271  } else if (type == QLatin1String("color")) {
272  return QStringLiteral("QColor");
273  } else if (type == QLatin1String("point")) {
274  return QStringLiteral("QPoint");
275  } else if (type == QLatin1String("int")) {
276  return QStringLiteral("int");
277  } else if (type == QLatin1String("uint")) {
278  return QStringLiteral("uint");
279  } else if (type == QLatin1String("bool")) {
280  return QStringLiteral("bool");
281  } else if (type == QLatin1String("double")) {
282  return QStringLiteral("double");
283  } else if (type == QLatin1String("datetime")) {
284  return QStringLiteral("QDateTime");
285  } else if (type == QLatin1String("longlong")) {
286  return QStringLiteral("qint64");
287  } else if (type == QLatin1String("ulonglong")) {
288  return QStringLiteral("quint64");
289  } else if (type == QLatin1String("intlist")) {
290  return QStringLiteral("QList<int>");
291  } else if (type == QLatin1String("enum")) {
292  return QStringLiteral("int");
293  } else if (type == QLatin1String("path")) {
294  return QStringLiteral("QString");
295  } else if (type == QLatin1String("pathlist")) {
296  return QStringLiteral("QStringList");
297  } else if (type == QLatin1String("password")) {
298  return QStringLiteral("QString");
299  } else if (type == QLatin1String("url")) {
300  return QStringLiteral("QUrl");
301  } else if (type == QLatin1String("urllist")) {
302  return QStringLiteral("QList<QUrl>");
303  } else {
304  std::cerr << "kconfig_compiler_kf5 does not support type \"" << qPrintable(type) << "\"" << std::endl;
305  return QStringLiteral("QString"); // For now, but an assert would be better
306  }
307 }
308 
309 QString defaultValue(const QString &t)
310 {
311  const QString type = t.toLower();
312  if (type == QLatin1String("string")) {
313  return QStringLiteral("\"\""); // Use empty string, not null string!
314  } else if (type == QLatin1String("stringlist")) {
315  return QStringLiteral("QStringList()");
316  } else if (type == QLatin1String("font")) {
317  return QStringLiteral("QFont()");
318  } else if (type == QLatin1String("rect")) {
319  return QStringLiteral("QRect()");
320  } else if (type == QLatin1String("size")) {
321  return QStringLiteral("QSize()");
322  } else if (type == QLatin1String("color")) {
323  return QStringLiteral("QColor(128, 128, 128)");
324  } else if (type == QLatin1String("point")) {
325  return QStringLiteral("QPoint()");
326  } else if (type == QLatin1String("int")) {
327  return QStringLiteral("0");
328  } else if (type == QLatin1String("uint")) {
329  return QStringLiteral("0");
330  } else if (type == QLatin1String("bool")) {
331  return QStringLiteral("false");
332  } else if (type == QLatin1String("double")) {
333  return QStringLiteral("0.0");
334  } else if (type == QLatin1String("datetime")) {
335  return QStringLiteral("QDateTime()");
336  } else if (type == QLatin1String("longlong")) {
337  return QStringLiteral("0");
338  } else if (type == QLatin1String("ulonglong")) {
339  return QStringLiteral("0");
340  } else if (type == QLatin1String("intlist")) {
341  return QStringLiteral("QList<int>()");
342  } else if (type == QLatin1String("enum")) {
343  return QStringLiteral("0");
344  } else if (type == QLatin1String("path")) {
345  return QStringLiteral("\"\""); // Use empty string, not null string!
346  } else if (type == QLatin1String("pathlist")) {
347  return QStringLiteral("QStringList()");
348  } else if (type == QLatin1String("password")) {
349  return QStringLiteral("\"\""); // Use empty string, not null string!
350  } else if (type == QLatin1String("url")) {
351  return QStringLiteral("QUrl()");
352  } else if (type == QLatin1String("urllist")) {
353  return QStringLiteral("QList<QUrl>()");
354  } else {
355  std::cerr << "Error, kconfig_compiler_kf5 does not support the \"" << qPrintable(type) << "\" type!" << std::endl;
356  return QStringLiteral("QString"); // For now, but an assert would be better
357  }
358 }
359 
360 QString itemType(const QString &type)
361 {
362  if (type.isEmpty()) {
363  return QString{};
364  }
365 
366  QString str = type;
367  str[0] = str.at(0).toUpper();
368 
369  return str;
370 }
371 
372 QString itemDeclaration(const CfgEntry *e, const KConfigParameters &cfg)
373 {
374  if (e->name.isEmpty()) {
375  return QString{};
376  }
377 
378  const QString type = cfg.inherits + QLatin1String{"::Item"} + itemType(e->type);
379 
380  QString fCap = e->name;
381  fCap[0] = fCap.at(0).toUpper();
382  const QString argSuffix = (!e->param.isEmpty()) ? (QStringLiteral("[%1]").arg(e->paramMax + 1)) : QString();
383  QString result;
384 
385  if (!cfg.itemAccessors && !cfg.dpointer) {
386  result += QLatin1String{" "} + (!e->signalList.isEmpty() ? QStringLiteral("KConfigCompilerSignallingItem") : type);
387  result += QLatin1String(" *item%1;\n").arg(fCap + argSuffix);
388  }
389 
390  if (!e->signalList.isEmpty()) {
391  result += QLatin1String(" %1 *%2;\n").arg(type, innerItemVar(e, cfg) + argSuffix);
392  }
393 
394  return result;
395 }
396 
397 // returns the name of an item variable
398 // use itemPath to know the full path
399 // like using d-> in case of dpointer
400 QString itemVar(const CfgEntry *e, const KConfigParameters &cfg)
401 {
402  QString result;
403  if (cfg.itemAccessors) {
404  if (!cfg.dpointer) {
405  result = QLatin1String("m%1Item").arg(e->name);
406  result[1] = result.at(1).toUpper();
407  } else {
408  result = e->name + QLatin1String{"Item"};
409  result[0] = result.at(0).toLower();
410  }
411  } else {
412  result = QLatin1String{"item"} + e->name;
413  result[4] = result.at(4).toUpper();
414  }
415  return result;
416 }
417 
418 // returns the name of the local inner item if there is one
419 // (before wrapping with KConfigCompilerSignallingItem)
420 // Otherwise return itemVar()
421 QString innerItemVar(const CfgEntry *e, const KConfigParameters &cfg)
422 {
423  if (e->signalList.isEmpty()) {
424  return itemPath(e, cfg);
425  }
426 
427  QString result = QLatin1String{"innerItem"} + e->name;
428  result[9] = result.at(9).toUpper();
429  return result;
430 }
431 
432 QString itemPath(const CfgEntry *e, const KConfigParameters &cfg)
433 {
434  return cfg.dpointer ? QLatin1String{"d->"} + itemVar(e, cfg) : itemVar(e, cfg);
435 }
436 
437 QString newInnerItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString &param)
438 {
439  QString str = QLatin1String("new %1::Item%2").arg(cfg.inherits, itemType(entry->type));
440  str += QLatin1String("( currentGroup(), %1, %2").arg(key, varPath(entry->name, cfg) + param);
441 
442  if (entry->type == QLatin1String("Enum")) {
443  str += QLatin1String{", values"} + entry->name;
444  }
445  if (!defaultValue.isEmpty()) {
446  str += QLatin1String(", ") + defaultValue;
447  }
448  str += QLatin1String(" );");
449 
450  return str;
451 }
452 
453 QString newItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString &param)
454 {
455  const QList<Signal> sigs = entry->signalList;
456  if (sigs.isEmpty()) {
457  return newInnerItem(entry, key, defaultValue, cfg, param);
458  }
459 
460  QString str;
461  str += QLatin1String("new KConfigCompilerSignallingItem(%1, this, notifyFunction, ").arg(innerItemVar(entry, cfg) + param);
462  // Append the signal flags
463  const int listSize = sigs.size();
464  for (int i = 0; i < listSize; ++i) {
465  if (i != 0) {
466  str += QLatin1String(" | ");
467  }
468  str += signalEnumName(sigs[i].name);
469  }
470  str += QLatin1String(");");
471 
472  return str;
473 }
474 
475 QString paramString(const QString &s, const CfgEntry *e, int i)
476 {
477  QString result = s;
478  const QString needle = QLatin1String("$(%1)").arg(e->param);
479  if (result.contains(needle)) {
480  const QString tmp = e->paramType == QLatin1String{"Enum"} ? e->paramValues.at(i) : QString::number(i);
481 
482  result.replace(needle, tmp);
483  }
484  return result;
485 }
486 
487 QString paramString(const QString &group, const QList<Param> &parameters)
488 {
489  QString paramString = group;
490  QString arguments;
491  int i = 1;
492  bool firstArg = true;
493  for (const auto &param : parameters) {
494  const QString paramName = param.name;
495  const QString str = QLatin1String("$(%1)").arg(paramName);
496  if (paramString.contains(str)) {
497  const QString tmp = QStringLiteral("%%1").arg(i++);
498  paramString.replace(str, tmp);
499 
500  if (firstArg) {
501  arguments += QLatin1String{".arg( "};
502  firstArg = false;
503  }
504 
505  arguments += QLatin1String("mParam%1, ").arg(paramName);
506  }
507  }
508 
509  if (!arguments.isEmpty()) {
510  // Remove the last ", "
511  arguments.chop(2);
512 
513  // Close the ".arg( "
514  arguments += QLatin1String{" )"};
515  } else {
516  return QLatin1String("QStringLiteral( \"%1\" )").arg(group);
517  }
518 
519  return QLatin1String("QStringLiteral( \"%1\" )%2").arg(paramString, arguments);
520 }
521 
522 QString translatedString(const KConfigParameters &cfg, const QString &string, const QString &context, const QString &param, const QString &paramValue)
523 {
524  QString result;
525 
526  switch (cfg.translationSystem) {
527  case KConfigParameters::QtTranslation:
528  if (!context.isEmpty()) {
529  result += QLatin1String("/*: %1 */ QCoreApplication::translate(\"").arg(context);
530  } else {
531  result += QLatin1String{"QCoreApplication::translate(\""};
532  }
533  result += QLatin1String("%1\", ").arg(cfg.className);
534  break;
535 
536  case KConfigParameters::KdeTranslation:
537  if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) {
538  result += QLatin1String("i18ndc(%1, %2, ").arg(quoteString(cfg.translationDomain), quoteString(context));
539  } else if (!cfg.translationDomain.isEmpty()) {
540  result += QLatin1String("i18nd(%1, ").arg(quoteString(cfg.translationDomain));
541  } else if (!context.isEmpty()) {
542  result += QLatin1String("i18nc(%1, ").arg(quoteString(context));
543  } else {
544  result += QLatin1String{"i18n("};
545  }
546  break;
547  }
548 
549  if (!param.isEmpty()) {
550  QString resolvedString = string;
551  resolvedString.replace(QLatin1String("$(%1)").arg(param), paramValue);
552  result += quoteString(resolvedString);
553  } else {
554  result += quoteString(string);
555  }
556 
557  result += QLatin1Char{')'};
558 
559  return result;
560 }
561 
562 /* int i is the value of the parameter */
563 QString userTextsFunctions(const CfgEntry *e, const KConfigParameters &cfg, QString itemVarStr, const QString &i)
564 {
565  QString txt;
566  if (itemVarStr.isNull()) {
567  itemVarStr = itemPath(e, cfg);
568  }
569  if (!e->label.isEmpty()) {
570  txt += QLatin1String(" %1->setLabel( %2 );\n").arg(itemVarStr, translatedString(cfg, e->label, e->labelContext, e->param, i));
571  }
572  if (!e->toolTip.isEmpty()) {
573  txt += QLatin1String(" %1->setToolTip( %2 );\n").arg(itemVarStr, translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i));
574  }
575  if (!e->whatsThis.isEmpty()) {
576  txt += QLatin1String(" %1->setWhatsThis( %2 );\n").arg(itemVarStr, translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i));
577  }
578  return txt;
579 }
580 
581 // returns the member mutator implementation
582 // which should go in the h file if inline
583 // or the cpp file if not inline
584 // TODO: Fix add Debug Method, it should also take the debug string.
585 void addDebugMethod(QTextStream &out, const KConfigParameters &cfg, const QString &n)
586 {
587  if (cfg.qCategoryLoggingName.isEmpty()) {
588  out << " qDebug() << \"" << setFunction(n);
589  } else {
590  out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n);
591  }
592 }
593 
594 // returns the member get default implementation
595 // which should go in the h file if inline
596 // or the cpp file if not inline
597 QString memberGetDefaultBody(const CfgEntry *e)
598 {
599  QString result = e->code;
600  QTextStream out(&result, QIODevice::WriteOnly);
601  out << '\n';
602 
603  if (!e->param.isEmpty()) {
604  out << " switch (i) {\n";
605  for (int i = 0; i <= e->paramMax; ++i) {
606  if (!e->paramDefaultValues[i].isEmpty()) {
607  out << " case " << i << ": return " << e->paramDefaultValues[i] << ";\n";
608  }
609  }
610  QString defaultValue = e->defaultValue;
611 
612  out << " default:\n";
613  out << " return " << defaultValue.replace(QLatin1String("$(%1)").arg(e->param), QLatin1String("i")) << ";\n";
614  out << " }\n";
615  } else {
616  out << " return " << e->defaultValue << ';';
617  }
618 
619  return result;
620 }
621 
622 // returns the item accesor implementation
623 // which should go in the h file if inline
624 // or the cpp file if not inline
625 QString itemAccessorBody(const CfgEntry *e, const KConfigParameters &cfg)
626 {
627  QString result;
628  QTextStream out(&result, QIODevice::WriteOnly);
629 
630  out << "return " << itemPath(e, cfg);
631  if (!e->param.isEmpty()) {
632  out << "[i]";
633  }
634  out << ";\n";
635 
636  return result;
637 }
638 
639 // indents text adding X spaces per line
640 QString indent(QString text, int spaces)
641 {
642  QString result;
643  QTextStream out(&result, QIODevice::WriteOnly);
644  QTextStream in(&text, QIODevice::ReadOnly);
645  QString currLine;
646  while (!in.atEnd()) {
647  currLine = in.readLine();
648  if (!currLine.isEmpty())
649  for (int i = 0; i < spaces; ++i) {
650  out << " ";
651  }
652  out << currLine << '\n';
653  }
654  return result;
655 }
656 
657 bool hasErrors(KConfigXmlParser &parser, const ParseResult &parseResult, const KConfigParameters &cfg)
658 {
659  Q_UNUSED(parser)
660 
661  if (cfg.className.isEmpty()) {
662  std::cerr << "Class name missing" << std::endl;
663  return true;
664  }
665 
666  if (cfg.singleton && !parseResult.parameters.isEmpty()) {
667  std::cerr << "Singleton class can not have parameters" << std::endl;
668  return true;
669  }
670 
671  if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) {
672  std::cerr << "Having both a fixed filename and a filename as argument is not possible." << std::endl;
673  return true;
674  }
675 
676  /* TODO: For some reason some configuration files prefer to have *no* entries
677  * at all in it, and the generated code is mostly bogus as KConfigXT will not
678  * handle save / load / properties, etc, nothing.
679  *
680  * The first of those files that I came across are qmakebuilderconfig.kcfg from the KDevelop
681  * project.
682  * I think we should remove the possibility of creating configuration classes from configuration
683  * files that don't really have configuration in it. but I'm changing this right now to allow
684  * kdevelop files to pass.
685  *
686  * Remove for KDE 6
687  * (to make things more interesting, it failed in a code that's never used within KDevelop... )
688  */
689  if (parseResult.entries.isEmpty()) {
690  std::cerr << "No entries." << std::endl;
691  return false;
692  }
693 
694  return false;
695 }
696 
697 int main(int argc, char **argv)
698 {
699  QCoreApplication app(argc, argv);
700  app.setApplicationName(QStringLiteral("kconfig_compiler"));
701  app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING));
702 
703  QString inputFilename, codegenFilename;
704 
705  QCommandLineOption targetDirectoryOption(QStringList{QStringLiteral("d"), QStringLiteral("directory")},
706  QCoreApplication::translate("main", "Directory to generate files in [.]"),
707  QCoreApplication::translate("main", "directory"),
708  QStringLiteral("."));
709 
710  QCommandLineOption licenseOption(QStringList{QStringLiteral("l"), QStringLiteral("license")},
711  QCoreApplication::translate("main", "Display software license."));
712 
713  QCommandLineParser parser;
714 
715  parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file"));
716  parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file"));
717 
718  parser.addOption(targetDirectoryOption);
719  parser.addOption(licenseOption);
720 
721  parser.addVersionOption();
722  parser.addHelpOption();
723  parser.process(app);
724 
725  if (parser.isSet(licenseOption)) {
726  std::cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << std::endl;
727  std::cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << std::endl;
728  std::cout << "This program comes with ABSOLUTELY NO WARRANTY." << std::endl;
729  std::cout << "You may redistribute copies of this program" << std::endl;
730  std::cout << "under the terms of the GNU Library Public License." << std::endl;
731  std::cout << "For more information about these matters, see the file named COPYING." << std::endl;
732  return 0;
733  }
734 
735  const QStringList args = parser.positionalArguments();
736  if (args.count() < 2) {
737  std::cerr << "Too few arguments." << std::endl;
738  return 1;
739  }
740 
741  if (args.count() > 2) {
742  std::cerr << "Too many arguments." << std::endl;
743  return 1;
744  }
745  inputFilename = args.at(0);
746  codegenFilename = args.at(1);
747 
748  // TODO: Transform baseDir into a helper.
749  QString baseDir = parser.value(targetDirectoryOption);
750 
751 #ifdef Q_OS_WIN
752  if (!baseDir.endsWith(QLatin1Char{'/'}) && !baseDir.endsWith(QLatin1Char{'\\'})) {
753 #else
754  if (!baseDir.endsWith(QLatin1Char{'/'})) {
755 #endif
756  baseDir.append(QLatin1Char{'/'});
757  }
758 
759  KConfigParameters cfg(codegenFilename);
760 
761  KConfigXmlParser xmlParser(cfg, inputFilename);
762 
763  // The Xml Parser aborts in the case of an error, so if we get
764  // to parseResult, we have a working Xml file.
765  xmlParser.start();
766 
767  ParseResult parseResult = xmlParser.getParseResult();
768 
769  if (hasErrors(xmlParser, parseResult, cfg)) {
770  return 1;
771  }
772 
773  // TODO: Move this to somewhere saner.
774  for (const auto &signal : qAsConst(parseResult.signalList)) {
775  parseResult.hasNonModifySignals |= !signal.modify;
776  }
777 
778  // remove '.kcfg' from the name.
779  const QString baseName = inputFilename.mid(0, inputFilename.size() - 5);
780  KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult);
781  headerGenerator.start();
782  headerGenerator.save();
783 
784  KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult);
785  sourceGenerator.start();
786  sourceGenerator.save();
787 
788  qDeleteAll(parseResult.entries);
789 }
QString & append(QChar ch)
QString & prepend(QChar ch)
const T & at(int i) const const
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
int size() const const
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
QString & remove(int position, int n)
void chop(int n)
int size() const const
bool isNull() const const
void clear()
QLatin1Char at(int pos) const const
QString number(int n, int base)
int count(const T &value) const const
QString::const_iterator cend() const const
Type type(const QSqlDatabase &db)
QChar fromLatin1(char c)
bool isEmpty() const const
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString toLower() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QChar toLower() const const
QString & replace(int position, int n, QChar after)
QString::const_iterator cbegin() const const
QString mid(int position, int n) const const
QChar toUpper() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
QString arg(Args &&...args) const const
Configuration Compiler Configuration.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jun 22 2021 22:47:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.