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

KDE's Doxygen guidelines are available online.