KConfig

kconfig_compiler.cpp
1 /*
2  This file is part of KDE.
3 
4  SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
5  SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org>
6  SPDX-FileCopyrightText: 2003 Zack Rusin <zack@kde.org>
7  SPDX-FileCopyrightText: 2006 MichaĆ«l Larouche <michael.larouche@kdemail.net>
8  SPDX-FileCopyrightText: 2008 Allen Winter <winter@kde.org>
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 "../core/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("rectf")) {
216  return QStringLiteral("const QRectF &");
217  } else if (type == QLatin1String("size")) {
218  return QStringLiteral("const QSize &");
219  } else if (type == QLatin1String("sizef")) {
220  return QStringLiteral("const QSizeF &");
221  } else if (type == QLatin1String("color")) {
222  return QStringLiteral("const QColor &");
223  } else if (type == QLatin1String("point")) {
224  return QStringLiteral("const QPoint &");
225  } else if (type == QLatin1String("pointf")) {
226  return QStringLiteral("const QPointF &");
227  } else if (type == QLatin1String("int")) {
228  return QStringLiteral("int");
229  } else if (type == QLatin1String("uint")) {
230  return QStringLiteral("uint");
231  } else if (type == QLatin1String("bool")) {
232  return QStringLiteral("bool");
233  } else if (type == QLatin1String("double")) {
234  return QStringLiteral("double");
235  } else if (type == QLatin1String("datetime")) {
236  return QStringLiteral("const QDateTime &");
237  } else if (type == QLatin1String("longlong")) {
238  return QStringLiteral("qint64");
239  } else if (type == QLatin1String("ulonglong")) {
240  return QStringLiteral("quint64");
241  } else if (type == QLatin1String("intlist")) {
242  return QStringLiteral("const QList<int> &");
243  } else if (type == QLatin1String("enum")) {
244  return QStringLiteral("int");
245  } else if (type == QLatin1String("path")) {
246  return QStringLiteral("const QString &");
247  } else if (type == QLatin1String("pathlist")) {
248  return QStringLiteral("const QStringList &");
249  } else if (type == QLatin1String("password")) {
250  return QStringLiteral("const QString &");
251  } else if (type == QLatin1String("url")) {
252  return QStringLiteral("const QUrl &");
253  } else if (type == QLatin1String("urllist")) {
254  return QStringLiteral("const QList<QUrl> &");
255  } else {
256  std::cerr << "kconfig_compiler_kf6 does not support type \"" << qPrintable(type) << "\"" << std::endl;
257  return QStringLiteral("QString"); // For now, but an assert would be better
258  }
259 }
260 
261 /**
262  Actual C++ storage type for given type.
263 */
264 QString cppType(const QString &t)
265 {
266  const QString type = t.toLower();
267  if (type == QLatin1String("string")) {
268  return QStringLiteral("QString");
269  } else if (type == QLatin1String("stringlist")) {
270  return QStringLiteral("QStringList");
271  } else if (type == QLatin1String("font")) {
272  return QStringLiteral("QFont");
273  } else if (type == QLatin1String("rect")) {
274  return QStringLiteral("QRect");
275  } else if (type == QLatin1String("rectf")) {
276  return QStringLiteral("QRectF");
277  } else if (type == QLatin1String("size")) {
278  return QStringLiteral("QSize");
279  } else if (type == QLatin1String("sizef")) {
280  return QStringLiteral("QSizeF");
281  } else if (type == QLatin1String("color")) {
282  return QStringLiteral("QColor");
283  } else if (type == QLatin1String("point")) {
284  return QStringLiteral("QPoint");
285  } else if (type == QLatin1String("pointf")) {
286  return QStringLiteral("QPointF");
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_kf6 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("rectf")) {
333  return QStringLiteral("QRectF()");
334  } else if (type == QLatin1String("size")) {
335  return QStringLiteral("QSize()");
336  } else if (type == QLatin1String("sizef")) {
337  return QStringLiteral("QSizeF()");
338  } else if (type == QLatin1String("color")) {
339  return QStringLiteral("QColor(128, 128, 128)");
340  } else if (type == QLatin1String("point")) {
341  return QStringLiteral("QPoint()");
342  } else if (type == QLatin1String("pointf")) {
343  return QStringLiteral("QPointF()");
344  } else if (type == QLatin1String("int")) {
345  return QStringLiteral("0");
346  } else if (type == QLatin1String("uint")) {
347  return QStringLiteral("0");
348  } else if (type == QLatin1String("bool")) {
349  return QStringLiteral("false");
350  } else if (type == QLatin1String("double")) {
351  return QStringLiteral("0.0");
352  } else if (type == QLatin1String("datetime")) {
353  return QStringLiteral("QDateTime()");
354  } else if (type == QLatin1String("longlong")) {
355  return QStringLiteral("0");
356  } else if (type == QLatin1String("ulonglong")) {
357  return QStringLiteral("0");
358  } else if (type == QLatin1String("intlist")) {
359  return QStringLiteral("QList<int>()");
360  } else if (type == QLatin1String("enum")) {
361  return QStringLiteral("0");
362  } else if (type == QLatin1String("path")) {
363  return QStringLiteral("\"\""); // Use empty string, not null string!
364  } else if (type == QLatin1String("pathlist")) {
365  return QStringLiteral("QStringList()");
366  } else if (type == QLatin1String("password")) {
367  return QStringLiteral("\"\""); // Use empty string, not null string!
368  } else if (type == QLatin1String("url")) {
369  return QStringLiteral("QUrl()");
370  } else if (type == QLatin1String("urllist")) {
371  return QStringLiteral("QList<QUrl>()");
372  } else {
373  std::cerr << "Error, kconfig_compiler_kf6 does not support the \"" << qPrintable(type) << "\" type!" << std::endl;
374  return QStringLiteral("QString"); // For now, but an assert would be better
375  }
376 }
377 
378 QString itemType(const QString &type)
379 {
380  if (type.isEmpty()) {
381  return QString{};
382  }
383 
384  QString str = type;
385  str[0] = str.at(0).toUpper();
386 
387  return str;
388 }
389 
390 QString itemDeclaration(const CfgEntry *e, const KConfigParameters &cfg)
391 {
392  if (e->name.isEmpty()) {
393  return QString{};
394  }
395 
396  const QString type = cfg.inherits + QLatin1String{"::Item"} + itemType(e->type);
397 
398  QString fCap = e->name;
399  fCap[0] = fCap.at(0).toUpper();
400  const QString argSuffix = (!e->param.isEmpty()) ? (QStringLiteral("[%1]").arg(e->paramMax + 1)) : QString();
401  QString result;
402 
403  if (!cfg.itemAccessors && !cfg.dpointer) {
404  result += QLatin1String{" "} + (!e->signalList.isEmpty() ? QStringLiteral("KConfigCompilerSignallingItem") : type);
405  result += QLatin1String(" *item%1;\n").arg(fCap + argSuffix);
406  }
407 
408  if (!e->signalList.isEmpty()) {
409  result += QLatin1String(" %1 *%2;\n").arg(type, innerItemVar(e, cfg) + argSuffix);
410  }
411 
412  return result;
413 }
414 
415 // returns the name of an item variable
416 // use itemPath to know the full path
417 // like using d-> in case of dpointer
418 QString itemVar(const CfgEntry *e, const KConfigParameters &cfg)
419 {
420  QString result;
421  if (cfg.itemAccessors) {
422  if (!cfg.dpointer) {
423  result = QLatin1String("m%1Item").arg(e->name);
424  result[1] = result.at(1).toUpper();
425  } else {
426  result = e->name + QLatin1String{"Item"};
427  result[0] = result.at(0).toLower();
428  }
429  } else {
430  result = QLatin1String{"item"} + e->name;
431  result[4] = result.at(4).toUpper();
432  }
433  return result;
434 }
435 
436 // returns the name of the local inner item if there is one
437 // (before wrapping with KConfigCompilerSignallingItem)
438 // Otherwise return itemVar()
439 QString innerItemVar(const CfgEntry *e, const KConfigParameters &cfg)
440 {
441  if (e->signalList.isEmpty()) {
442  return itemPath(e, cfg);
443  }
444 
445  QString result = QLatin1String{"innerItem"} + e->name;
446  result[9] = result.at(9).toUpper();
447  return result;
448 }
449 
450 QString itemPath(const CfgEntry *e, const KConfigParameters &cfg)
451 {
452  return cfg.dpointer ? QLatin1String{"d->"} + itemVar(e, cfg) : itemVar(e, cfg);
453 }
454 
455 QString newInnerItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString &param)
456 {
457  QString str = QLatin1String("new %1::Item%2").arg(cfg.inherits, itemType(entry->type));
458  str += QLatin1String("( currentGroup(), %1, %2").arg(key, varPath(entry->name, cfg) + param);
459 
460  if (entry->type == QLatin1String("Enum")) {
461  str += QLatin1String{", values"} + entry->name;
462  }
463  if (!defaultValue.isEmpty()) {
464  str += QLatin1String(", ") + defaultValue;
465  }
466  str += QLatin1String(" );");
467 
468  return str;
469 }
470 
471 QString newItem(const CfgEntry *entry, const QString &key, const QString &defaultValue, const KConfigParameters &cfg, const QString &param)
472 {
473  const QList<Signal> sigs = entry->signalList;
474  if (sigs.isEmpty()) {
475  return newInnerItem(entry, key, defaultValue, cfg, param);
476  }
477 
478  QString str;
479  str += QLatin1String("new KConfigCompilerSignallingItem(%1, this, notifyFunction, ").arg(innerItemVar(entry, cfg) + param);
480  // Append the signal flags
481  const int listSize = sigs.size();
482  for (int i = 0; i < listSize; ++i) {
483  if (i != 0) {
484  str += QLatin1String(" | ");
485  }
486  str += signalEnumName(sigs[i].name);
487  }
488  str += QLatin1String(");");
489 
490  return str;
491 }
492 
493 QString paramString(const QString &s, const CfgEntry *e, int i)
494 {
495  QString result = s;
496  const QString needle = QLatin1String("$(%1)").arg(e->param);
497  if (result.contains(needle)) {
498  const QString tmp = e->paramType == QLatin1String{"Enum"} ? e->paramValues.at(i) : QString::number(i);
499 
500  result.replace(needle, tmp);
501  }
502  return result;
503 }
504 
505 QString paramString(const QString &group, const QList<Param> &parameters)
506 {
507  QString paramString = group;
508  QString arguments;
509  int i = 1;
510  bool firstArg = true;
511  for (const auto &param : parameters) {
512  const QString paramName = param.name;
513  const QString str = QLatin1String("$(%1)").arg(paramName);
514  if (paramString.contains(str)) {
515  const QString tmp = QStringLiteral("%%1").arg(i++);
516  paramString.replace(str, tmp);
517 
518  if (firstArg) {
519  arguments += QLatin1String{".arg( "};
520  firstArg = false;
521  }
522 
523  arguments += QLatin1String("mParam%1, ").arg(paramName);
524  }
525  }
526 
527  if (!arguments.isEmpty()) {
528  // Remove the last ", "
529  arguments.chop(2);
530 
531  // Close the ".arg( "
532  arguments += QLatin1String{" )"};
533  } else {
534  return QLatin1String("QStringLiteral( \"%1\" )").arg(group);
535  }
536 
537  return QLatin1String("QStringLiteral( \"%1\" )%2").arg(paramString, arguments);
538 }
539 
540 QString translatedString(const KConfigParameters &cfg, const QString &string, const QString &context, const QString &param, const QString &paramValue)
541 {
542  QString result;
543 
544  switch (cfg.translationSystem) {
545  case KConfigParameters::QtTranslation:
546  if (!context.isEmpty()) {
547  result += QLatin1String("/*: %1 */ QCoreApplication::translate(\"").arg(context);
548  } else {
549  result += QLatin1String{"QCoreApplication::translate(\""};
550  }
551  result += QLatin1String("%1\", ").arg(cfg.className);
552  break;
553 
554  case KConfigParameters::KdeTranslation:
555  if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) {
556  result += QLatin1String("i18ndc(%1, %2, ").arg(quoteString(cfg.translationDomain), quoteString(context));
557  } else if (!cfg.translationDomain.isEmpty()) {
558  result += QLatin1String("i18nd(%1, ").arg(quoteString(cfg.translationDomain));
559  } else if (!context.isEmpty()) {
560  result += QLatin1String("i18nc(%1, ").arg(quoteString(context));
561  } else {
562  result += QLatin1String{"i18n("};
563  }
564  break;
565  }
566 
567  if (!param.isEmpty()) {
568  QString resolvedString = string;
569  resolvedString.replace(QLatin1String("$(%1)").arg(param), paramValue);
570  result += quoteString(resolvedString);
571  } else {
572  result += quoteString(string);
573  }
574 
575  result += QLatin1Char{')'};
576 
577  return result;
578 }
579 
580 /* int i is the value of the parameter */
581 QString userTextsFunctions(const CfgEntry *e, const KConfigParameters &cfg, QString itemVarStr, const QString &i)
582 {
583  QString txt;
584  if (itemVarStr.isNull()) {
585  itemVarStr = itemPath(e, cfg);
586  }
587  if (!e->label.isEmpty()) {
588  txt += QLatin1String(" %1->setLabel( %2 );\n").arg(itemVarStr, translatedString(cfg, e->label, e->labelContext, e->param, i));
589  }
590  if (!e->toolTip.isEmpty()) {
591  txt += QLatin1String(" %1->setToolTip( %2 );\n").arg(itemVarStr, translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i));
592  }
593  if (!e->whatsThis.isEmpty()) {
594  txt += QLatin1String(" %1->setWhatsThis( %2 );\n").arg(itemVarStr, translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i));
595  }
596  return txt;
597 }
598 
599 // returns the member mutator implementation
600 // which should go in the h file if inline
601 // or the cpp file if not inline
602 // TODO: Fix add Debug Method, it should also take the debug string.
603 void addDebugMethod(QTextStream &out, const KConfigParameters &cfg, const QString &n)
604 {
605  if (cfg.qCategoryLoggingName.isEmpty()) {
606  out << " qDebug() << \"" << setFunction(n);
607  } else {
608  out << " qCDebug(" << cfg.qCategoryLoggingName << ") << \"" << setFunction(n);
609  }
610 }
611 
612 // returns the member get default implementation
613 // which should go in the h file if inline
614 // or the cpp file if not inline
615 QString memberGetDefaultBody(const CfgEntry *e)
616 {
617  QString result = e->code;
618  QTextStream out(&result, QIODevice::WriteOnly);
619  out << '\n';
620 
621  if (!e->param.isEmpty()) {
622  out << " switch (i) {\n";
623  for (int i = 0; i <= e->paramMax; ++i) {
624  if (!e->paramDefaultValues[i].isEmpty()) {
625  out << " case " << i << ": return " << e->paramDefaultValues[i] << ";\n";
626  }
627  }
628  QString defaultValue = e->defaultValue;
629 
630  out << " default:\n";
631  out << " return " << defaultValue.replace(QLatin1String("$(%1)").arg(e->param), QLatin1String("i")) << ";\n";
632  out << " }\n";
633  } else {
634  out << " return " << e->defaultValue << ';';
635  }
636 
637  return result;
638 }
639 
640 // returns the item accessor implementation
641 // which should go in the h file if inline
642 // or the cpp file if not inline
643 QString itemAccessorBody(const CfgEntry *e, const KConfigParameters &cfg)
644 {
645  QString result;
646  QTextStream out(&result, QIODevice::WriteOnly);
647 
648  out << "return " << itemPath(e, cfg);
649  if (!e->param.isEmpty()) {
650  out << "[i]";
651  }
652  out << ";\n";
653 
654  return result;
655 }
656 
657 // indents text adding X spaces per line
658 QString indent(QString text, int spaces)
659 {
660  QString result;
661  QTextStream out(&result, QIODevice::WriteOnly);
662  QTextStream in(&text, QIODevice::ReadOnly);
663  QString currLine;
664  while (!in.atEnd()) {
665  currLine = in.readLine();
666  if (!currLine.isEmpty()) {
667  for (int i = 0; i < spaces; ++i) {
668  out << " ";
669  }
670  }
671  out << currLine << '\n';
672  }
673  return result;
674 }
675 
676 bool hasErrors(KConfigXmlParser &parser, const ParseResult &parseResult, const KConfigParameters &cfg)
677 {
678  Q_UNUSED(parser)
679 
680  if (cfg.className.isEmpty()) {
681  std::cerr << "Class name missing" << std::endl;
682  return true;
683  }
684 
685  if (cfg.singleton && !parseResult.parameters.isEmpty()) {
686  std::cerr << "Singleton class can not have parameters" << std::endl;
687  return true;
688  }
689 
690  if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) {
691  std::cerr << "Having both a fixed filename and a filename as argument is not possible." << std::endl;
692  return true;
693  }
694 
695  /* TODO: For some reason some configuration files prefer to have *no* entries
696  * at all in it, and the generated code is mostly bogus as KConfigXT will not
697  * handle save / load / properties, etc, nothing.
698  *
699  * The first of those files that I came across are qmakebuilderconfig.kcfg from the KDevelop
700  * project.
701  * I think we should remove the possibility of creating configuration classes from configuration
702  * files that don't really have configuration in it. but I'm changing this right now to allow
703  * kdevelop files to pass.
704  *
705  * Remove for KDE 6
706  * (to make things more interesting, it failed in a code that's never used within KDevelop... )
707  */
708  if (parseResult.entries.isEmpty()) {
709  std::cerr << "No entries." << std::endl;
710  return false;
711  }
712 
713  return false;
714 }
715 
716 int main(int argc, char **argv)
717 {
718  QCoreApplication app(argc, argv);
719  app.setApplicationName(QStringLiteral("kconfig_compiler"));
720  app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING));
721 
722  QString inputFilename;
723  QString codegenFilename;
724 
725  QCommandLineOption targetDirectoryOption(QStringList{QStringLiteral("d"), QStringLiteral("directory")},
726  QCoreApplication::translate("main", "Directory to generate files in [.]"),
727  QCoreApplication::translate("main", "directory"),
728  QStringLiteral("."));
729 
730  QCommandLineOption licenseOption(QStringList{QStringLiteral("l"), QStringLiteral("license")},
731  QCoreApplication::translate("main", "Display software license."));
732 
733  QCommandLineParser parser;
734 
735  parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file"));
736  parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file"));
737 
738  parser.addOption(targetDirectoryOption);
739  parser.addOption(licenseOption);
740 
741  parser.addVersionOption();
742  parser.addHelpOption();
743  parser.process(app);
744 
745  if (parser.isSet(licenseOption)) {
746  std::cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << std::endl;
747  std::cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << std::endl;
748  std::cout << "This program comes with ABSOLUTELY NO WARRANTY." << std::endl;
749  std::cout << "You may redistribute copies of this program" << std::endl;
750  std::cout << "under the terms of the GNU Library Public License." << std::endl;
751  std::cout << "For more information about these matters, see the file named COPYING." << std::endl;
752  return 0;
753  }
754 
755  const QStringList args = parser.positionalArguments();
756  if (args.count() < 2) {
757  std::cerr << "Too few arguments." << std::endl;
758  return 1;
759  }
760 
761  if (args.count() > 2) {
762  std::cerr << "Too many arguments." << std::endl;
763  return 1;
764  }
765  inputFilename = args.at(0);
766  codegenFilename = args.at(1);
767 
768  // TODO: Transform baseDir into a helper.
769  QString baseDir = parser.value(targetDirectoryOption);
770 
771 #ifdef Q_OS_WIN
772  if (!baseDir.endsWith(QLatin1Char{'/'}) && !baseDir.endsWith(QLatin1Char{'\\'})) {
773 #else
774  if (!baseDir.endsWith(QLatin1Char{'/'})) {
775 #endif
776  baseDir.append(QLatin1Char{'/'});
777  }
778 
779  KConfigParameters cfg(codegenFilename);
780 
781  KConfigXmlParser xmlParser(cfg, inputFilename);
782 
783  // The Xml Parser aborts in the case of an error, so if we get
784  // to parseResult, we have a working Xml file.
785  xmlParser.start();
786 
787  ParseResult parseResult = xmlParser.getParseResult();
788 
789  if (hasErrors(xmlParser, parseResult, cfg)) {
790  return 1;
791  }
792 
793  // TODO: Move this to somewhere saner.
794  for (const auto &signal : std::as_const(parseResult.signalList)) {
795  parseResult.hasNonModifySignals |= !signal.modify;
796  }
797 
798  // remove '.kcfg' from the name.
799  const QString baseName = inputFilename.mid(0, inputFilename.size() - 5);
800  KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult);
801  headerGenerator.start();
802  headerGenerator.save();
803 
804  KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult);
805  sourceGenerator.start();
806  sourceGenerator.save();
807 
808  qDeleteAll(parseResult.entries);
809 }
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool isNull() const const
QString number(int n, int base)
QChar toLower() const const
int size() const const
Configuration Compiler Configuration.
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
Type type(const QSqlDatabase &db)
int count(const T &value) const const
void clear()
QString arg(Args &&... args) const const
QChar toUpper() const const
QString & prepend(QChar ch)
void chop(int n)
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
QString::const_iterator cend() const const
int size() const const
QLatin1Char at(int pos) const const
bool isEmpty() const const
const T & at(int i) const const
bool isEmpty() const const
QString & replace(int position, int n, QChar after)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString toLower() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString::const_iterator cbegin() const const
const QChar at(int position) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString mid(int position, int n) const const
QString & append(QChar ch)
QChar fromLatin1(char c)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 04:07:59 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.