aboutsummaryrefslogtreecommitdiff
path: root/src/kconfig_compiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/kconfig_compiler')
-rw-r--r--src/kconfig_compiler/CMakeLists.txt9
-rw-r--r--src/kconfig_compiler/KCFGXmlParser.cpp564
-rw-r--r--src/kconfig_compiler/KCFGXmlParser.h82
-rw-r--r--src/kconfig_compiler/KConfigCodeGeneratorBase.cpp276
-rw-r--r--src/kconfig_compiler/KConfigCodeGeneratorBase.h118
-rw-r--r--src/kconfig_compiler/KConfigCommonStructs.h195
-rw-r--r--src/kconfig_compiler/KConfigHeaderGenerator.cpp612
-rw-r--r--src/kconfig_compiler/KConfigHeaderGenerator.h78
-rw-r--r--src/kconfig_compiler/KConfigSourceGenerator.cpp657
-rw-r--r--src/kconfig_compiler/KConfigSourceGenerator.h86
-rw-r--r--src/kconfig_compiler/KConfigXTParameters.cpp100
-rw-r--r--src/kconfig_compiler/KConfigXTParameters.h81
-rw-r--r--src/kconfig_compiler/kconfig_compiler.cpp2208
13 files changed, 2977 insertions, 2089 deletions
diff --git a/src/kconfig_compiler/CMakeLists.txt b/src/kconfig_compiler/CMakeLists.txt
index dc0a08db..3543dfa2 100644
--- a/src/kconfig_compiler/CMakeLists.txt
+++ b/src/kconfig_compiler/CMakeLists.txt
@@ -1,6 +1,13 @@
-set(kconfig_compiler_SRCS kconfig_compiler.cpp)
+set(kconfig_compiler_SRCS
+ KConfigXTParameters.cpp
+ KConfigCodeGeneratorBase.cpp
+ KConfigHeaderGenerator.cpp
+ KConfigSourceGenerator.cpp
+ KCFGXmlParser.cpp
+ kconfig_compiler.cpp
+)
add_executable(kconfig_compiler ${kconfig_compiler_SRCS})
diff --git a/src/kconfig_compiler/KCFGXmlParser.cpp b/src/kconfig_compiler/KCFGXmlParser.cpp
new file mode 100644
index 00000000..214335c3
--- /dev/null
+++ b/src/kconfig_compiler/KCFGXmlParser.cpp
@@ -0,0 +1,564 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KCFGXmlParser.h"
+#include "KConfigXTParameters.h"
+
+#include <QDomAttr>
+#include <QDomElement>
+#include <QDomNode>
+#include <QFile>
+#include <QList>
+#include <QStringList>
+#include <QTextStream>
+
+namespace
+{
+QTextStream cout(stdout);
+QTextStream cerr(stderr);
+}
+
+//TODO: Move preprocessDefault to Header / CPP implementation.
+// it makes no sense for a parser to process those values and generate code.
+
+static void preProcessDefault(QString &defaultValue, const QString &name,
+ const QString &type,
+ const CfgEntry::Choices &choices,
+ QString &code, const KConfigXTParameters &cfg)
+{
+ if (type == QLatin1String("String") && !defaultValue.isEmpty()) {
+ defaultValue = literalString(defaultValue);
+
+ } else if (type == QLatin1String("Path") && !defaultValue.isEmpty()) {
+ defaultValue = literalString(defaultValue);
+ } else if (type == QLatin1String("Url") && !defaultValue.isEmpty()) {
+ // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did.
+ defaultValue = QLatin1String("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')');
+ } else if ((type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty()) {
+ QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append);
+ if (!code.isEmpty()) {
+ cpp << endl;
+ }
+
+ if (type == QLatin1String("UrlList")) {
+ cpp << " QList<QUrl> default" << name << ";" << endl;
+ } else {
+ cpp << " QStringList default" << name << ";" << endl;
+ }
+ const QStringList defaults = defaultValue.split(QLatin1Char(','));
+ QStringList::ConstIterator it;
+ for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) {
+ cpp << " default" << name << ".append( ";
+ if (type == QLatin1String("UrlList")) {
+ cpp << "QUrl::fromUserInput(";
+ }
+ cpp << "QString::fromUtf8( \"" << *it << "\" ) ";
+ if (type == QLatin1String("UrlList")) {
+ cpp << ") ";
+ }
+ cpp << ");" << endl;
+ }
+ defaultValue = QLatin1String("default") + name;
+
+ } else if (type == QLatin1String("Color") && !defaultValue.isEmpty()) {
+ const QRegularExpression colorRe(QRegularExpression::anchoredPattern(
+ QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?")));
+
+ if (colorRe.match(defaultValue).hasMatch()) {
+ defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )");
+ } else {
+ defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )");
+ }
+
+ } else if (type == QLatin1String("Enum")) {
+ QList<CfgEntry::Choice>::ConstIterator it;
+ for (it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it) {
+ if ((*it).name == defaultValue) {
+ if (cfg.globalEnums && choices.name().isEmpty()) {
+ defaultValue.prepend(choices.prefix);
+ } else {
+ defaultValue.prepend(enumTypeQualifier(name, choices) + choices.prefix);
+ }
+ break;
+ }
+ }
+
+ } else if (type == QLatin1String("IntList")) {
+ QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append);
+ if (!code.isEmpty()) {
+ cpp << endl;
+ }
+
+ cpp << " QList<int> default" << name << ";" << endl;
+ if (!defaultValue.isEmpty()) {
+ const QStringList defaults = defaultValue.split(QLatin1Char(','));
+ QStringList::ConstIterator it;
+ for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) {
+ cpp << " default" << name << ".append( " << *it << " );"
+ << endl;
+ }
+ }
+ defaultValue = QLatin1String("default") + name;
+ }
+}
+
+static QString dumpNode(const QDomNode &node)
+{
+ QString msg;
+ QTextStream s(&msg, QIODevice::WriteOnly);
+ node.save(s, 0);
+
+ msg = msg.simplified();
+ if (msg.length() > 40) {
+ return msg.left(37) + QLatin1String("...");
+ }
+ return msg;
+}
+
+void KCFGXmlParser::readParameterFromEntry(CfgEntry &readEntry, const QDomElement &e)
+{
+ readEntry.param = e.attribute(QStringLiteral("name"));
+ readEntry.paramType = e.attribute(QStringLiteral("type"));
+
+ if (readEntry.param.isEmpty()) {
+ cerr << "Parameter must have a name: " << dumpNode(e) << endl;
+ exit (1);
+ }
+
+ if (readEntry.paramType.isEmpty()) {
+ cerr << "Parameter must have a type: " << dumpNode(e) << endl;
+ exit(1);
+ }
+
+ if ((readEntry.paramType == QLatin1String("Int")) || (readEntry.paramType == QLatin1String("UInt"))) {
+ bool ok;
+ readEntry.paramMax = e.attribute(QStringLiteral("max")).toInt(&ok);
+ if (!ok) {
+ cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
+ exit(1);
+ }
+ } else if (readEntry.paramType == QLatin1String("Enum")) {
+ for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
+ if (e2.tagName() == QLatin1String("values")) {
+ for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
+ if (e3.tagName() == QLatin1String("value")) {
+ readEntry.paramValues.append(e3.text());
+ }
+ }
+ break;
+ }
+ }
+ if (readEntry.paramValues.isEmpty()) {
+ cerr << "No values specified for parameter '" << readEntry.param << "'." << endl;
+ exit(1);
+ }
+ readEntry.paramMax = readEntry.paramValues.count() - 1;
+ } else {
+ cerr << "Parameter '" << readEntry.param << "' has type " << readEntry.paramType
+ << " but must be of type int, uint or Enum." << endl;
+ exit(1);
+ }
+}
+
+bool KCFGXmlParser::hasDefaultCode(CfgEntry &readEntry, const QDomElement &element)
+{
+ for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
+ if (e.attribute(QStringLiteral("param")).isEmpty()) {
+ if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void KCFGXmlParser::readChoicesFromEntry(CfgEntry &readEntry, const QDomElement &e)
+{
+ QList<CfgEntry::Choice> chlist;
+ for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
+ if (e2.tagName() != QLatin1String("choice")) {
+ continue;
+ }
+ CfgEntry::Choice choice;
+ choice.name = e2.attribute(QStringLiteral("name"));
+ if (choice.name.isEmpty()) {
+ cerr << "Tag <choice> requires attribute 'name'." << endl;
+ }
+ for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
+ if (e3.tagName() == QLatin1String("label")) {
+ choice.label = e3.text();
+ choice.context = e3.attribute(QStringLiteral("context"));
+ }
+ if (e3.tagName() == QLatin1String("tooltip")) {
+ choice.toolTip = e3.text();
+ choice.context = e3.attribute(QStringLiteral("context"));
+ }
+ if (e3.tagName() == QLatin1String("whatsthis")) {
+ choice.whatsThis = e3.text();
+ choice.context = e3.attribute(QStringLiteral("context"));
+ }
+ }
+ chlist.append(choice);
+ }
+
+ QString name = e.attribute(QStringLiteral("name"));
+ QString prefix = e.attribute(QStringLiteral("prefix"));
+
+ readEntry.choices = CfgEntry::Choices(chlist, name, prefix);
+}
+
+void KCFGXmlParser::readGroupElements(CfgEntry &readEntry, const QDomElement &element)
+{
+ for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
+ QString tag = e.tagName();
+ if (tag == QLatin1String("label")) {
+ readEntry.label = e.text();
+ readEntry.labelContext = e.attribute(QStringLiteral("context"));
+ } else if (tag == QLatin1String("tooltip")) {
+ readEntry.toolTip = e.text();
+ readEntry.toolTipContext = e.attribute(QStringLiteral("context"));
+ } else if (tag == QLatin1String("whatsthis")) {
+ readEntry.whatsThis = e.text();
+ readEntry.whatsThisContext = e.attribute(QStringLiteral("context"));
+ } else if (tag == QLatin1String("min")) {
+ readEntry.min = e.text();
+ } else if (tag == QLatin1String("max")) {
+ readEntry.max = e.text();
+ } else if (tag == QLatin1String("code")) {
+ readEntry.code = e.text();
+ } else if (tag == QLatin1String("parameter")) {
+ readParameterFromEntry(readEntry, e);
+ } else if (tag == QLatin1String("default")) {
+ if (e.attribute(QStringLiteral("param")).isEmpty()) {
+ readEntry.defaultValue = e.text();
+ }
+ } else if (tag == QLatin1String("choices")) {
+ readChoicesFromEntry(readEntry, e);
+ } else if (tag == QLatin1String("emit")) {
+ Signal signal;
+ signal.name = e.attribute(QStringLiteral("signal"));
+ readEntry.signalList.append(signal);
+ }
+ }
+}
+
+void KCFGXmlParser::createChangedSignal(CfgEntry &readEntry)
+{
+ if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(readEntry.name))) {
+ Signal s;
+ s.name = changeSignalName(readEntry.name);
+ s.modify = true;
+ readEntry.signalList.append(s);
+ }
+}
+
+void KCFGXmlParser::validateNameAndKey(CfgEntry &readEntry, const QDomElement &element)
+{
+ bool nameIsEmpty = readEntry.name.isEmpty();
+ if (nameIsEmpty && readEntry.key.isEmpty()) {
+ cerr << "Entry must have a name or a key: " << dumpNode(element) << endl;
+ exit (1);
+ }
+
+ if (readEntry.key.isEmpty()) {
+ readEntry.key = readEntry.name;
+ }
+
+ if (nameIsEmpty) {
+ readEntry.name = readEntry.key;
+ readEntry.name.remove(QLatin1Char(' '));
+ } else if (readEntry.name.contains(QLatin1Char(' '))) {
+ cout << "Entry '" << readEntry.name << "' contains spaces! <name> elements can not contain spaces!" << endl;
+ readEntry.name.remove(QLatin1Char(' '));
+ }
+
+ if (readEntry.name.contains(QStringLiteral("$("))) {
+ if (readEntry.param.isEmpty()) {
+ cerr << "Name may not be parameterized: " << readEntry.name << endl;
+ exit (1);
+ }
+ } else {
+ if (!readEntry.param.isEmpty()) {
+ cerr << "Name must contain '$(" << readEntry.param << ")': " << readEntry.name << endl;
+ exit (1);
+ }
+ }
+}
+
+void KCFGXmlParser::readParamDefaultValues(CfgEntry &readEntry, const QDomElement &element)
+{
+ if (readEntry.param.isEmpty()) {
+ return;
+ }
+ // Adjust name
+ readEntry.paramName = readEntry.name;
+
+ readEntry.name.remove(QStringLiteral("$(") + readEntry.param + QLatin1Char(')'));
+ // Lookup defaults for indexed entries
+ for (int i = 0; i <= readEntry.paramMax; i++) {
+ readEntry.paramDefaultValues.append(QString());
+ }
+
+ for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
+ QString tag = e.tagName();
+ if (tag != QLatin1String("default")) {
+ continue;
+ }
+ QString index = e.attribute(QStringLiteral("param"));
+ if (index.isEmpty()) {
+ continue;
+ }
+
+ bool ok;
+ int i = index.toInt(&ok);
+ if (!ok) {
+ i = readEntry.paramValues.indexOf(index);
+ if (i == -1) {
+ cerr << "Index '" << index << "' for default value is unknown." << endl;
+ exit (1);
+ }
+ }
+
+ if ((i < 0) || (i > readEntry.paramMax)) {
+ cerr << "Index '" << i << "' for default value is out of range [0, " << readEntry.paramMax << "]." << endl;
+ exit (1);
+ }
+
+ QString tmpDefaultValue = e.text();
+
+ if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) {
+ preProcessDefault(tmpDefaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg);
+ }
+
+ readEntry.paramDefaultValues[i] = tmpDefaultValue;
+ }
+}
+
+CfgEntry *KCFGXmlParser::parseEntry(const QString &group, const QDomElement &element)
+{
+ CfgEntry readEntry;
+ readEntry.type = element.attribute(QStringLiteral("type"));
+ readEntry.name = element.attribute(QStringLiteral("name"));
+ readEntry.key = element.attribute(QStringLiteral("key"));
+ readEntry.hidden = element.attribute(QStringLiteral("hidden")) == QLatin1String("true");;
+ readEntry.group = group;
+
+ const bool nameIsEmpty = readEntry.name.isEmpty();
+
+ readGroupElements(readEntry, element);
+
+ createChangedSignal(readEntry);
+ validateNameAndKey(readEntry, element);
+
+ if (readEntry.label.isEmpty()) {
+ readEntry.label = readEntry.key;
+ }
+
+ if (readEntry.type.isEmpty()) {
+ readEntry.type = QStringLiteral("String"); // XXX : implicit type might be bad
+ }
+
+ readParamDefaultValues(readEntry, element);
+
+ if (!mValidNameRegexp.match(readEntry.name).hasMatch()) {
+ if (nameIsEmpty)
+ cerr << "The key '" << readEntry.key << "' can not be used as name for the entry because "
+ "it is not a valid name. You need to specify a valid name for this entry." << endl;
+ else {
+ cerr << "The name '" << readEntry.name << "' is not a valid name for an entry." << endl;
+ }
+ exit (1);
+ }
+
+ if (mAllNames.contains(readEntry.name)) {
+ if (nameIsEmpty)
+ cerr << "The key '" << readEntry.key << "' can not be used as name for the entry because "
+ "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
+ else {
+ cerr << "The name '" << readEntry.name << "' is not unique." << endl;
+ }
+ exit (1);
+ }
+
+ mAllNames.append(readEntry.name);
+
+ if (!hasDefaultCode(readEntry, element)) {
+ // TODO: Move all the options to CfgEntry.
+ preProcessDefault(readEntry.defaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg);
+ }
+
+ // TODO: Try to Just return the CfgEntry we populated instead of
+ // creating another one to fill the code.
+ CfgEntry *result = new CfgEntry();
+ result->group = readEntry.group;
+ result->type = readEntry.type;
+ result->key = readEntry.key;
+ result->name = readEntry.name;
+ result->labelContext = readEntry.labelContext;
+ result->label = readEntry.label;
+ result->toolTipContext = readEntry.toolTipContext;
+ result->toolTip = readEntry.toolTip;
+ result->whatsThisContext = readEntry.whatsThisContext;
+ result->whatsThis = readEntry.whatsThis;
+ result->code = readEntry.code;
+ result->defaultValue = readEntry.defaultValue;
+ result->choices = readEntry.choices;
+ result->signalList = readEntry.signalList;
+ result->hidden = readEntry.hidden;
+
+ if (!readEntry.param.isEmpty()) {
+ result->param = readEntry.param;
+ result->paramName = readEntry.paramName;
+ result->paramType = readEntry.paramType;
+ result->paramValues = readEntry.paramValues;
+ result->paramDefaultValues = readEntry.paramDefaultValues;
+ result->paramMax = readEntry.paramMax;
+ }
+ result->min = readEntry.min;
+ result->max = readEntry.max;
+
+ return result;
+}
+
+// TODO: Change the name of the config variable.
+KCFGXmlParser::KCFGXmlParser(const KConfigXTParameters &cfg, const QString& inputFileName)
+ : cfg(cfg), mInputFileName(inputFileName)
+{
+ mValidNameRegexp.setPattern(QRegularExpression::anchoredPattern(QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*")));
+}
+
+void KCFGXmlParser::start()
+{
+ QFile input(mInputFileName);
+ QDomDocument doc;
+ QString errorMsg;
+ int errorRow;
+ int errorCol;
+ if (!doc.setContent(&input, &errorMsg, &errorRow, &errorCol)) {
+ cerr << "Unable to load document." << endl;
+ cerr << "Parse error in " << mInputFileName << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
+ exit (1);
+ }
+
+ QDomElement cfgElement = doc.documentElement();
+ if (cfgElement.isNull()) {
+ cerr << "No document in kcfg file" << endl;
+ exit (1);
+ }
+
+ for (QDomElement element = cfgElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
+ QString tag = element.tagName();
+
+ if (tag == QLatin1String("include")) {
+ readIncludeTag(element);
+ } else if (tag == QLatin1String("kcfgfile")) {
+ readKcfgfileTag(element);
+ } else if (tag == QLatin1String("group")) {
+ readGroupTag(element);
+ } else if (tag == QLatin1String("signal")) {
+ readSignalTag(element);
+ }
+ }
+}
+
+ParseResult KCFGXmlParser::getParseResult() const
+{
+ return mParseResult;
+}
+
+void KCFGXmlParser::readIncludeTag(const QDomElement &e)
+{
+ QString includeFile = e.text();
+ if (!includeFile.isEmpty()) {
+ mParseResult.includes.append(includeFile);
+ }
+}
+
+void KCFGXmlParser::readGroupTag(const QDomElement &e)
+{
+ QString group = e.attribute(QStringLiteral("name"));
+ if (group.isEmpty()) {
+ cerr << "Group without name" << endl;
+ exit (1);
+ }
+
+ for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
+ if (e2.tagName() != QLatin1String("entry")) {
+ continue;
+ }
+ CfgEntry *entry = parseEntry(group, e2);
+ if (entry) {
+ mParseResult.entries.append(entry);
+ } else {
+ cerr << "Can not parse entry." << endl;
+ exit (1);
+ }
+ }
+}
+
+void KCFGXmlParser::readKcfgfileTag(const QDomElement &e)
+{
+ mParseResult.cfgFileName = e.attribute(QStringLiteral("name"));
+ mParseResult.cfgFileNameArg = e.attribute(QStringLiteral("arg")).toLower() == QLatin1String("true");
+ for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
+ if (e2.tagName() == QLatin1String("parameter")) {
+ Param p;
+ p.name = e2.attribute(QStringLiteral("name"));
+ p.type = e2.attribute(QStringLiteral("type"));
+ if (p.type.isEmpty()) {
+ p.type = QStringLiteral("String");
+ }
+ mParseResult.parameters.append(p);
+ }
+ }
+}
+
+void KCFGXmlParser::readSignalTag(const QDomElement &e)
+{
+ QString signalName = e.attribute(QStringLiteral("name"));
+ if (signalName.isEmpty()) {
+ cerr << "Signal without name." << endl;
+ exit (1);
+ }
+ Signal theSignal;
+ theSignal.name = signalName;
+
+ for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
+ if (e2.tagName() == QLatin1String("argument")) {
+ Param argument;
+ argument.type = e2.attribute(QStringLiteral("type"));
+ if (argument.type.isEmpty()) {
+ cerr << "Signal argument without type." << endl;
+ exit (1);
+ }
+ argument.name= e2.text();
+ theSignal.arguments.append(argument);
+ } else if (e2.tagName() == QLatin1String("label")) {
+ theSignal.label = e2.text();
+ }
+ }
+
+ mParseResult.signalList.append(theSignal);
+}
diff --git a/src/kconfig_compiler/KCFGXmlParser.h b/src/kconfig_compiler/KCFGXmlParser.h
new file mode 100644
index 00000000..8c85d878
--- /dev/null
+++ b/src/kconfig_compiler/KCFGXmlParser.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCFGXMLPARSER_H
+#define KCFGXMLPARSER_H
+
+#include <QDomDocument>
+#include <QString>
+#include <QRegularExpression>
+
+#include "KConfigCommonStructs.h"
+#include "KConfigXTParameters.h"
+
+/* This parses the contents of a Xml file into a ParseResult Structure,
+ * It also fails hard:
+ * If start() succeeds, you can use the result,
+ * if start() fails, the program aborts with an error message so there's
+ * no possibility of generating incorrect code information.
+ */
+class KCFGXmlParser {
+public:
+ KCFGXmlParser(const KConfigXTParameters &cfg, const QString& inputFileName);
+
+ // Start the parser and reads the contents of the inputFileName into the ParseResult Structure
+ void start();
+
+ // Get the result of the parse
+ ParseResult getParseResult() const;
+
+private:
+ // creates a `somethingChanged` signal for every property
+ void createChangedSignal(CfgEntry &readEntry);
+
+ void validateNameAndKey(CfgEntry &readEntry, const QDomElement &element);
+
+ // TODO: Use std::optional and CfgEntry (without heap allocation) for this function
+ // *or* fail hard if the parse fails.
+ CfgEntry *parseEntry(const QString &group, const QDomElement &element);
+
+ // Steps
+ void readIncludeTag(const QDomElement &element);
+ void readGroupTag(const QDomElement &element);
+ void readKcfgfileTag(const QDomElement &element);
+ void readSignalTag(const QDomElement &element);
+
+ // Those are the Entries in the Xml, that represent a parameter within the <group> </group> tag.
+ void readParameterFromEntry(CfgEntry &entry, const QDomElement &element);
+ bool hasDefaultCode(CfgEntry &entry, const QDomElement &element);
+ void readChoicesFromEntry(CfgEntry &entry, const QDomElement &element);
+ void readGroupElements(CfgEntry &entry, const QDomElement &element);
+ void readParamDefaultValues(CfgEntry &entry, const QDomElement &element);
+
+private:
+ ParseResult mParseResult;
+ KConfigXTParameters cfg;
+ QString mInputFileName;
+ QStringList mAllNames;
+ QRegularExpression mValidNameRegexp;
+};
+
+#endif
diff --git a/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp b/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp
new file mode 100644
index 00000000..024af19c
--- /dev/null
+++ b/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp
@@ -0,0 +1,276 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KConfigCodeGeneratorBase.h"
+#include "KConfigXTParameters.h"
+#include "KConfigCommonStructs.h"
+
+#include <QTextStream>
+#include <QLatin1Char>
+#include <QFileInfo>
+
+#include <ostream>
+#include <QDebug>
+
+using std::endl;
+
+namespace
+{
+QTextStream cout(stdout);
+QTextStream cerr(stderr);
+}
+
+KConfigCodeGeneratorBase::KConfigCodeGeneratorBase(
+ const QString& inputFile,
+ const QString& baseDir,
+ const QString& fileName,
+ const KConfigXTParameters &parameters,
+ ParseResult &parseResult)
+ : inputFile(inputFile), baseDir(baseDir), fileName(fileName), cfg(parameters), parseResult(parseResult)
+{
+ file.setFileName(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ cerr << "Can not open '" << fileName << "for writing." << endl;
+ exit(1);
+ }
+ stream.setDevice(&file);
+ stream.setCodec("utf-8");
+
+ if (cfg.staticAccessors) {
+ This = QStringLiteral("self()->");
+ } else {
+ Const = QStringLiteral(" const");
+ }
+}
+
+KConfigCodeGeneratorBase::~KConfigCodeGeneratorBase()
+{
+ save();
+}
+
+void KConfigCodeGeneratorBase::save()
+{
+ file.close();
+}
+
+void KConfigCodeGeneratorBase::indent()
+{
+ if (indentLevel >= 4) {
+ indentLevel += 2;
+ } else {
+ indentLevel += 4;
+ }
+}
+
+void KConfigCodeGeneratorBase::unindent()
+{
+ if (indentLevel > 4) {
+ indentLevel -= 2;
+ } else {
+ indentLevel -= 4;
+ }
+}
+
+QString KConfigCodeGeneratorBase::whitespace()
+{
+ QString spaces;
+ for (int i = 0; i < indentLevel; i++) {
+ spaces.append(QLatin1Char(' '));
+ }
+ return spaces;
+}
+
+void KConfigCodeGeneratorBase::startScope()
+{
+ stream << whitespace() << QLatin1Char('{');
+ stream << endl;
+ indent();
+}
+
+void KConfigCodeGeneratorBase::endScope(ScopeFinalizer finalizer)
+{
+ unindent();
+ stream << whitespace() << QLatin1Char('}');
+ if (finalizer == ScopeFinalizer::Semicolon) {
+ stream << ';';
+ }
+ stream << endl;
+}
+
+void KConfigCodeGeneratorBase::start()
+{
+ const QString fileName = QFileInfo(inputFile).fileName();
+ stream << "// This file is generated by kconfig_compiler_kf5 from " << fileName << ".kcfg" << "." << endl;
+ stream << "// All changes you do to this file will be lost." << endl;
+}
+
+void KConfigCodeGeneratorBase::addHeaders(const QStringList& headerList)
+{
+ for (auto include : qAsConst(headerList)) {
+ if (include.startsWith(QLatin1Char('"'))) {
+ stream << "#include " << include << endl;
+ } else {
+ stream << "#include <" << include << ">" << endl;
+ }
+ }
+}
+
+// adds as many 'namespace foo {' lines to p_out as
+// there are namespaces in p_ns
+void KConfigCodeGeneratorBase::beginNamespaces()
+{
+ if (!cfg.nameSpace.isEmpty()) {
+ for (const QString &ns : cfg.nameSpace.split(QStringLiteral("::"))) {
+ stream << "namespace " << ns << " {" << endl;
+ }
+ stream << endl;
+ }
+}
+
+// adds as many '}' lines to p_out as
+// there are namespaces in p_ns
+void KConfigCodeGeneratorBase::endNamespaces()
+{
+ if (!cfg.nameSpace.isEmpty()) {
+ stream << endl;
+ const int namespaceCount = cfg.nameSpace.count(QStringLiteral("::")) + 1;
+ for (int i = 0; i < namespaceCount; ++i) {
+ stream << "}" << endl;
+ }
+ }
+}
+
+// returns the member accesor implementation
+// which should go in the h file if inline
+// or the cpp file if not inline
+QString KConfigCodeGeneratorBase::memberAccessorBody(const CfgEntry *e, bool globalEnums) const
+{
+ QString result;
+ QTextStream out(&result, QIODevice::WriteOnly);
+ QString n = e->name;
+ QString t = e->type;
+ bool useEnumType = cfg.useEnumTypes && t == QLatin1String("Enum");
+
+ out << "return ";
+ if (useEnumType) {
+ out << "static_cast<" << enumType(e, globalEnums) << ">(";
+ }
+ out << This << varPath(n, cfg);
+ if (!e->param.isEmpty()) {
+ out << "[i]";
+ }
+ if (useEnumType) {
+ out << ")";
+ }
+ out << ";" << endl;
+
+ return result;
+}
+
+void KConfigCodeGeneratorBase::createIfSetLogic(const CfgEntry *e, const QString &varExpression)
+{
+ const QString n = e->name;
+ const QString t = e->type;
+ const bool hasBody = !e->signalList.empty() || cfg.generateProperties;
+
+ stream << whitespace() << "if (";
+ if (hasBody) {
+ stream << "v != " << varExpression << " && ";
+ }
+ stream << "!" << This << "isImmutable( QStringLiteral( \"";
+ if (!e->param.isEmpty()) {
+ QString paramName = e->paramName;
+
+ stream << paramName.replace(QStringLiteral("$(") + e->param + QStringLiteral(")"), QLatin1String("%1")) << "\" ).arg( ";
+ if (e->paramType == QLatin1String("Enum")) {
+ stream << "QLatin1String( ";
+
+ if (cfg.globalEnums) {
+ stream << enumName(e->param) << "ToString[i]";
+ } else {
+ stream << enumName(e->param) << "::enumToString[i]";
+ }
+
+ stream << " )";
+ } else {
+ stream << "i";
+ }
+ stream << " )";
+ } else {
+ stream << n << "\" )";
+ }
+ stream << " ))";
+}
+
+void KConfigCodeGeneratorBase::memberMutatorBody(const CfgEntry *e)
+{
+ QString n = e->name;
+ QString t = e->type;
+
+ // HACK: Don't open '{' manually, use startScope / endScope to automatically handle whitespace indentation.
+ if (!e->min.isEmpty()) {
+ if (e->min != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579)
+ stream << whitespace() << "if (v < " << e->min << ")" << endl;
+ stream << whitespace() << "{" << endl;
+ stream << whitespace(); addDebugMethod(stream, cfg, n);
+ stream << ": value \" << v << \" is less than the minimum value of " << e->min << "\";" << endl;
+ stream << whitespace() << " v = " << e->min << ";" << endl;
+ stream << whitespace() << "}" << endl;
+ }
+ }
+
+ if (!e->max.isEmpty()) {
+ stream << endl;
+ stream << whitespace() << "if (v > " << e->max << ")" << endl;
+ stream << whitespace() << "{" << endl;
+ stream << whitespace(); addDebugMethod(stream, cfg, n);
+ stream << ": value \" << v << \" is greater than the maximum value of " << e->max << "\";" << endl;
+ stream << whitespace() << " v = " << e->max << ";" << endl;
+ stream << whitespace() << "}" << endl << endl;
+ }
+
+ const QString varExpression = This + varPath(n, cfg) + (e->param.isEmpty() ? QString() : QStringLiteral("[i]"));
+
+ // TODO: Remove this `hasBody` logic, always use an '{' for the if.
+ const bool hasBody = !e->signalList.empty() || cfg.generateProperties;
+
+ // This call creates an `if (someTest ...) that's just to long to throw over the code.
+ createIfSetLogic(e, varExpression);
+ stream << (hasBody ? " {" : "") << endl;
+ stream << whitespace() << " " << varExpression << " = v;" << endl;
+
+ const auto listSignal = e->signalList;
+ for (const Signal &signal : qAsConst(listSignal)) {
+ if (signal.modify) {
+ stream << whitespace() << " Q_EMIT " << This << signal.name << "();" << endl;
+ } else {
+ stream << whitespace() << " " << This << varPath(QStringLiteral("settingsChanged"), cfg)
+ << " |= " << signalEnumName(signal.name) << ";" << endl;
+ }
+ }
+ if (hasBody) {
+ stream << whitespace() << "}" << endl;
+ }
+}
diff --git a/src/kconfig_compiler/KConfigCodeGeneratorBase.h b/src/kconfig_compiler/KConfigCodeGeneratorBase.h
new file mode 100644
index 00000000..fdf3b7e3
--- /dev/null
+++ b/src/kconfig_compiler/KConfigCodeGeneratorBase.h
@@ -0,0 +1,118 @@
+/*
+ This file is part of KDE.
+
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGCODEGENERATORBASE_H
+#define KCONFIGCODEGENERATORBASE_H
+
+#include <QString>
+#include <QTextStream>
+#include <QFile>
+#include <QVector>
+
+#include "KConfigXTParameters.h"
+
+class CfgEntry;
+struct ParseResult;
+
+/* This class manages the base of writing a C - Based code */
+class KConfigCodeGeneratorBase {
+public:
+ enum ScopeFinalizer {None, Semicolon};
+
+ KConfigCodeGeneratorBase(
+ const QString& inputFileName, // The kcfg file
+ const QString& baseDir, // where we should store the generated file
+ const QString& fileName, // the name of the generated file
+ const KConfigXTParameters &parameters, // parameters passed to the generator
+ ParseResult &parseResult // The pre processed configuration entries
+ );
+ virtual ~KConfigCodeGeneratorBase();
+
+ // iterates over the header list adding an #include directive.
+ void addHeaders(const QStringList& header);
+
+ // Create all the namespace indentation levels based on the parsed result and parameters */
+ void beginNamespaces();
+
+ // Closes all the namespaces adding lines with single '}'
+ void endNamespaces();
+
+ // Add the correct amount of whitespace in the code.
+ QString whitespace();
+
+ // start a block scope `{` and increase indentation level.
+ void endScope(ScopeFinalizer finalizer = None);
+
+ // end a block scope `}` and decrease indentation level.
+ void startScope();
+
+ // start writing to the output file
+ virtual void start();
+
+ // save the result on the disk
+ void save();
+
+ // Code Implementations
+ // Implements the `Get` methods for the CfgEntry
+ // TODO: write to the stream directly without returning a QString.
+ QString memberAccessorBody(const CfgEntry *e, bool globalEnums) const;
+
+ // Implements the `Set` methods for the CfgEntry
+ void memberMutatorBody(const CfgEntry *e);
+
+ // This is the code that creates the logic for the Setter / Mutator.
+ // It *just* creates the if test, no body. The reason is that just
+ // the if test was more than 20 lines of code and hard to understand
+ // what was happening in a bigger function.
+ void createIfSetLogic(const CfgEntry *e, const QString &varExpression);
+
+protected:
+ /* advance the number of spaces for the indentation level */
+ void indent();
+
+ /* reduce the number of spaces for the indentation level */
+ void unindent();
+
+ QString inputFile; // the base file name, input file is based on this.
+
+ QString baseDir; // Where we are going to save the file
+ QString fileName; // The file name
+
+ const KConfigXTParameters &cfg; // The parameters passed via the kcfgc file
+ ParseResult &parseResult; // the result of the parsed kcfg file
+ QTextStream stream; // the stream that operates in the file to write data.
+ QFile file; // The file handler.
+
+ // Special access to `this->` and `const` thru the code.
+ QString This;
+ QString Const;
+
+private:
+ int indentLevel = 0;
+};
+
+#endif
diff --git a/src/kconfig_compiler/KConfigCommonStructs.h b/src/kconfig_compiler/KConfigCommonStructs.h
new file mode 100644
index 00000000..c78c7b76
--- /dev/null
+++ b/src/kconfig_compiler/KConfigCommonStructs.h
@@ -0,0 +1,195 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGCOMMONSTRUCTS_H
+#define KCONFIGCOMMONSTRUCTS_H
+
+#include <QString>
+#include <QVector>
+#include <QList>
+
+#include "KConfigXTParameters.h"
+
+struct Param
+{
+ QString name;
+ QString type;
+};
+
+struct Signal
+{
+ QString name;
+ QString label;
+ QList<Param> arguments;
+ bool modify = false;
+};
+
+class CfgEntry
+{
+public:
+ struct Choice {
+ QString name;
+ QString context;
+ QString label;
+ QString toolTip;
+ QString whatsThis;
+ };
+ class Choices
+ {
+ public:
+ Choices() {}
+ Choices(const QList<Choice> &d, const QString &n, const QString &p)
+ : prefix(p), choices(d), mName(n)
+ {
+ int i = n.indexOf(QLatin1String("::"));
+ if (i >= 0) {
+ mExternalQual = n.left(i + 2);
+ }
+ }
+ QString prefix;
+ QList<Choice> choices;
+ const QString &name() const
+ {
+ return mName;
+ }
+ const QString &externalQualifier() const
+ {
+ return mExternalQual;
+ }
+ bool external() const
+ {
+ return !mExternalQual.isEmpty();
+ }
+ private:
+ QString mName;
+ QString mExternalQual;
+ };
+
+public:
+ QString group;
+ QString type;
+ QString key;
+ QString name;
+ QString labelContext;
+ QString label;
+ QString toolTipContext;
+ QString toolTip;
+ QString whatsThisContext;
+ QString whatsThis;
+ QString code;
+ QString defaultValue;
+ QString param;
+ QString paramName;
+ QString paramType;
+ Choices choices;
+ QList<Signal> signalList;
+ QStringList paramValues;
+ QStringList paramDefaultValues;
+ int paramMax;
+ bool hidden;
+ QString min;
+ QString max;
+};
+
+struct ParseResult {
+ QString cfgFileName;
+ bool cfgFileNameArg = false;
+ QList<Param> parameters;
+ QList<Signal> signalList;
+ QStringList includes;
+ QList<CfgEntry *> entries;
+ bool hasNonModifySignals = false;
+};
+
+// TODO: Move those methods
+QString enumName(const QString &n);
+QString enumName(const QString &n, const CfgEntry::Choices &c);
+QString param(const QString &t);
+QString cppType(const QString &t);
+QString itemType(const QString &type);
+QString changeSignalName(const QString &n);
+
+QString enumType(const CfgEntry *e, bool globalEnums);
+
+QString getDefaultFunction(const QString &n, const QString &className = QString());
+QString setFunction(const QString &n, const QString &className = QString());
+QString getFunction(const QString &n, const QString &className = QString());
+
+QString itemAccessorBody(const CfgEntry *e, const KConfigXTParameters &cfg);
+QString signalEnumName(const QString &signalName);
+
+bool isUnsigned(const QString &type);
+
+// returns the name of an member variable
+// use itemPath to know the full path
+// like using d-> in case of dpointer
+QString varName(const QString &n, const KConfigXTParameters &cfg);
+
+QString varPath(const QString &n, const KConfigXTParameters &cfg);
+
+// returns the name of an item variable
+// use itemPath to know the full path
+// like using d-> in case of dpointer
+QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg);
+
+QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg);
+
+QString filenameOnly(const QString &path);
+
+QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg);
+
+QString translatedString(
+ const KConfigXTParameters &cfg,
+ const QString &string,
+ const QString &context = QString(),
+ const QString &param = QString(),
+ const QString &paramValue = QString());
+
+// TODO: Sanitize those functions.
+QString newItem(
+ const CfgEntry* entry,
+ const QString &key,
+ const QString& defaultValue,
+ const KConfigXTParameters &cfg,
+ const QString &param = QString());
+
+QString userTextsFunctions(
+ const CfgEntry *e,
+ const KConfigXTParameters &cfg,
+ QString itemVarStr = QString(),
+ const QString &i = QString());
+
+QString paramString(const QString &s, const CfgEntry *e, int i);
+QString paramString(const QString &group, const QList<Param> &parameters);
+
+QString defaultValue(const QString &t);
+QString memberGetDefaultBody(const CfgEntry *e);
+QString literalString(const QString &s);
+QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c);
+
+void addQuotes(QString &s);
+void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n);
+
+#endif
diff --git a/src/kconfig_compiler/KConfigHeaderGenerator.cpp b/src/kconfig_compiler/KConfigHeaderGenerator.cpp
new file mode 100644
index 00000000..088f64e7
--- /dev/null
+++ b/src/kconfig_compiler/KConfigHeaderGenerator.cpp
@@ -0,0 +1,612 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KConfigHeaderGenerator.h"
+#include "KConfigCommonStructs.h"
+
+#include <QTextStream>
+#include <QDebug>
+
+namespace
+{
+QTextStream cout(stdout);
+QTextStream cerr(stderr);
+}
+
+KConfigHeaderGenerator::KConfigHeaderGenerator(
+ const QString& inputFile,
+ const QString& baseDir,
+ const KConfigXTParameters &cfg,
+ ParseResult &parseResult)
+ : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.headerExtension, cfg, parseResult)
+{
+}
+
+void KConfigHeaderGenerator::start()
+{
+ KConfigCodeGeneratorBase::start();
+ startHeaderGuards();
+ createHeaders();
+
+ beginNamespaces();
+
+ createForwardDeclarations();
+
+ doClassDefinition();
+
+ endNamespaces();
+ endHeaderGuards();
+}
+
+void KConfigHeaderGenerator::doClassDefinition()
+{
+ stream << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl;
+ startScope();
+
+ // Add Q_OBJECT macro if the config need signals.
+ if (!parseResult.signalList.isEmpty() || cfg.generateProperties) {
+ stream << " Q_OBJECT" << endl;
+ }
+ stream << " public:" << endl;
+ implementEnums();
+ createConstructor();
+ createDestructor();
+
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ const QString n = entry->name;
+ const QString t = entry->type;
+
+ const QString returnType = (cfg.useEnumTypes && t == QLatin1String("Enum"))
+ ? enumType(entry, cfg.globalEnums)
+ : cppType(t);
+
+ createSetters(entry);
+ createProperties(entry, returnType);
+ createGetters(entry, returnType);
+ createDefaultValueMember(entry);
+ createItemAcessors(entry, returnType);
+ }
+
+ createSignals();
+ stream << " protected:" << endl;
+ createSingleton();
+
+ // TODO: Move those to functions too.
+ if (parseResult.hasNonModifySignals) {
+ stream << whitespace() << "bool usrSave() override;" << endl;
+ }
+
+ // Member variables
+ if (!cfg.memberVariables.isEmpty() && cfg.memberVariables != QLatin1String("private") && cfg.memberVariables != QLatin1String("dpointer")) {
+ stream << " " << cfg.memberVariables << ":" << endl;
+ }
+
+ // Class Parameters
+ for (const auto &parameter : qAsConst(parseResult.parameters)) {
+ stream << whitespace() << "" << cppType(parameter.type) << " mParam" << parameter.name << ";" << endl;
+ }
+
+ createNonDPointerHelpers();
+ createDPointer();
+
+ if (cfg.customAddons) {
+ stream << whitespace() << "// Include custom additions" << endl;
+ stream << whitespace() << "#include \"" << cfg.baseName << "_addons." << cfg.headerExtension << '"' << endl;
+ }
+
+ endScope(ScopeFinalizer::Semicolon);
+}
+
+void KConfigHeaderGenerator::createHeaders()
+{
+ addHeaders(cfg.headerIncludes);
+ if (cfg.headerIncludes.size()) {
+ stream << endl;
+ }
+
+ if (!cfg.singleton && parseResult.parameters.isEmpty()) {
+ addHeaders({QStringLiteral("qglobal.h")});
+ }
+
+ if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) {
+ addHeaders({QStringLiteral("kcoreconfigskeleton.h")});
+ } else {
+ addHeaders({QStringLiteral("kconfigskeleton.h")});
+ }
+
+ addHeaders({QStringLiteral("QCoreApplication"), QStringLiteral("QDebug")});
+ stream << endl;
+
+ addHeaders(parseResult.includes);
+ if (parseResult.includes.size()) {
+ stream << endl;
+ }
+}
+
+void KConfigHeaderGenerator::startHeaderGuards()
+{
+ const bool hasNamespace = !cfg.nameSpace.isEmpty();
+ const QString namespaceName = QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_"))).toUpper();
+ const QString namespaceStr = hasNamespace ? namespaceName + QLatin1Char('_') : QStringLiteral("");
+ const QString defineName = namespaceStr + cfg.className.toUpper() + QStringLiteral("_H");
+
+ stream << "#ifndef " << defineName << endl;
+ stream << "#define " << defineName << endl;
+ stream << endl;
+}
+
+void KConfigHeaderGenerator::endHeaderGuards()
+{
+ stream << endl;
+ stream << "#endif";
+ stream << endl;
+ // HACK: Original files ended with two last newlines, add them.
+ stream << endl;
+}
+
+void KConfigHeaderGenerator::implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices)
+{
+ const QList<CfgEntry::Choice> chlist = choices.choices;
+
+ if (chlist.isEmpty()) {
+ return;
+ }
+
+ QStringList values;
+ for (const auto choice : qAsConst(chlist)) {
+ values.append(choices.prefix + choice.name);
+ }
+
+ if (choices.name().isEmpty()) {
+ if (cfg.globalEnums) {
+ stream << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
+ } else {
+ // Create an automatically named enum
+ stream << whitespace() << "class " << enumName(entry->name, entry->choices) << endl;
+ stream << whitespace() << "{" << endl;
+ stream << whitespace() << " public:" << endl;
+ stream << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl;
+ stream << whitespace() << "};" << endl;
+ }
+ } else if (!choices.external()) {
+ // Create a named enum
+ stream << whitespace() << "enum " << enumName(entry->name, entry->choices) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
+ }
+}
+
+void KConfigHeaderGenerator::implementValueEnums(const CfgEntry *entry, const QStringList &values)
+{
+ if (values.isEmpty()) {
+ return;
+ }
+
+ if (cfg.globalEnums) {
+ // ### FIXME!!
+ // make the following string table an index-based string search!
+ // ###
+ stream << whitespace() << "enum " << enumName(entry->param) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
+ stream << whitespace() << "static const char* const " << enumName(entry->param) << "ToString[];" << endl;
+ } else {
+ stream << whitespace() << "class " << enumName(entry->param) << endl;
+ stream << whitespace() << "{" << endl;
+ stream << whitespace() << " public:" << endl;
+ stream << whitespace() << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl;
+ stream << whitespace() << " static const char* const enumToString[];" << endl;
+ stream << whitespace() << "};" << endl;
+ }
+}
+
+void KConfigHeaderGenerator::implementEnums()
+{
+ if (!parseResult.entries.size()) {
+ return;
+ }
+
+ for (const auto entry : qAsConst(parseResult.entries)) {
+ const CfgEntry::Choices &choices = entry->choices;
+ const QStringList values = entry->paramValues;
+
+ implementChoiceEnums(entry, choices);
+ implementValueEnums(entry, values);
+ }
+ stream << endl;
+}
+
+void KConfigHeaderGenerator::createSignals()
+{
+ // Signal definition.
+ const bool hasSignals = !parseResult.signalList.isEmpty();
+
+ unsigned val = 1 << parseResult.signalList.size();
+ if (!val) {
+ cerr << "Too many signals to create unique bit masks" << endl;
+ exit(1);
+ }
+
+ if (!hasSignals) {
+ return;
+ }
+
+ stream << "\n enum {" << endl;
+ val = 1;
+
+ // HACK: Use C-Style for add a comma in all but the last element,
+ // just to make the source generated code equal to the old one.
+ // When we are sure, revert this to a range-based-for and just add
+ // a last comma, as it's valid c++.
+ for (int i = 0, end = parseResult.signalList.size(); i < end; i++) {
+ auto signal = parseResult.signalList.at(i);
+ stream << whitespace() << " " << signalEnumName(signal.name) << " = 0x" << hex << val;
+ if (i != end-1) {
+ stream << "," << endl;
+ }
+
+ val <<= 1;
+ }
+ stream << endl;
+ stream << whitespace() << "};" << dec << endl << endl;
+
+ stream << " Q_SIGNALS:";
+ for (const Signal &signal : qAsConst(parseResult.signalList)) {
+ stream << endl;
+ if (!signal.label.isEmpty()) {
+ stream << whitespace() << "/**" << endl;
+ stream << whitespace() << " " << signal.label << endl;
+ stream << whitespace() << "*/" << endl;
+ }
+ stream << whitespace() << "void " << signal.name << "(";
+ QList<Param>::ConstIterator it, itEnd = signal.arguments.constEnd();
+ for (it = signal.arguments.constBegin(); it != itEnd;) {
+ Param argument = *it;
+ QString type = param(argument.type);
+ if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) {
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ if (entry->name == argument.name) {
+ type = enumType(entry, cfg.globalEnums);
+ break;
+ }
+ }
+ }
+ stream << type << " " << argument.name;
+ if (++it != itEnd) {
+ stream << ", ";
+ }
+ }
+ stream << ");" << endl;
+ }
+ stream << endl;
+
+ stream << " private:" << endl;
+ stream << whitespace() << "void itemChanged(quint64 flags);" << endl;
+ stream << endl;
+}
+
+void KConfigHeaderGenerator::createDPointer()
+{
+ if (!cfg.dpointer) {
+ return;
+ }
+
+ // use a private class for both member variables and items
+ stream << " private:" << endl;
+ for (const auto &entry : qAsConst(parseResult.entries)) {
+ if (cfg.allDefaultGetters || cfg.defaultGetters.contains(entry->name)) {
+ stream << whitespace() << "";
+ if (cfg.staticAccessors) {
+ stream << "static ";
+ }
+ stream << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << ";" << endl;
+ }
+ }
+ stream << whitespace() << "" << cfg.className << "Private *d;" << endl;
+}
+
+void KConfigHeaderGenerator::createConstructor()
+{
+ if (cfg.singleton) {
+ stream << whitespace() << "static " << cfg.className << " *self();" << endl;
+ if (parseResult.cfgFileNameArg) {
+ stream << whitespace() << "static void instance(const QString& cfgfilename);" << endl;
+ stream << whitespace() << "static void instance(KSharedConfig::Ptr config);" << endl;
+ }
+ return;
+ }
+
+ stream << whitespace() << "" << cfg.className << "(";
+ if (parseResult.cfgFileNameArg) {
+ if (cfg.forceStringFilename)
+ stream << " const QString &cfgfilename" << (parseResult.parameters.isEmpty() ? " = QString()" : ", ");
+ else
+ stream << " KSharedConfig::Ptr config" << (parseResult.parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", ");
+ }
+
+ bool first = true;
+ for (const auto parameter : qAsConst(parseResult.parameters)) {
+ if (first) {
+ first = false;
+ } else {
+ stream << ",";
+ }
+
+ stream << " " << param(parameter.type) << " " << parameter.name;
+ }
+
+ if (cfg.parentInConstructor) {
+ if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
+ stream << ",";
+ }
+ stream << " QObject *parent = nullptr";
+ }
+ stream << " );" << endl;
+}
+
+void KConfigHeaderGenerator::createDestructor()
+{
+ stream << whitespace() << "~" << cfg.className << "();" << endl << endl;
+}
+
+void KConfigHeaderGenerator::createForwardDeclarations()
+{
+ // Private class declaration
+ if (cfg.dpointer) {
+ stream << "class " << cfg.className << "Private;" << endl << endl;
+ }
+}
+
+void KConfigHeaderGenerator::createProperties(const CfgEntry *entry, const QString& returnType)
+{
+ if (!cfg.generateProperties) {
+ return;
+ }
+ stream << whitespace() << "Q_PROPERTY(" << returnType << ' ' << getFunction(entry->name);
+ stream << " READ " << getFunction(entry->name);
+
+ if (cfg.allMutators || cfg.mutators.contains(entry->name)) {
+ const QString signal = changeSignalName(entry->name);
+ stream << " WRITE " << setFunction(entry->name);
+ stream << " NOTIFY " << signal;
+
+ //If we have the modified signal, we'll also need
+ //the changed signal as well
+ Signal s;
+ s.name = signal;
+ s.modify = true;
+ parseResult.signalList.append(s);
+ } else {
+ stream << " CONSTANT";
+ }
+ stream << ")" << endl;
+}
+
+void KConfigHeaderGenerator::createSetters(const CfgEntry *entry)
+{
+ // Manipulator
+ if (!cfg.allMutators && !cfg.mutators.contains(entry->name)) {
+ return;
+ }
+
+ stream << whitespace() << "/**" << endl;
+ stream << whitespace() << " Set " << entry->label << endl;
+ stream << whitespace() << "*/" << endl;
+
+ if (cfg.staticAccessors) {
+ stream << whitespace() << "static" << endl;
+ }
+
+ stream << whitespace() << "void " << setFunction(entry->name) << "( ";
+ if (!entry->param.isEmpty()) {
+ stream <<cppType(entry->paramType) << " i, ";
+ }
+
+ stream << (cfg.useEnumTypes && entry->type == QLatin1String("Enum")
+ ? enumType(entry, cfg.globalEnums)
+ : param(entry->type));
+
+ stream << " v )";
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ if (!cfg.dpointer) {
+ stream << endl;
+ startScope();
+ memberMutatorBody(entry);
+ endScope();
+ stream << endl;
+ } else {
+ stream << ";" << endl << endl;
+ }
+}
+
+void KConfigHeaderGenerator::createGetters(const CfgEntry *entry, const QString& returnType)
+{
+ // Accessor
+ stream << whitespace() << "/**" << endl;
+ stream << whitespace() << " Get " << entry->label << endl;
+ stream << whitespace() << "*/" << endl;
+ if (cfg.staticAccessors) {
+ stream << whitespace() << "static" << endl;
+ }
+ stream << whitespace() << "";
+ stream << returnType;
+ stream << " " << getFunction(entry->name) << "(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const;
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ if (!cfg.dpointer) {
+ stream << endl;
+ startScope();
+ stream << whitespace() << memberAccessorBody(entry, cfg.globalEnums);
+ endScope();
+ stream << endl;
+ } else {
+ stream << ";" << endl << endl;
+ }
+}
+
+void KConfigHeaderGenerator::createItemAcessors(const CfgEntry *entry, const QString& returnType)
+{
+ // Item accessor
+ if (!cfg.itemAccessors) {
+ return;
+ }
+ stream << whitespace() << "/**" << endl;
+ stream << whitespace() << " Get Item object corresponding to " << entry->name << "()"
+ << endl;
+ stream << whitespace() << "*/" << endl;
+ stream << whitespace() << "Item" << itemType(entry->type) << " *"
+ << getFunction(entry->name) << "Item(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")";
+ if (!cfg.dpointer) {
+ stream << endl;
+ startScope();
+ stream << whitespace() << itemAccessorBody(entry, cfg);
+ endScope();
+ } else {
+ stream << ";" << endl;
+ }
+
+ stream <<endl;
+}
+
+void KConfigHeaderGenerator::createDefaultValueMember(const CfgEntry *entry)
+{
+ // Default value Accessor
+ if (! ((cfg.allDefaultGetters || cfg.defaultGetters.contains(entry->name)) && !entry->defaultValue.isEmpty())) {
+ return;
+ }
+ stream << whitespace() << "/**" << endl;
+ stream << whitespace() << " Get " << entry->label << " default value" << endl;
+ stream << whitespace() << "*/" << endl;
+ if (cfg.staticAccessors) {
+ stream << whitespace() << "static" << endl;
+ }
+ stream << whitespace() << "";
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << enumType(entry, cfg.globalEnums);
+ } else {
+ stream << cppType(entry->type);
+ }
+ stream << " " << getDefaultFunction(entry->name) << "(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << endl;
+ stream << whitespace() << "{" << endl;
+ stream << whitespace() << " return ";
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << "static_cast<" << enumType(entry, cfg.globalEnums) << ">(";
+ }
+ stream << getDefaultFunction(entry->name) << "_helper(";
+ if (!entry->param.isEmpty()) {
+ stream << " i ";
+ }
+ stream << ")";
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << ")";
+ }
+ stream << ";" << endl;
+ stream << whitespace() << "}" << endl;
+ stream << endl;
+}
+
+void KConfigHeaderGenerator::createSingleton()
+{
+ // Private constructor for singleton
+ if (!cfg.singleton) {
+ return;
+ }
+
+ stream << whitespace() << "" << cfg.className << "(";
+ if (parseResult.cfgFileNameArg) {
+ stream << "KSharedConfig::Ptr config";
+ }
+ if (cfg.parentInConstructor) {
+ if (parseResult.cfgFileNameArg) {
+ stream << ", ";
+ }
+ stream << "QObject *parent = nullptr";
+ }
+ stream << ");" << endl;
+ stream << whitespace() << "friend class " << cfg.className << "Helper;" << endl << endl;
+}
+
+void KConfigHeaderGenerator::createNonDPointerHelpers()
+{
+ if (cfg.memberVariables == QLatin1String("dpointer")) {
+ return;
+ }
+
+ QString group;
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ if (entry->group != group) {
+ group = entry->group;
+ stream << endl;
+ stream << whitespace() << "// " << group << endl;
+ }
+ stream << whitespace() << "" << cppType(entry->type) << " " << varName(entry->name, cfg);
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+
+ if (cfg.allDefaultGetters || cfg.defaultGetters.contains(entry->name)) {
+ stream << whitespace() << "";
+ if (cfg.staticAccessors) {
+ stream << "static ";
+ }
+ stream << cppType(entry->type) << " " << getDefaultFunction(entry->name) << "_helper(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << ";" << endl;
+ }
+ }
+
+ stream << endl << " private:" << endl;
+ if (cfg.itemAccessors) {
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ stream << whitespace() << "Item" << itemType(entry->type) << " *" << itemVar(entry, cfg);
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+ }
+ }
+
+ if (parseResult.hasNonModifySignals) {
+ stream << whitespace() << "uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl;
+ }
+}
diff --git a/src/kconfig_compiler/KConfigHeaderGenerator.h b/src/kconfig_compiler/KConfigHeaderGenerator.h
new file mode 100644
index 00000000..30f09ac4
--- /dev/null
+++ b/src/kconfig_compiler/KConfigHeaderGenerator.h
@@ -0,0 +1,78 @@
+/*
+ This file is part of KDE.
+
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGHEADERGENERATOR_H
+#define KCONFIGHEADERGENERATOR_H
+
+#include "KConfigCodeGeneratorBase.h"
+#include "KConfigCommonStructs.h"
+
+#include <QString>
+#include <QList>
+
+class KConfigXTParameters;
+class CfgEntry;
+class QTextStream;
+struct ParseResult;
+
+class KConfigHeaderGenerator : public KConfigCodeGeneratorBase {
+public:
+ KConfigHeaderGenerator(
+ const QString& inputFile,
+ const QString& baseDir,
+ const KConfigXTParameters &parameters,
+ ParseResult &parseResult);
+
+ void start() override;
+
+private:
+ void startHeaderGuards();
+ void endHeaderGuards();
+
+ void implementEnums();
+ void implementChoiceEnums(const CfgEntry *entry, const CfgEntry::Choices &choices);
+ void implementValueEnums(const CfgEntry *entry, const QStringList &values);
+
+ void doClassDefinition();
+ void createHeaders();
+ void createDPointer();
+ void createNonDPointerHelpers();
+
+ void createConstructor();
+ void createDestructor();
+ void createForwardDeclarations();
+ void createSingleton();
+ void createSignals();
+
+ void createSetters(const CfgEntry *entry);
+ void createItemAcessors(const CfgEntry *entry, const QString& returnType);
+ void createGetters(const CfgEntry *entry, const QString& returnType);
+ void createProperties(const CfgEntry *entry, const QString& returnType);
+ void createDefaultValueMember(const CfgEntry *entry);
+};
+
+#endif
diff --git a/src/kconfig_compiler/KConfigSourceGenerator.cpp b/src/kconfig_compiler/KConfigSourceGenerator.cpp
new file mode 100644
index 00000000..1949b420
--- /dev/null
+++ b/src/kconfig_compiler/KConfigSourceGenerator.cpp
@@ -0,0 +1,657 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KConfigSourceGenerator.h"
+#include "KConfigCommonStructs.h"
+
+
+KConfigSourceGenerator::KConfigSourceGenerator(
+ const QString& inputFile,
+ const QString& baseDir,
+ const KConfigXTParameters &cfg,
+ ParseResult &parseResult)
+ : KConfigCodeGeneratorBase(inputFile, baseDir, baseDir + cfg.baseName + QLatin1Char('.') + cfg.sourceExtension, cfg, parseResult)
+{
+}
+
+void KConfigSourceGenerator::start()
+{
+ KConfigCodeGeneratorBase::start();
+ stream << endl;
+ createHeaders();
+
+ if (!cfg.nameSpace.isEmpty()) {
+ stream << "using namespace " << cfg.nameSpace << ";";
+ stream << endl << endl;
+ }
+
+ createPrivateDPointerImplementation();
+ createSingletonImplementation();
+ createPreamble();
+ doConstructor();
+ doGetterSetterDPointerMode();
+ createDefaultValueGetterSetter();
+ createDestructor();
+ createNonModifyingSignalsHelper();
+ createSignalFlagsHandler();
+ includeMoc();
+}
+
+void KConfigSourceGenerator::createHeaders()
+{
+ QString headerName = cfg.baseName + QLatin1Char('.') + cfg.headerExtension;
+
+ // TODO: Make addQuotes return a string instead of replacing it inplace.
+ addQuotes(headerName);
+
+ addHeaders({ headerName });
+ stream << endl;
+
+ addHeaders(cfg.sourceIncludes);
+ if (cfg.setUserTexts && cfg.translationSystem == KConfigXTParameters::KdeTranslation) {
+ addHeaders({QStringLiteral("klocalizedstring.h")});
+ stream << endl;
+ }
+
+ // Header required by singleton implementation
+ if (cfg.singleton) {
+ addHeaders({QStringLiteral("qglobal.h"), QStringLiteral("QFile")});
+
+ // HACK: Add single line to fix test.
+ if (cfg.singleton && parseResult.cfgFileNameArg) {
+ stream << endl;
+ }
+ }
+
+ if (cfg.singleton && parseResult.cfgFileNameArg) {
+ addHeaders({QStringLiteral("QDebug")});
+ }
+
+ if (cfg.singleton) {
+ stream << endl;
+ }
+}
+
+void KConfigSourceGenerator::createPrivateDPointerImplementation()
+{
+ // private class implementation
+ if (!cfg.dpointer) {
+ return;
+ }
+
+ QString group;
+ beginNamespaces();
+ stream << "class " << cfg.className << "Private" << endl;
+ stream << "{" << endl;
+ stream << " public:" << endl;
+
+ // Create Members
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ if (entry->group != group) {
+ group = entry->group;
+ stream << endl;
+ stream << " // " << group << endl;
+ }
+ stream << " " << cppType(entry->type) << " " << varName(entry->name, cfg);
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+ }
+ stream << endl << " // items" << endl;
+
+ // Create Items.
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ const QString declType = entry->signalList.isEmpty()
+ ? QString(cfg.inherits + QStringLiteral("::Item") + itemType(entry->type))
+ : QStringLiteral("KConfigCompilerSignallingItem");
+
+ stream << " " << declType << " *" << itemVar( entry, cfg );
+ if (!entry->param.isEmpty()) {
+ stream << QStringLiteral("[%1]").arg(entry->paramMax + 1);
+ }
+ stream << ";" << endl;
+ }
+
+ if (parseResult.hasNonModifySignals) {
+ stream << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl;
+ }
+
+ stream << "};" << endl << endl;
+ endNamespaces();
+}
+
+void KConfigSourceGenerator::createSingletonImplementation()
+{
+ // Singleton implementation
+ if (!cfg.singleton) {
+ return;
+ }
+
+ beginNamespaces();
+ stream << "class " << cfg.className << "Helper" << endl;
+ stream << '{' << endl;
+ stream << " public:" << endl;
+ stream << " " << cfg.className << "Helper() : q(nullptr) {}" << endl;
+ stream << " ~" << cfg.className << "Helper() { delete q; }" << endl;
+ stream << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl;
+ stream << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl;
+ stream << " " << cfg.className << " *q;" << endl;
+ stream << "};" << endl;
+ endNamespaces();
+
+ stream << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl;
+
+ stream << cfg.className << " *" << cfg.className << "::self()" << endl;
+ stream << "{" << endl;
+ if (parseResult.cfgFileNameArg) {
+ stream << " if (!s_global" << cfg.className << "()->q)" << endl;
+ stream << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl;
+ } else {
+ stream << " if (!s_global" << cfg.className << "()->q) {" << endl;
+ stream << " new " << cfg.className << ';' << endl;
+ stream << " s_global" << cfg.className << "()->q->read();" << endl;
+ stream << " }" << endl << endl;
+ }
+ stream << " return s_global" << cfg.className << "()->q;" << endl;
+ stream << "}" << endl << endl;
+
+ if (parseResult.cfgFileNameArg) {
+ auto instance = [this] (const QString &type, const QString &arg, bool isString) {
+ stream << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl;
+ stream << "{" << endl;
+ stream << " if (s_global" << cfg.className << "()->q) {" << endl;
+ stream << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl;
+ stream << " return;" << endl;
+ stream << " }" << endl;
+ stream << " new " << cfg.className << "(";
+ if (isString) {
+ stream << "KSharedConfig::openConfig(" << arg << ")";
+ } else {
+ stream << "std::move(" << arg << ")";
+ }
+ stream << ");" << endl;
+ stream << " s_global" << cfg.className << "()->q->read();" << endl;
+ stream << "}" << endl << endl;
+ };
+ instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
+ instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
+ }
+}
+
+void KConfigSourceGenerator::createPreamble()
+{
+ QString cppPreamble;
+ for (const auto entry : qAsConst(parseResult.entries)) {
+ if (entry->paramValues.isEmpty()) {
+ continue;
+ }
+
+ cppPreamble += QStringLiteral("const char* const ") + cfg.className + QStringLiteral("::") + enumName(entry->param);
+ cppPreamble += cfg.globalEnums
+ ? QStringLiteral("ToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n")
+ : QStringLiteral("::enumToString[] = { \"") + entry->paramValues.join(QStringLiteral("\", \"")) + QStringLiteral("\" };\n");
+ }
+
+ if (!cppPreamble.isEmpty()) {
+ stream << cppPreamble << endl;
+ }
+}
+
+void KConfigSourceGenerator::createConstructorParameterList()
+{
+ if (parseResult.cfgFileNameArg) {
+ if (!cfg.forceStringFilename) {
+ stream << " KSharedConfig::Ptr config";
+ } else {
+ stream << " const QString& config";
+ }
+ stream << (parseResult.parameters.isEmpty() ? "" : ",");
+ }
+
+ for (QList<Param>::ConstIterator it = parseResult.parameters.constBegin();
+ it != parseResult.parameters.constEnd(); ++it) {
+ if (it != parseResult.parameters.constBegin()) {
+ stream << ",";
+ }
+ stream << " " << param((*it).type) << " " << (*it).name;
+ }
+
+ if (cfg.parentInConstructor) {
+ if (parseResult.cfgFileNameArg || !parseResult.parameters.isEmpty()) {
+ stream << ",";
+ }
+ stream << " QObject *parent";
+ }
+
+}
+
+void KConfigSourceGenerator::createParentConstructorCall()
+{
+ stream << cfg.inherits << "(";
+ if (!parseResult.cfgFileName.isEmpty()) {
+ stream << " QStringLiteral( \"" << parseResult.cfgFileName << "\" ";
+ }
+ if (parseResult.cfgFileNameArg) {
+ if (! cfg.forceStringFilename) {
+ stream << " std::move( config ) ";
+ } else {
+ stream << " config ";
+ }
+ }
+ if (!parseResult.cfgFileName.isEmpty()) {
+ stream << ") ";
+ }
+ stream << ")" << endl;
+}
+
+void KConfigSourceGenerator::createInitializerList()
+{
+ for (const auto &parameter : qAsConst(parseResult.parameters)) {
+ stream << " , mParam" << parameter.name << "(" << parameter.name << ")" << endl;
+ }
+
+ if (parseResult.hasNonModifySignals && !cfg.dpointer) {
+ stream << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl;
+ }
+}
+
+void KConfigSourceGenerator::createEnums(const CfgEntry *entry)
+{
+ if (entry->type != QLatin1String("Enum")) {
+ return;
+ }
+ stream << " QList<" << cfg.inherits << "::ItemEnum::Choice> values" << entry->name << ";" << endl;
+
+ for (const auto &choice : qAsConst(entry->choices.choices)) {
+ stream << " {" << endl;
+ stream << " " << cfg.inherits << "::ItemEnum::Choice choice;" << endl;
+ stream << " choice.name = QStringLiteral(\"" << choice.name << "\");" << endl;
+ if (cfg.setUserTexts) {
+ if (!choice.label.isEmpty()) {
+ stream << " choice.label = "
+ << translatedString(cfg, choice.label, choice.context)
+ << ";" << endl;
+ }
+ if (!choice.toolTip.isEmpty()) {
+ stream << " choice.toolTip = "
+ << translatedString(cfg, choice.toolTip, choice.context)
+ << ";" << endl;
+ }
+ if (!choice.whatsThis.isEmpty()) {
+ stream << " choice.whatsThis = "
+ << translatedString(cfg, choice.whatsThis, choice.context)
+ << ";" << endl;
+ }
+ }
+ stream << " values" << entry->name << ".append( choice );" << endl;
+ stream << " }" << endl;
+ }
+}
+
+void KConfigSourceGenerator::createNormalEntry(const CfgEntry *entry, const QString& key)
+{
+ stream << " " << itemPath(entry, cfg) << " = "
+ << newItem(entry, key, entry->defaultValue, cfg) << endl;
+
+ if (!entry->min.isEmpty()) {
+ stream << " " << itemPath(entry, cfg) << "->setMinValue(" << entry->min << ");" << endl;
+ }
+ if (!entry->max.isEmpty()) {
+ stream << " " << itemPath(entry, cfg) << "->setMaxValue(" << entry->max << ");" << endl;
+ }
+
+ if (cfg.setUserTexts) {
+ stream << userTextsFunctions(entry, cfg);
+ }
+
+ if (cfg.allNotifiers || cfg.notifiers.contains(entry->name)) {
+ stream << " " << itemPath(entry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl;
+ }
+
+ stream << " addItem( " << itemPath(entry, cfg);
+ QString quotedName = entry->name;
+ addQuotes(quotedName);
+ if (quotedName != key) {
+ stream << ", QStringLiteral( \"" << entry->name << "\" )";
+ }
+ stream << " );" << endl;
+}
+
+void KConfigSourceGenerator::createIndexedEntry(const CfgEntry *entry, const QString& key)
+{
+ for (int i = 0; i <= entry->paramMax; i++) {
+ QString itemVarStr(itemPath(entry, cfg) + QStringLiteral("[%1]").arg(i));
+
+ QString defaultStr = !entry->paramDefaultValues[i].isEmpty() ? entry->paramDefaultValues[i]
+ : !entry->defaultValue.isEmpty() ? paramString(entry->defaultValue, entry, i)
+ : defaultValue(entry->type);
+
+ stream << " " << itemVarStr << " = "
+ << newItem(entry, paramString(key, entry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl;
+
+ if (cfg.setUserTexts) {
+ stream << userTextsFunctions(entry, cfg, itemVarStr, entry->paramName);
+ }
+
+ // Make mutators for enum parameters work by adding them with $(..) replaced by the
+ // param name. The check for isImmutable in the set* functions doesn't have the param
+ // name available, just the corresponding enum value (int), so we need to store the
+ // param names in a separate static list!.
+ const bool isEnum = entry->paramType == QLatin1String("Enum");
+ const QString arg = isEnum ? entry->paramValues[i] : QString::number(i);
+
+ QString paramName = entry->paramName;
+
+ stream << " addItem( " << itemVarStr << ", QStringLiteral( \"";
+ stream << paramName.replace(QStringLiteral("$(") + entry->param + QLatin1Char(')'), QLatin1String("%1")).arg( arg );
+ stream << "\" ) );" << endl;
+ }
+}
+
+void KConfigSourceGenerator::handleCurrentGroupChange(const CfgEntry *entry)
+{
+ if (entry->group == mCurrentGroup) {
+ return;
+ }
+
+ // HACK: This fixes one spacing line in the diff. Remove this in the future and adapt the testcases.
+ static bool first = true;
+ if (!entry->group.isEmpty()) {
+ if (!first) {
+ stream << endl;
+ }
+ first = false;
+ }
+
+ mCurrentGroup = entry->group;
+ stream << " setCurrentGroup( " << paramString(mCurrentGroup, parseResult.parameters) << " );";
+ stream << endl << endl;
+}
+
+void KConfigSourceGenerator::doConstructor()
+{
+ // Constructor
+ stream << cfg.className << "::" << cfg.className << "(";
+ createConstructorParameterList();
+ stream << " )" << endl;
+ stream << " : ";
+ createParentConstructorCall();
+ createInitializerList();
+
+ stream << "{" << endl;
+
+ if (cfg.parentInConstructor) {
+ stream << " setParent(parent);" << endl;
+ }
+
+ if (cfg.dpointer) {
+ stream << " d = new " << cfg.className << "Private;" << endl;
+ if (parseResult.hasNonModifySignals) {
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
+ }
+ }
+
+ // Needed in case the singleton class is used as baseclass for
+ // another singleton.
+ if (cfg.singleton) {
+ stream << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl;
+ stream << " s_global" << cfg.className << "()->q = this;" << endl;
+ }
+
+ if (!parseResult.signalList.isEmpty()) {
+ // this cast to base-class pointer-to-member is valid C++
+ // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
+ stream << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
+ << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&"
+ << cfg.className << "::itemChanged);" << endl;
+
+ stream << endl;
+ }
+
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ handleCurrentGroupChange(entry);
+
+ const QString key = paramString(entry->key, parseResult.parameters);
+ if (!entry->code.isEmpty()) {
+ stream << entry->code << endl;
+ }
+ createEnums(entry);
+
+ if (!cfg.dpointer) {
+ stream << itemDeclaration(entry, cfg);
+ }
+
+ if (entry->param.isEmpty()) {
+ createNormalEntry(entry, key);
+ } else {
+ createIndexedEntry(entry, key);
+ }
+ }
+
+ stream << "}" << endl << endl;
+}
+
+void KConfigSourceGenerator::createGetterDPointerMode(const CfgEntry *entry)
+{
+ // Accessor
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << enumType(entry, cfg.globalEnums);
+ } else {
+ stream << cppType(entry->type);
+ }
+
+ stream << " " << getFunction(entry->name, cfg.className) << "(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << endl;
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ startScope();
+ // HACK: Fix memberAccessorBody
+ stream << " " << memberAccessorBody(entry, cfg.globalEnums);
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createSetterDPointerMode(const CfgEntry *entry)
+{
+ // Manipulator
+ if (!(cfg.allMutators || cfg.mutators.contains(entry->name))) {
+ return;
+ }
+
+ stream << "void " << setFunction(entry->name, cfg.className) << "( ";
+ if (!entry->param.isEmpty()) {
+ stream << cppType(entry->paramType) << " i, ";
+ }
+
+ if (cfg.useEnumTypes && entry->type == QLatin1String("Enum")) {
+ stream << enumType(entry, cfg.globalEnums);
+ } else {
+ stream << param(entry->type);
+ }
+ stream << " v )" << endl;
+
+ // function body inline only if not using dpointer
+ // for BC mode
+ startScope();
+ memberMutatorBody(entry);
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createItemGetterDPointerMode(const CfgEntry *entry)
+{
+ // Item accessor
+ if (!cfg.itemAccessors) {
+ return;
+ }
+ stream << endl;
+ stream << cfg.inherits << "::Item" << itemType(entry->type) << " *"
+ << getFunction(entry->name, cfg.className) << "Item(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << endl;
+ startScope();
+ stream << " " << itemAccessorBody(entry, cfg);
+ endScope();
+}
+
+void KConfigSourceGenerator::doGetterSetterDPointerMode()
+{
+ if (!cfg.dpointer) {
+ return;
+ }
+
+ // setters and getters go in Cpp if in dpointer mode
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ createSetterDPointerMode(entry);
+ createGetterDPointerMode(entry);
+ createItemGetterDPointerMode(entry);
+ stream << endl;
+ }
+}
+
+void KConfigSourceGenerator::createDefaultValueGetterSetter()
+{
+ // default value getters always go in Cpp
+ for (auto *entry : qAsConst(parseResult.entries)) {
+ QString n = entry->name;
+ QString t = entry->type;
+
+ // Default value Accessor, as "helper" function
+ if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !entry->defaultValue.isEmpty()) {
+ stream << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper(";
+ if (!entry->param.isEmpty()) {
+ stream << " " << cppType(entry->paramType) << " i ";
+ }
+ stream << ")" << Const << endl;
+ startScope();
+ stream << memberGetDefaultBody(entry) << endl;
+ endScope();
+ stream << endl;
+ }
+ }
+}
+
+void KConfigSourceGenerator::createDestructor()
+{
+ stream << cfg.className << "::~" << cfg.className << "()" << endl;
+ startScope();
+ if (cfg.dpointer) {
+ stream << " delete d;" << endl;
+ }
+ if (cfg.singleton) {
+ stream << " s_global" << cfg.className << "()->q = nullptr;" << endl;
+ }
+ endScope();
+ stream << endl;
+}
+
+void KConfigSourceGenerator::createNonModifyingSignalsHelper()
+{
+ if (!parseResult.hasNonModifySignals) {
+ return;
+ }
+ stream << "bool " << cfg.className << "::" << "usrSave()" << endl;
+ startScope();
+ stream << " const bool res = " << cfg.inherits << "::usrSave();" << endl;
+ stream << " if (!res) return false;" << endl << endl;
+ for (const Signal &signal : qAsConst(parseResult.signalList)) {
+ if (signal.modify) {
+ continue;
+ }
+
+ stream << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl;
+ stream << " Q_EMIT " << signal.name << "(";
+ QList<Param>::ConstIterator it, itEnd = signal.arguments.constEnd();
+ for (it = signal.arguments.constBegin(); it != itEnd;) {
+ Param argument = *it;
+ bool cast = false;
+ if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) {
+ for (int i = 0, end = parseResult.entries.count(); i < end; ++i) {
+ if (parseResult.entries.at(i)->name == argument.name) {
+ stream << "static_cast<" << enumType(parseResult.entries.at(i), cfg.globalEnums) << ">(";
+ cast = true;
+ break;
+ }
+ }
+ }
+ stream << varPath(argument.name, cfg);
+ if (cast) {
+ stream << ")";
+ }
+ if (++it != itEnd) {
+ stream << ", ";
+ }
+ }
+
+ stream << ");" << endl;
+ }
+
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
+ stream << " return true;" << endl;
+ endScope();
+}
+
+void KConfigSourceGenerator::createSignalFlagsHandler()
+{
+ if (parseResult.signalList.isEmpty()) {
+ return;
+ }
+
+ stream << endl;
+ stream << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl;
+ if (parseResult.hasNonModifySignals)
+ stream << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl;
+
+ if (!parseResult.signalList.isEmpty())
+ stream << endl;
+
+ for (const Signal &signal : qAsConst(parseResult.signalList)) {
+ if (signal.modify) {
+ stream << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl;
+ stream << " Q_EMIT " << signal.name << "();" << endl;
+ stream << " }" << endl;
+ }
+ }
+
+ stream << "}" << endl;
+}
+
+void KConfigSourceGenerator::includeMoc() {
+ const QString mocFileName = cfg.baseName + QStringLiteral(".moc");
+
+ if (parseResult.signalList.count() || cfg.generateProperties) {
+ // Add includemoc if they are signals defined.
+ stream << endl;
+ stream << "#include \"" << mocFileName << "\"" << endl;
+ stream << endl;
+ }
+}
diff --git a/src/kconfig_compiler/KConfigSourceGenerator.h b/src/kconfig_compiler/KConfigSourceGenerator.h
new file mode 100644
index 00000000..77409329
--- /dev/null
+++ b/src/kconfig_compiler/KConfigSourceGenerator.h
@@ -0,0 +1,86 @@
+/*
+ This file is part of KDE.
+
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGSOURCEGENERATOR_H
+#define KCONFIGSOURCEGENERATOR_H
+
+#include "KConfigCodeGeneratorBase.h"
+#include "KConfigCommonStructs.h"
+
+#include <QString>
+#include <QList>
+
+class KConfigXTParameters;
+class CfgEntry;
+class QTextStream;
+struct ParseResult;
+
+class KConfigSourceGenerator : public KConfigCodeGeneratorBase {
+public:
+ KConfigSourceGenerator(
+ const QString& inputFile,
+ const QString& baseDir,
+ const KConfigXTParameters &parameters,
+ ParseResult &parseResult);
+
+ void start() override;
+
+private:
+ // Those are fairly self contained functions.
+ void createHeaders();
+ void createPrivateDPointerImplementation();
+ void createSingletonImplementation();
+ void createPreamble();
+ void createDestructor();
+ void createConstructorParameterList();
+ void createParentConstructorCall();
+ void createInitializerList();
+ void createDefaultValueGetterSetter();
+ void createNonModifyingSignalsHelper();
+ void createSignalFlagsHandler();
+ void includeMoc();
+
+ // Constructor related methods
+ // the `do` methods have related helper functions that are only related
+ // to it. So we can break the function into many smaller ones and create
+ // logic inside of the `do` function.
+ void doConstructor();
+ void createEnums(const CfgEntry *entry);
+ void createNormalEntry(const CfgEntry *entry, const QString& key);
+ void createIndexedEntry(const CfgEntry *entry, const QString& key);
+ void handleCurrentGroupChange(const CfgEntry *entry);
+
+ void doGetterSetterDPointerMode();
+ void createGetterDPointerMode(const CfgEntry *entry);
+ void createSetterDPointerMode(const CfgEntry *entry);
+ void createItemGetterDPointerMode(const CfgEntry *entry);
+
+private:
+ QString mCurrentGroup;
+};
+
+#endif
diff --git a/src/kconfig_compiler/KConfigXTParameters.cpp b/src/kconfig_compiler/KConfigXTParameters.cpp
new file mode 100644
index 00000000..1d488e9e
--- /dev/null
+++ b/src/kconfig_compiler/KConfigXTParameters.cpp
@@ -0,0 +1,100 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KConfigXTParameters.h"
+
+// TODO: Remove this.
+#undef QT_NO_CAST_FROM_ASCII
+
+#include <QDebug>
+#include <QFileInfo>
+
+namespace
+{
+QTextStream cout(stdout);
+QTextStream cerr(stderr);
+}
+
+KConfigXTParameters::KConfigXTParameters(const QString &codegenFilename)
+{
+ if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) {
+ cerr << "Codegen options file must have extension .kcfgc" << endl;
+ exit(1);
+ }
+
+ baseName = QFileInfo(codegenFilename).fileName();
+ baseName = baseName.left(baseName.length() - 6);
+
+ // Configure the compiler with some settings
+ QSettings codegenConfig(codegenFilename, QSettings::IniFormat);
+
+ nameSpace = codegenConfig.value(QStringLiteral("NameSpace")).toString();
+ className = codegenConfig.value(QStringLiteral("ClassName")).toString();
+ if (className.isEmpty()) {
+ cerr << "Class name missing" << endl;
+ exit(1);
+ }
+ inherits = codegenConfig.value(QStringLiteral("Inherits")).toString();
+ if (inherits.isEmpty()) {
+ inherits = QStringLiteral("KConfigSkeleton");
+ }
+ visibility = codegenConfig.value(QStringLiteral("Visibility")).toString();
+ if (!visibility.isEmpty()) {
+ visibility += QLatin1Char(' ');
+ }
+ parentInConstructor = codegenConfig.value(QStringLiteral("ParentInConstructor"), false).toBool();
+ forceStringFilename = codegenConfig.value(QStringLiteral("ForceStringFilename"), false).toBool();
+ singleton = codegenConfig.value(QStringLiteral("Singleton"), false).toBool();
+ staticAccessors = singleton;
+ customAddons = codegenConfig.value(QStringLiteral("CustomAdditions"), false).toBool();
+ memberVariables = codegenConfig.value(QStringLiteral("MemberVariables")).toString();
+ dpointer = (memberVariables == QLatin1String("dpointer"));
+ headerIncludes = codegenConfig.value(QStringLiteral("IncludeFiles"), QStringList()).toStringList();
+ sourceIncludes = codegenConfig.value(QStringLiteral("SourceIncludeFiles"), QStringList()).toStringList();
+ mutators = codegenConfig.value(QStringLiteral("Mutators"), QStringList()).toStringList();
+ allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == QLatin1String("true")));
+ itemAccessors = codegenConfig.value(QStringLiteral("ItemAccessors"), false).toBool();
+ setUserTexts = codegenConfig.value(QStringLiteral("SetUserTexts"), false).toBool();
+ defaultGetters = codegenConfig.value(QStringLiteral("DefaultValueGetters"), QStringList()).toStringList();
+ allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == QLatin1String("true"));
+ notifiers = codegenConfig.value(QStringLiteral("Notifiers"), QStringList()).toStringList();
+ allNotifiers = ((notifiers.count() == 1) && (notifiers.at(0).toLower() == QLatin1String("true")));
+ globalEnums = codegenConfig.value(QStringLiteral("GlobalEnums"), false).toBool();
+ useEnumTypes = codegenConfig.value(QStringLiteral("UseEnumTypes"), false).toBool();
+ const QString trString = codegenConfig.value(QStringLiteral("TranslationSystem")).toString().toLower();
+ generateProperties = codegenConfig.value(QStringLiteral("GenerateProperties"), false).toBool();
+ if (trString == QLatin1String("kde")) {
+ translationSystem = KdeTranslation;
+ translationDomain = codegenConfig.value(QStringLiteral("TranslationDomain")).toString();
+ } else {
+ if (!trString.isEmpty() && trString != QLatin1String("qt")) {
+ cerr << "Unknown translation system, falling back to Qt tr()" << endl;
+ }
+ translationSystem = QtTranslation;
+ }
+ qCategoryLoggingName = codegenConfig.value(QStringLiteral("CategoryLoggingName"), QString()).toString();
+ headerExtension = codegenConfig.value(QStringLiteral("HeaderExtension"), QStringLiteral("h")).toString();
+ sourceExtension = codegenConfig.value(QStringLiteral("SourceExtension"), QStringLiteral("cpp")).toString();
+}
diff --git a/src/kconfig_compiler/KConfigXTParameters.h b/src/kconfig_compiler/KConfigXTParameters.h
new file mode 100644
index 00000000..db2cbcb5
--- /dev/null
+++ b/src/kconfig_compiler/KConfigXTParameters.h
@@ -0,0 +1,81 @@
+/*
+ This file is part of KDE.
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+ Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
+ Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 2003 Zack Rusin <zack@kde.org>
+ Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2008 Allen Winter <winter@kde.org>
+ Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCOFIGXTPARAMETERS_H
+#define KCOFIGXTPARAMETERS_H
+
+#include <QSettings>
+#include <QString>
+#include <QStringList>
+
+/**
+ Configuration Compiler Configuration
+*/
+class KConfigXTParameters
+{
+public:
+ KConfigXTParameters(const QString &codegenFilename);
+
+public:
+ enum TranslationSystem {
+ QtTranslation,
+ KdeTranslation
+ };
+
+ // These are read from the .kcfgc configuration file
+ QString nameSpace; // The namespace for the class to be generated
+ QString className; // The class name to be generated
+ QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton)
+ QString visibility;
+ bool parentInConstructor; // The class has the optional parent parameter in its constructor
+ bool forceStringFilename;
+ bool singleton; // The class will be a singleton
+ bool staticAccessors; // provide or not static accessors
+ bool customAddons;
+ QString memberVariables;
+ QStringList headerIncludes;
+ QStringList sourceIncludes;
+ QStringList mutators;
+ QStringList defaultGetters;
+ QStringList notifiers;
+ QString qCategoryLoggingName;
+ QString headerExtension;
+ QString sourceExtension;
+ bool allMutators;
+ bool setUserTexts;
+ bool allDefaultGetters;
+ bool dpointer;
+ bool globalEnums;
+ bool useEnumTypes;
+ bool itemAccessors;
+ bool allNotifiers;
+ TranslationSystem translationSystem;
+ QString translationDomain;
+ bool generateProperties;
+ QString baseName;
+};
+
+#endif
diff --git a/src/kconfig_compiler/kconfig_compiler.cpp b/src/kconfig_compiler/kconfig_compiler.cpp
index 848595f2..00699c36 100644
--- a/src/kconfig_compiler/kconfig_compiler.cpp
+++ b/src/kconfig_compiler/kconfig_compiler.cpp
@@ -34,15 +34,19 @@
#include <QDomAttr>
#include <QRegularExpression>
#include <QStringList>
-
-#include <qcommandlineparser.h>
-#include <qcommandlineoption.h>
+#include <QCommandLineParser>
+#include <QCommandLineOption>
#include <ostream>
#include <iostream>
#include <stdlib.h>
#include "../../kconfig_version.h"
+#include "KConfigXTParameters.h"
+#include "KConfigCommonStructs.h"
+#include "KConfigHeaderGenerator.h"
+#include "KConfigSourceGenerator.h"
+#include "KCFGXmlParser.h"
namespace
{
@@ -50,444 +54,7 @@ QTextStream cout(stdout);
QTextStream cerr(stderr);
}
-QStringList allNames;
-QRegularExpression *validNameRegexp;
-QString This;
-QString Const;
-
-/**
- Configuration Compiler Configuration
-*/
-class CfgConfig
-{
-public:
- CfgConfig(const QString &codegenFilename)
- {
- // Configure the compiler with some settings
- QSettings codegenConfig(codegenFilename, QSettings::IniFormat);
-
- nameSpace = codegenConfig.value(QStringLiteral("NameSpace")).toString();
- className = codegenConfig.value(QStringLiteral("ClassName")).toString();
- if (className.isEmpty()) {
- cerr << "Class name missing" << endl;
- exit(1);
- }
- inherits = codegenConfig.value(QStringLiteral("Inherits")).toString();
- if (inherits.isEmpty()) {
- inherits = QStringLiteral("KConfigSkeleton");
- }
- visibility = codegenConfig.value(QStringLiteral("Visibility")).toString();
- if (!visibility.isEmpty()) {
- visibility += ' ';
- }
- parentInConstructor = codegenConfig.value(QStringLiteral("ParentInConstructor"), false).toBool();
- forceStringFilename = codegenConfig.value(QStringLiteral("ForceStringFilename"), false).toBool();
- singleton = codegenConfig.value(QStringLiteral("Singleton"), false).toBool();
- staticAccessors = singleton;
- customAddons = codegenConfig.value(QStringLiteral("CustomAdditions"), false).toBool();
- memberVariables = codegenConfig.value(QStringLiteral("MemberVariables")).toString();
- dpointer = (memberVariables == QLatin1String("dpointer"));
- headerIncludes = codegenConfig.value(QStringLiteral("IncludeFiles"), QStringList()).toStringList();
- sourceIncludes = codegenConfig.value(QStringLiteral("SourceIncludeFiles"), QStringList()).toStringList();
- mutators = codegenConfig.value(QStringLiteral("Mutators"), QStringList()).toStringList();
- allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == QLatin1String("true")));
- itemAccessors = codegenConfig.value(QStringLiteral("ItemAccessors"), false).toBool();
- setUserTexts = codegenConfig.value(QStringLiteral("SetUserTexts"), false).toBool();
- defaultGetters = codegenConfig.value(QStringLiteral("DefaultValueGetters"), QStringList()).toStringList();
- allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == QLatin1String("true"));
- notifiers = codegenConfig.value(QStringLiteral("Notifiers"), QStringList()).toStringList();
- allNotifiers = ((notifiers.count() == 1) && (notifiers.at(0).toLower() == QLatin1String("true")));
- globalEnums = codegenConfig.value(QStringLiteral("GlobalEnums"), false).toBool();
- useEnumTypes = codegenConfig.value(QStringLiteral("UseEnumTypes"), false).toBool();
- const QString trString = codegenConfig.value(QStringLiteral("TranslationSystem")).toString().toLower();
- generateProperties = codegenConfig.value(QStringLiteral("GenerateProperties"), false).toBool();
- if (trString == QLatin1String("kde")) {
- translationSystem = KdeTranslation;
- translationDomain = codegenConfig.value(QStringLiteral("TranslationDomain")).toString();
- } else {
- if (!trString.isEmpty() && trString != QLatin1String("qt")) {
- cerr << "Unknown translation system, falling back to Qt tr()" << endl;
- }
- translationSystem = QtTranslation;
- }
- qCategoryLoggingName = codegenConfig.value(QStringLiteral("CategoryLoggingName"), QString()).toString();
- headerExtension = codegenConfig.value(QStringLiteral("HeaderExtension"), QStringLiteral("h")).toString();
- sourceExtension = codegenConfig.value(QStringLiteral("SourceExtension"), QStringLiteral("cpp")).toString();
- }
-
-public:
- enum TranslationSystem {
- QtTranslation,
- KdeTranslation
- };
-
- // These are read from the .kcfgc configuration file
- QString nameSpace; // The namespace for the class to be generated
- QString className; // The class name to be generated
- QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton)
- QString visibility;
- bool parentInConstructor; // The class has the optional parent parameter in its constructor
- bool forceStringFilename;
- bool singleton; // The class will be a singleton
- bool staticAccessors; // provide or not static accessors
- bool customAddons;
- QString memberVariables;
- QStringList headerIncludes;
- QStringList sourceIncludes;
- QStringList mutators;
- QStringList defaultGetters;
- QStringList notifiers;
- QString qCategoryLoggingName;
- QString headerExtension;
- QString sourceExtension;
- bool allMutators;
- bool setUserTexts;
- bool allDefaultGetters;
- bool dpointer;
- bool globalEnums;
- bool useEnumTypes;
- bool itemAccessors;
- bool allNotifiers;
- TranslationSystem translationSystem;
- QString translationDomain;
- bool generateProperties;
-};
-
-struct SignalArguments {
- QString type;
- QString variableName;
-};
-
-class Signal
-{
-public:
- Signal() : modify(false) {}
-
- QString name;
- QString label;
- QList<SignalArguments> arguments;
- bool modify;
-};
-
-class CfgEntry
-{
-public:
- struct Choice {
- QString name;
- QString context;
- QString label;
- QString toolTip;
- QString whatsThis;
- };
- class Choices
- {
- public:
- Choices() {}
- Choices(const QList<Choice> &d, const QString &n, const QString &p)
- : prefix(p), choices(d), mName(n)
- {
- int i = n.indexOf(QLatin1String("::"));
- if (i >= 0) {
- mExternalQual = n.left(i + 2);
- }
- }
- QString prefix;
- QList<Choice> choices;
- const QString &name() const
- {
- return mName;
- }
- const QString &externalQualifier() const
- {
- return mExternalQual;
- }
- bool external() const
- {
- return !mExternalQual.isEmpty();
- }
- private:
- QString mName;
- QString mExternalQual;
- };
-
- CfgEntry(const QString &group, const QString &type, const QString &key,
- const QString &name, const QString &labelContext, const QString &label,
- const QString &toolTipContext, const QString &toolTip, const QString &whatsThisContext, const QString &whatsThis, const QString &code,
- const QString &defaultValue, const Choices &choices, const QList<Signal> &signalList,
- bool hidden)
- : mGroup(group), mType(type), mKey(key), mName(name),
- mLabelContext(labelContext), mLabel(label), mToolTipContext(toolTipContext), mToolTip(toolTip),
- mWhatsThisContext(whatsThisContext), mWhatsThis(whatsThis),
- mCode(code), mDefaultValue(defaultValue), mChoices(choices),
- mSignalList(signalList), mParamMax(0), mHidden(hidden)
- {
- }
-
- void setGroup(const QString &group)
- {
- mGroup = group;
- }
- QString group() const
- {
- return mGroup;
- }
-
- void setType(const QString &type)
- {
- mType = type;
- }
- QString type() const
- {
- return mType;
- }
-
- void setKey(const QString &key)
- {
- mKey = key;
- }
- QString key() const
- {
- return mKey;
- }
-
- void setName(const QString &name)
- {
- mName = name;
- }
- QString name() const
- {
- return mName;
- }
-
- void setLabelContext(const QString &labelContext)
- {
- mLabelContext = labelContext;
- }
- QString labelContext() const
- {
- return mLabelContext;
- }
-
- void setLabel(const QString &label)
- {
- mLabel = label;
- }
- QString label() const
- {
- return mLabel;
- }
-
- void setToolTipContext(const QString &toolTipContext)
- {
- mToolTipContext = toolTipContext;
- }
- QString toolTipContext() const
- {
- return mToolTipContext;
- }
-
- void setToolTip(const QString &toolTip)
- {
- mToolTip = toolTip;
- }
- QString toolTip() const
- {
- return mToolTip;
- }
-
- void setWhatsThisContext(const QString &whatsThisContext)
- {
- mWhatsThisContext = whatsThisContext;
- }
- QString whatsThisContext() const
- {
- return mWhatsThisContext;
- }
-
- void setWhatsThis(const QString &whatsThis)
- {
- mWhatsThis = whatsThis;
- }
- QString whatsThis() const
- {
- return mWhatsThis;
- }
-
- void setDefaultValue(const QString &d)
- {
- mDefaultValue = d;
- }
- QString defaultValue() const
- {
- return mDefaultValue;
- }
-
- void setCode(const QString &d)
- {
- mCode = d;
- }
- QString code() const
- {
- return mCode;
- }
-
- void setMinValue(const QString &d)
- {
- mMin = d;
- }
- QString minValue() const
- {
- return mMin;
- }
-
- void setMaxValue(const QString &d)
- {
- mMax = d;
- }
- QString maxValue() const
- {
- return mMax;
- }
-
- void setParam(const QString &d)
- {
- mParam = d;
- }
- QString param() const
- {
- return mParam;
- }
-
- void setParamName(const QString &d)
- {
- mParamName = d;
- }
- QString paramName() const
- {
- return mParamName;
- }
-
- void setParamType(const QString &d)
- {
- mParamType = d;
- }
- QString paramType() const
- {
- return mParamType;
- }
-
- void setChoices(const QList<Choice> &d, const QString &n, const QString &p)
- {
- mChoices = Choices(d, n, p);
- }
- Choices choices() const
- {
- return mChoices;
- }
-
- void setParamValues(const QStringList &d)
- {
- mParamValues = d;
- }
- QStringList paramValues() const
- {
- return mParamValues;
- }
-
- void setParamDefaultValues(const QStringList &d)
- {
- mParamDefaultValues = d;
- }
- QString paramDefaultValue(int i) const
- {
- return mParamDefaultValues[i];
- }
-
- void setParamMax(int d)
- {
- mParamMax = d;
- }
- int paramMax() const
- {
- return mParamMax;
- }
-
- void setSignalList(const QList<Signal> &value)
- {
- mSignalList = value;
- }
- QList<Signal> signalList() const
- {
- return mSignalList;
- }
-
- bool hidden() const
- {
- return mHidden;
- }
-
- void dump() const
- {
- cerr << "<entry>" << endl;
- cerr << " group: " << mGroup << endl;
- cerr << " type: " << mType << endl;
- cerr << " key: " << mKey << endl;
- cerr << " name: " << mName << endl;
- cerr << " label context: " << mLabelContext << endl;
- cerr << " label: " << mLabel << endl;
-// whatsthis
- cerr << " code: " << mCode << endl;
-// cerr << " values: " << mValues.join(":") << endl;
-
- if (!param().isEmpty()) {
- cerr << " param name: " << mParamName << endl;
- cerr << " param type: " << mParamType << endl;
- cerr << " paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl;
- }
- cerr << " default: " << mDefaultValue << endl;
- cerr << " hidden: " << mHidden << endl;
- cerr << " min: " << mMin << endl;
- cerr << " max: " << mMax << endl;
- cerr << "</entry>" << endl;
- }
-
-private:
- QString mGroup;
- QString mType;
- QString mKey;
- QString mName;
- QString mLabelContext;
- QString mLabel;
- QString mToolTipContext;
- QString mToolTip;
- QString mWhatsThisContext;
- QString mWhatsThis;
- QString mCode;
- QString mDefaultValue;
- QString mParam;
- QString mParamName;
- QString mParamType;
- Choices mChoices;
- QList<Signal> mSignalList;
- QStringList mParamValues;
- QStringList mParamDefaultValues;
- int mParamMax;
- bool mHidden;
- QString mMin;
- QString mMax;
-};
-
-class Param
-{
-public:
- QString name;
- QString type;
-};
-
-// returns the name of an member variable
-// use itemPath to know the full path
-// like using d-> in case of dpointer
-static QString varName(const QString &n, const CfgConfig &cfg)
+QString varName(const QString &n, const KConfigXTParameters &cfg)
{
QString result;
if (!cfg.dpointer) {
@@ -500,7 +67,7 @@ static QString varName(const QString &n, const CfgConfig &cfg)
return result;
}
-static QString varPath(const QString &n, const CfgConfig &cfg)
+QString varPath(const QString &n, const KConfigXTParameters &cfg)
{
QString result;
if (cfg.dpointer) {
@@ -511,14 +78,14 @@ static QString varPath(const QString &n, const CfgConfig &cfg)
return result;
}
-static QString enumName(const QString &n)
+QString enumName(const QString &n)
{
QString result = QLatin1String("Enum") + n;
result[4] = result[4].toUpper();
return result;
}
-static QString enumName(const QString &n, const CfgEntry::Choices &c)
+QString enumName(const QString &n, const CfgEntry::Choices &c)
{
QString result = c.name();
if (result.isEmpty()) {
@@ -528,11 +95,11 @@ static QString enumName(const QString &n, const CfgEntry::Choices &c)
return result;
}
-static QString enumType(const CfgEntry *e, bool globalEnums)
+QString enumType(const CfgEntry *e, bool globalEnums)
{
- QString result = e->choices().name();
+ QString result = e->choices.name();
if (result.isEmpty()) {
- result = QLatin1String("Enum") + e->name();
+ result = QLatin1String("Enum") + e->name;
if (!globalEnums) {
result += QLatin1String("::type");
}
@@ -541,7 +108,7 @@ static QString enumType(const CfgEntry *e, bool globalEnums)
return result;
}
-static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
+QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
{
QString result = c.name();
if (result.isEmpty()) {
@@ -555,7 +122,7 @@ static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)
return result;
}
-static QString setFunction(const QString &n, const QString &className = QString())
+QString setFunction(const QString &n, const QString &className)
{
QString result = QLatin1String("set") + n;
result[3] = result[3].toUpper();
@@ -566,12 +133,12 @@ static QString setFunction(const QString &n, const QString &className = QString(
return result;
}
-static QString changeSignalName(const QString &n)
+QString changeSignalName(const QString &n)
{
return n+QStringLiteral("Changed");
}
-static QString getDefaultFunction(const QString &n, const QString &className = QString())
+QString getDefaultFunction(const QString &n, const QString &className)
{
QString result = QLatin1String("default") + n + QLatin1String("Value");
result[7] = result[7].toUpper();
@@ -582,7 +149,7 @@ static QString getDefaultFunction(const QString &n, const QString &className = Q
return result;
}
-static QString getFunction(const QString &n, const QString &className = QString())
+QString getFunction(const QString &n, const QString &className)
{
QString result = n;
result[0] = result[0].toLower();
@@ -593,7 +160,7 @@ static QString getFunction(const QString &n, const QString &className = QString(
return result;
}
-static void addQuotes(QString &s)
+void addQuotes(QString &s)
{
if (!s.startsWith(QLatin1Char('"'))) {
s.prepend(QLatin1Char('"'));
@@ -613,7 +180,7 @@ static QString quoteString(const QString &s)
return QLatin1Char('\"') + r + QLatin1Char('\"');
}
-static QString literalString(const QString &s)
+QString literalString(const QString &s)
{
bool isAscii = true;
for (int i = s.length(); i--;)
@@ -628,20 +195,8 @@ static QString literalString(const QString &s)
}
}
-static QString dumpNode(const QDomNode &node)
-{
- QString msg;
- QTextStream s(&msg, QIODevice::WriteOnly);
- node.save(s, 0);
- msg = msg.simplified();
- if (msg.length() > 40) {
- return msg.left(37) + QLatin1String("...");
- }
- return msg;
-}
-
-static QString signalEnumName(const QString &signalName)
+QString signalEnumName(const QString &signalName)
{
QString result;
result = QLatin1String("signal") + signalName;
@@ -650,345 +205,8 @@ static QString signalEnumName(const QString &signalName)
return result;
}
-static void preProcessDefault(QString &defaultValue, const QString &name,
- const QString &type,
- const CfgEntry::Choices &choices,
- QString &code, const CfgConfig &cfg)
-{
- if (type == QLatin1String("String") && !defaultValue.isEmpty()) {
- defaultValue = literalString(defaultValue);
-
- } else if (type == QLatin1String("Path") && !defaultValue.isEmpty()) {
- defaultValue = literalString(defaultValue);
- } else if (type == QLatin1String("Url") && !defaultValue.isEmpty()) {
- // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did.
- defaultValue = QLatin1String("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')');
- } else if ((type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty()) {
- QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append);
- if (!code.isEmpty()) {
- cpp << endl;
- }
- if (type == QLatin1String("UrlList")) {
- cpp << " QList<QUrl> default" << name << ";" << endl;
- } else {
- cpp << " QStringList default" << name << ";" << endl;
- }
- const QStringList defaults = defaultValue.split(QLatin1Char(','));
- QStringList::ConstIterator it;
- for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) {
- cpp << " default" << name << ".append( ";
- if (type == QLatin1String("UrlList")) {
- cpp << "QUrl::fromUserInput(";
- }
- cpp << "QString::fromUtf8( \"" << *it << "\" ) ";
- if (type == QLatin1String("UrlList")) {
- cpp << ") ";
- }
- cpp << ");" << endl;
- }
- defaultValue = QLatin1String("default") + name;
-
- } else if (type == QLatin1String("Color") && !defaultValue.isEmpty()) {
- const QRegularExpression colorRe(QRegularExpression::anchoredPattern(
- QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?")));
-
- if (colorRe.match(defaultValue).hasMatch()) {
- defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )");
- } else {
- defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )");
- }
-
- } else if (type == QLatin1String("Enum")) {
- QList<CfgEntry::Choice>::ConstIterator it;
- for (it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it) {
- if ((*it).name == defaultValue) {
- if (cfg.globalEnums && choices.name().isEmpty()) {
- defaultValue.prepend(choices.prefix);
- } else {
- defaultValue.prepend(enumTypeQualifier(name, choices) + choices.prefix);
- }
- break;
- }
- }
-
- } else if (type == QLatin1String("IntList")) {
- QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append);
- if (!code.isEmpty()) {
- cpp << endl;
- }
-
- cpp << " QList<int> default" << name << ";" << endl;
- if (!defaultValue.isEmpty()) {
- const QStringList defaults = defaultValue.split(QLatin1Char(','));
- QStringList::ConstIterator it;
- for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) {
- cpp << " default" << name << ".append( " << *it << " );"
- << endl;
- }
- }
- defaultValue = QLatin1String("default") + name;
- }
-}
-
-CfgEntry *parseEntry(const QString &group, const QDomElement &element, const CfgConfig &cfg)
-{
- bool defaultCode = false;
- QString type = element.attribute(QStringLiteral("type"));
- QString name = element.attribute(QStringLiteral("name"));
- QString key = element.attribute(QStringLiteral("key"));
- QString hidden = element.attribute(QStringLiteral("hidden"));
- QString labelContext;
- QString label;
- QString toolTipContext;
- QString toolTip;
- QString whatsThisContext;
- QString whatsThis;
- QString defaultValue;
- QString code;
- QString param;
- QString paramName;
- QString paramType;
- CfgEntry::Choices choices;
- QList<Signal> signalList;
- QStringList paramValues;
- QStringList paramDefaultValues;
- QString minValue;
- QString maxValue;
- int paramMax = 0;
-
- for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
- QString tag = e.tagName();
- if (tag == QLatin1String("label")) {
- label = e.text();
- labelContext = e.attribute(QStringLiteral("context"));
- } else if (tag == QLatin1String("tooltip")) {
- toolTip = e.text();
- toolTipContext = e.attribute(QStringLiteral("context"));
- } else if (tag == QLatin1String("whatsthis")) {
- whatsThis = e.text();
- whatsThisContext = e.attribute(QStringLiteral("context"));
- } else if (tag == QLatin1String("min")) {
- minValue = e.text();
- } else if (tag == QLatin1String("max")) {
- maxValue = e.text();
- } else if (tag == QLatin1String("code")) {
- code = e.text();
- } else if (tag == QLatin1String("parameter")) {
- param = e.attribute(QStringLiteral("name"));
- paramType = e.attribute(QStringLiteral("type"));
- if (param.isEmpty()) {
- cerr << "Parameter must have a name: " << dumpNode(e) << endl;
- return nullptr;
- }
- if (paramType.isEmpty()) {
- cerr << "Parameter must have a type: " << dumpNode(e) << endl;
- return nullptr;
- }
- if ((paramType == QLatin1String("Int")) || (paramType == QLatin1String("UInt"))) {
- bool ok;
- paramMax = e.attribute(QStringLiteral("max")).toInt(&ok);
- if (!ok) {
- cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): "
- << dumpNode(e) << endl;
- return nullptr;
- }
- } else if (paramType == QLatin1String("Enum")) {
- for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
- if (e2.tagName() == QLatin1String("values")) {
- for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
- if (e3.tagName() == QLatin1String("value")) {
- paramValues.append(e3.text());
- }
- }
- break;
- }
- }
- if (paramValues.isEmpty()) {
- cerr << "No values specified for parameter '" << param
- << "'." << endl;
- return nullptr;
- }
- paramMax = paramValues.count() - 1;
- } else {
- cerr << "Parameter '" << param << "' has type " << paramType
- << " but must be of type int, uint or Enum." << endl;
- return nullptr;
- }
- } else if (tag == QLatin1String("default")) {
- if (e.attribute(QStringLiteral("param")).isEmpty()) {
- defaultValue = e.text();
- if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) {
- defaultCode = true;
- }
- }
- } else if (tag == QLatin1String("choices")) {
- QString name = e.attribute(QStringLiteral("name"));
- QString prefix = e.attribute(QStringLiteral("prefix"));
- QList<CfgEntry::Choice> chlist;
- for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
- if (e2.tagName() == QLatin1String("choice")) {
- CfgEntry::Choice choice;
- choice.name = e2.attribute(QStringLiteral("name"));
- if (choice.name.isEmpty()) {
- cerr << "Tag <choice> requires attribute 'name'." << endl;
- }
- for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) {
- if (e3.tagName() == QLatin1String("label")) {
- choice.label = e3.text();
- choice.context = e3.attribute(QStringLiteral("context"));
- }
- if (e3.tagName() == QLatin1String("tooltip")) {
- choice.toolTip = e3.text();
- choice.context = e3.attribute(QStringLiteral("context"));
- }
- if (e3.tagName() == QLatin1String("whatsthis")) {
- choice.whatsThis = e3.text();
- choice.context = e3.attribute(QStringLiteral("context"));
- }
- }
- chlist.append(choice);
- }
- }
- choices = CfgEntry::Choices(chlist, name, prefix);
- } else if (tag == QLatin1String("emit")) {
- Signal signal;
- signal.name = e.attribute(QStringLiteral("signal"));
- signalList.append(signal);
- }
- }
-
- if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(name))) {
- Signal s;
- s.name = changeSignalName(name);
- s.modify = true;
- signalList.append(s);
- }
-
- bool nameIsEmpty = name.isEmpty();
- if (nameIsEmpty && key.isEmpty()) {
- cerr << "Entry must have a name or a key: " << dumpNode(element) << endl;
- return nullptr;
- }
-
- if (key.isEmpty()) {
- key = name;
- }
-
- if (nameIsEmpty) {
- name = key;
- name.remove(' ');
- } else if (name.contains(' ')) {
- cout << "Entry '" << name << "' contains spaces! <name> elements can not contain spaces!" << endl;
- name.remove(' ');
- }
-
- if (name.contains(QStringLiteral("$("))) {
- if (param.isEmpty()) {
- cerr << "Name may not be parameterized: " << name << endl;
- return nullptr;
- }
- } else {
- if (!param.isEmpty()) {
- cerr << "Name must contain '$(" << param << ")': " << name << endl;
- return nullptr;
- }
- }
-
- if (label.isEmpty()) {
- label = key;
- }
-
- if (type.isEmpty()) {
- type = QStringLiteral("String"); // XXX : implicit type might be bad
- }
-
- if (!param.isEmpty()) {
- // Adjust name
- paramName = name;
- name.remove("$(" + param + ')');
- // Lookup defaults for indexed entries
- for (int i = 0; i <= paramMax; i++) {
- paramDefaultValues.append(QString());
- }
-
- for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
- QString tag = e.tagName();
- if (tag == QLatin1String("default")) {
- QString index = e.attribute(QStringLiteral("param"));
- if (index.isEmpty()) {
- continue;
- }
-
- bool ok;
- int i = index.toInt(&ok);
- if (!ok) {
- i = paramValues.indexOf(index);
- if (i == -1) {
- cerr << "Index '" << index << "' for default value is unknown." << endl;
- return nullptr;
- }
- }
-
- if ((i < 0) || (i > paramMax)) {
- cerr << "Index '" << i << "' for default value is out of range [0, " << paramMax << "]." << endl;
- return nullptr;
- }
-
- QString tmpDefaultValue = e.text();
-
- if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) {
- preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg);
- }
-
- paramDefaultValues[i] = tmpDefaultValue;
- }
- }
- }
-
- if (!validNameRegexp->match(name).hasMatch()) {
- if (nameIsEmpty)
- cerr << "The key '" << key << "' can not be used as name for the entry because "
- "it is not a valid name. You need to specify a valid name for this entry." << endl;
- else {
- cerr << "The name '" << name << "' is not a valid name for an entry." << endl;
- }
- return nullptr;
- }
-
- if (allNames.contains(name)) {
- if (nameIsEmpty)
- cerr << "The key '" << key << "' can not be used as name for the entry because "
- "it does not result in a unique name. You need to specify a unique name for this entry." << endl;
- else {
- cerr << "The name '" << name << "' is not unique." << endl;
- }
- return nullptr;
- }
- allNames.append(name);
-
- if (!defaultCode) {
- preProcessDefault(defaultValue, name, type, choices, code, cfg);
- }
-
- CfgEntry *result = new CfgEntry(group, type, key, name, labelContext, label, toolTipContext, toolTip, whatsThisContext, whatsThis,
- code, defaultValue, choices, signalList,
- hidden == QLatin1String("true"));
- if (!param.isEmpty()) {
- result->setParam(param);
- result->setParamName(paramName);
- result->setParamType(paramType);
- result->setParamValues(paramValues);
- result->setParamDefaultValues(paramDefaultValues);
- result->setParamMax(paramMax);
- }
- result->setMinValue(minValue);
- result->setMaxValue(maxValue);
-
- return result;
-}
-
-static bool isUnsigned(const QString &type)
+bool isUnsigned(const QString &type)
{
if (type == QLatin1String("UInt")) {
return true;
@@ -1168,47 +386,47 @@ QString itemType(const QString &type)
return t;
}
-static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg)
+QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg)
{
if (cfg.itemAccessors) {
return QString();
}
QString type;
- if (!e->signalList().isEmpty()) {
+ if (!e->signalList.isEmpty()) {
type = QStringLiteral("KConfigCompilerSignallingItem");
} else {
- type = cfg.inherits + "::Item" + itemType(e->type());
+ type = cfg.inherits + "::Item" + itemType(e->type);
}
- QString fCap = e->name();
+ QString fCap = e->name;
fCap[0] = fCap[0].toUpper();
return " " + type + " *item" + fCap +
- ( (!e->param().isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax()+1)) : QString()) + ";\n";
+ ( (!e->param.isEmpty())?(QStringLiteral("[%1]").arg(e->paramMax+1)) : QString()) + ";\n";
}
// returns the name of an item variable
// use itemPath to know the full path
// like using d-> in case of dpointer
-static QString itemVar(const CfgEntry *e, const CfgConfig &cfg)
+QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg)
{
QString result;
if (cfg.itemAccessors) {
if (!cfg.dpointer) {
- result = 'm' + e->name() + "Item";
+ result = 'm' + e->name + "Item";
result[1] = result[1].toUpper();
} else {
- result = e->name() + "Item";
+ result = e->name + "Item";
result[0] = result[0].toLower();
}
} else {
- result = "item" + e->name();
+ result = "item" + e->name;
result[4] = result[4].toUpper();
}
return result;
}
-static QString itemPath(const CfgEntry *e, const CfgConfig &cfg)
+QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg)
{
QString result;
if (cfg.dpointer) {
@@ -1220,18 +438,18 @@ static QString itemPath(const CfgEntry *e, const CfgConfig &cfg)
}
QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue,
- const CfgConfig &cfg, const QString &param = QString()) {
+ const KConfigXTParameters &cfg, const QString &param) {
- QList<Signal> sigs = entry->signalList();
+ QList<Signal> sigs = entry->signalList;
QString t;
if (!sigs.isEmpty()) {
t += QLatin1String("new KConfigCompilerSignallingItem(");
}
- t += "new "+ cfg.inherits + "::Item" + itemType(entry->type()) + "( currentGroup(), "
- + key + ", " + varPath( entry->name(), cfg ) + param;
+ t += "new "+ cfg.inherits + "::Item" + itemType(entry->type) + "( currentGroup(), "
+ + key + ", " + varPath( entry->name, cfg ) + param;
- if (entry->type() == QLatin1String("Enum")) {
- t += ", values" + entry->name();
+ if (entry->type == QLatin1String("Enum")) {
+ t += ", values" + entry->name;
}
if (!defaultValue.isEmpty()) {
t += QLatin1String(", ") + defaultValue;
@@ -1255,11 +473,11 @@ QString newItem(const CfgEntry* entry, const QString &key, const QString& defaul
QString paramString(const QString &s, const CfgEntry *e, int i)
{
QString result = s;
- QString needle = "$(" + e->param() + ')';
+ QString needle = "$(" + e->param + ')';
if (result.contains(needle)) {
QString tmp;
- if (e->paramType() == QLatin1String("Enum")) {
- tmp = e->paramValues().at(i);
+ if (e->paramType == QLatin1String("Enum")) {
+ tmp = e->paramValues.at(i);
} else {
tmp = QString::number(i);
}
@@ -1289,12 +507,12 @@ QString paramString(const QString &group, const QList<Param> &parameters)
return "QStringLiteral( \"" + paramString + "\" )" + arguments;
}
-QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString &param = QString(), const QString &paramValue = QString())
+QString translatedString(const KConfigXTParameters &cfg, const QString &string, const QString &context, const QString &param, const QString &paramValue)
{
QString result;
switch (cfg.translationSystem) {
- case CfgConfig::QtTranslation:
+ case KConfigXTParameters::QtTranslation:
if (!context.isEmpty()) {
result += "/*: " + context + " */ QCoreApplication::translate(\"";
} else {
@@ -1303,7 +521,7 @@ QString translatedString(const CfgConfig &cfg, const QString &string, const QStr
result += cfg.className + "\", ";
break;
- case CfgConfig::KdeTranslation:
+ case KConfigXTParameters::KdeTranslation:
if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) {
result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", ";
} else if (!cfg.translationDomain.isEmpty()) {
@@ -1330,62 +548,36 @@ QString translatedString(const CfgConfig &cfg, const QString &string, const QStr
}
/* int i is the value of the parameter */
-QString userTextsFunctions(CfgEntry *e, const CfgConfig &cfg, QString itemVarStr = QString(), const QString &i = QString())
+QString userTextsFunctions(const CfgEntry *e, const KConfigXTParameters &cfg, QString itemVarStr, const QString &i)
{
QString txt;
if (itemVarStr.isNull()) {
itemVarStr = itemPath(e, cfg);
}
- if (!e->label().isEmpty()) {
+ if (!e->label.isEmpty()) {
txt += " " + itemVarStr + "->setLabel( ";
- txt += translatedString(cfg, e->label(), e->labelContext(), e->param(), i);
+ txt += translatedString(cfg, e->label, e->labelContext, e->param, i);
txt += QLatin1String(" );\n");
}
- if (!e->toolTip().isEmpty()) {
+ if (!e->toolTip.isEmpty()) {
txt += " " + itemVarStr + "->setToolTip( ";
- txt += translatedString(cfg, e->toolTip(), e->toolTipContext(), e->param(), i);
+ txt += translatedString(cfg, e->toolTip, e->toolTipContext, e->param, i);
txt += QLatin1String(" );\n");
}
- if (!e->whatsThis().isEmpty()) {
+ if (!e->whatsThis.isEmpty()) {
txt += " " + itemVarStr + "->setWhatsThis( ";
- txt += translatedString(cfg, e->whatsThis(), e->whatsThisContext(), e->param(), i);
+ txt += translatedString(cfg, e->whatsThis, e->whatsThisContext, e->param, i);
txt += QLatin1String(" );\n");
}
return txt;
}
-// returns the member accesor implementation
-// which should go in the h file if inline
-// or the cpp file if not inline
-QString memberAccessorBody(CfgEntry *e, bool globalEnums, const CfgConfig &cfg)
-{
- QString result;
- QTextStream out(&result, QIODevice::WriteOnly);
- QString n = e->name();
- QString t = e->type();
- bool useEnumType = cfg.useEnumTypes && t == QLatin1String("Enum");
-
- out << "return ";
- if (useEnumType) {
- out << "static_cast<" << enumType(e, globalEnums) << ">(";
- }
- out << This << varPath(n, cfg);
- if (!e->param().isEmpty()) {
- out << "[i]";
- }
- if (useEnumType) {
- out << ")";
- }
- out << ";" << endl;
-
- return result;
-}
// returns the member mutator implementation
// which should go in the h file if inline
// or the cpp file if not inline
-
-void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n)
+//TODO: Fix add Debug Method, it should also take the debug string.
+void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n)
{
if (cfg.qCategoryLoggingName.isEmpty()) {
out << " qDebug() << \"" << setFunction(n);
@@ -1394,101 +586,30 @@ void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n)
}
}
-QString memberMutatorBody(CfgEntry *e, const CfgConfig &cfg)
-{
- QString result;
- QTextStream out(&result, QIODevice::WriteOnly);
- QString n = e->name();
- QString t = e->type();
-
- if (!e->minValue().isEmpty()) {
- if (e->minValue() != QLatin1String("0") || !isUnsigned(t)) { // skip writing "if uint<0" (#187579)
- out << "if (v < " << e->minValue() << ")" << endl;
- out << "{" << endl;
- addDebugMethod(out, cfg, n);
- out << ": value \" << v << \" is less than the minimum value of ";
- out << e->minValue() << "\";" << endl;
- out << " v = " << e->minValue() << ";" << endl;
- out << "}" << endl;
- }
- }
-
- if (!e->maxValue().isEmpty()) {
- out << endl << "if (v > " << e->maxValue() << ")" << endl;
- out << "{" << endl;
- addDebugMethod(out, cfg, n);
- out << ": value \" << v << \" is greater than the maximum value of ";
- out << e->maxValue() << "\";" << endl;
- out << " v = " << e->maxValue() << ";" << endl;
- out << "}" << endl << endl;
- }
-
- const QString varExpression = This + varPath(n, cfg) + (e->param().isEmpty() ? QString() : QStringLiteral("[i]"));
-
- const bool hasBody = !e->signalList().empty() || cfg.generateProperties;
- out << "if (";
- if (hasBody) {
- out << "v != " << varExpression << " && ";
- }
- out << "!" << This << "isImmutable( QStringLiteral( \"";
- if (!e->param().isEmpty()) {
- out << e->paramName().replace("$(" + e->param() + ")", QLatin1String("%1")) << "\" ).arg( ";
- if (e->paramType() == QLatin1String("Enum")) {
- out << "QLatin1String( ";
-
- if (cfg.globalEnums) {
- out << enumName(e->param()) << "ToString[i]";
- } else {
- out << enumName(e->param()) << "::enumToString[i]";
- }
-
- out << " )";
- } else {
- out << "i";
- }
- out << " )";
- } else {
- out << n << "\" )";
- }
- out << " ))" << (hasBody ? " {" : "") << endl;
- out << " " << varExpression << " = v;" << endl;
-
- const auto listSignal = e->signalList();
- for (const Signal &signal : listSignal) {
- if (signal.modify) {
- out << " Q_EMIT " << This << signal.name << "();" << endl;
- } else {
- out << " " << This << varPath(QStringLiteral("settingsChanged"), cfg) << " |= " << signalEnumName(signal.name) << ";" << endl;
- }
- }
- if (hasBody) {
- out << "}" << endl;
- }
-
- return result;
-}
// returns the member get default implementation
// which should go in the h file if inline
// or the cpp file if not inline
-QString memberGetDefaultBody(CfgEntry *e)
+QString memberGetDefaultBody(const CfgEntry *e)
{
- QString result = e->code();
+ QString result = e->code;
QTextStream out(&result, QIODevice::WriteOnly);
out << endl;
- if (!e->param().isEmpty()) {
+ if (!e->param.isEmpty()) {
out << " switch (i) {" << endl;
- for (int i = 0; i <= e->paramMax(); ++i) {
- if (!e->paramDefaultValue(i).isEmpty()) {
- out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl;
+ for (int i = 0; i <= e->paramMax; ++i) {
+ if (!e->paramDefaultValues[i].isEmpty()) {
+ out << " case " << i << ": return " << e->paramDefaultValues[i] << ';' << endl;
}
}
+ QString defaultValue = e->defaultValue;
+
out << " default:" << endl;
- out << " return " << e->defaultValue().replace("$(" + e->param() + ')', QLatin1String("i")) << ';' << endl;
+ out << " return " << defaultValue.replace("$(" + e->param + ')', QLatin1String("i")) << ';' << endl;
out << " }" << endl;
} else {
- out << " return " << e->defaultValue() << ';';
+ out << " return " << e->defaultValue << ';';
}
return result;
@@ -1497,13 +618,13 @@ QString memberGetDefaultBody(CfgEntry *e)
// returns the item accesor implementation
// which should go in the h file if inline
// or the cpp file if not inline
-QString itemAccessorBody(CfgEntry *e, const CfgConfig &cfg)
+QString itemAccessorBody(const CfgEntry *e, const KConfigXTParameters &cfg)
{
QString result;
QTextStream out(&result, QIODevice::WriteOnly);
out << "return " << itemPath(e, cfg);
- if (!e->param().isEmpty()) {
+ if (!e->param.isEmpty()) {
out << "[i]";
}
out << ";" << endl;
@@ -1529,30 +650,29 @@ QString indent(QString text, int spaces)
return result;
}
-// adds as many 'namespace foo {' lines to p_out as
-// there are namespaces in p_ns
-void beginNamespaces(const QString &p_ns, QTextStream &p_out)
+bool hasErrors(KCFGXmlParser &parser, const ParseResult& parseResult, const KConfigXTParameters &cfg)
{
- if (!p_ns.isEmpty()) {
- const QStringList nameSpaces = p_ns.split(QStringLiteral("::"));
- for (const QString &ns : nameSpaces) {
- p_out << "namespace " << ns << " {" << endl;
- }
- p_out << endl;
+ if (cfg.className.isEmpty()) {
+ cerr << "Class name missing" << endl;
+ return true;
}
-}
-// adds as many '}' lines to p_out as
-// there are namespaces in p_ns
-void endNamespaces(const QString &p_ns, QTextStream &p_out)
-{
- if (!p_ns.isEmpty()) {
- const int namespaceCount = p_ns.count(QStringLiteral("::")) + 1;
- for (int i = 0; i < namespaceCount; ++i) {
- p_out << "}" << endl;
- }
- p_out << endl;
+ if (cfg.singleton && !parseResult.parameters.isEmpty()) {
+ cerr << "Singleton class can not have parameters" << endl;
+ return true;
+ }
+
+ if (!parseResult.cfgFileName.isEmpty() && parseResult.cfgFileNameArg) {
+ cerr << "Having both a fixed filename and a filename as argument is not possible." << endl;
+ return true;
}
+
+ if (parseResult.entries.isEmpty()) {
+ cerr << "No entries." << endl;
+ return true;
+ }
+
+ return false;
}
int main(int argc, char **argv)
@@ -1561,22 +681,22 @@ int main(int argc, char **argv)
app.setApplicationName(QStringLiteral("kconfig_compiler"));
app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING));
- validNameRegexp = new QRegularExpression(QRegularExpression::anchoredPattern(
- QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*")));
-
QString inputFilename, codegenFilename;
+ QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") },
+ QCoreApplication::translate("main", "Directory to generate files in [.]"),
+ QCoreApplication::translate("main", "directory"), QStringLiteral("."));
+
+ QCommandLineOption licenseOption (
+ QStringList { QStringLiteral("l"), QStringLiteral("license") },
+ QCoreApplication::translate("main", "Display software license."));
+
QCommandLineParser parser;
parser.addPositionalArgument(QStringLiteral("file.kcfg"), QStringLiteral("Input kcfg XML file"));
parser.addPositionalArgument(QStringLiteral("file.kcfgc"), QStringLiteral("Code generation options file"));
- QCommandLineOption targetDirectoryOption(QStringList { QStringLiteral("d"), QStringLiteral("directory") },
- QCoreApplication::translate("main", "Directory to generate files in [.]"),
- QCoreApplication::translate("main", "directory"), QStringLiteral("."));
parser.addOption(targetDirectoryOption);
-
- QCommandLineOption licenseOption (QStringList { QStringLiteral("l"), QStringLiteral("license") }, QCoreApplication::translate("main", "Display software license."));
parser.addOption (licenseOption);
parser.addVersionOption();
@@ -1584,7 +704,7 @@ int main(int argc, char **argv)
parser.process(app);
if (parser.isSet(licenseOption)) {
- cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl;
+ cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl;
cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl;
cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl;
cout << "You may redistribute copies of this program" << endl;
@@ -1595,16 +715,18 @@ int main(int argc, char **argv)
const QStringList args = parser.positionalArguments();
if (args.count() < 2) {
- cerr << "Too few arguments." << endl;
- return 1;
+ cerr << "Too few arguments." << endl;
+ return 1;
}
+
if (args.count() > 2) {
- cerr << "Too many arguments." << endl;
- return 1;
+ cerr << "Too many arguments." << endl;
+ return 1;
}
inputFilename = args.at(0);
codegenFilename = args.at(1);
+ // TODO: Transform baseDir into a helper.
QString baseDir = parser.value(targetDirectoryOption);
#ifdef Q_OS_WIN
@@ -1614,1124 +736,34 @@ int main(int argc, char **argv)
#endif
baseDir.append("/");
- if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) {
- cerr << "Codegen options file must have extension .kcfgc" << endl;
- return 1;
- }
- QString baseName = QFileInfo(codegenFilename).fileName();
- baseName = baseName.left(baseName.length() - 6);
-
- CfgConfig cfg = CfgConfig(codegenFilename);
+ KConfigXTParameters cfg(codegenFilename);
- QFile input(inputFilename);
+ KCFGXmlParser xmlParser(cfg, inputFilename);
+
+ // The Xml Parser aborts in the case of an error, so if we get
+ // to parseResult, we have a working Xml file.
+ xmlParser.start();
- QDomDocument doc;
- QString errorMsg;
- int errorRow;
- int errorCol;
- if (!doc.setContent(&input, &errorMsg, &errorRow, &errorCol)) {
- cerr << "Unable to load document." << endl;
- cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
- return 1;
- }
+ ParseResult parseResult = xmlParser.getParseResult();
- QDomElement cfgElement = doc.documentElement();
-
- if (cfgElement.isNull()) {
- cerr << "No document in kcfg file" << endl;
+ if (hasErrors(xmlParser, parseResult, cfg)) {
return 1;
}
- QString cfgFileName;
- bool cfgFileNameArg = false;
- QList<Param> parameters;
- QList<Signal> signalList;
- QStringList includes;
-
- QList<CfgEntry *> entries;
-
- for (QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
- QString tag = e.tagName();
-
- if (tag == QLatin1String("include")) {
- QString includeFile = e.text();
- if (!includeFile.isEmpty()) {
- includes.append(includeFile);
- }
-
- } else if (tag == QLatin1String("kcfgfile")) {
- cfgFileName = e.attribute(QStringLiteral("name"));
- cfgFileNameArg = e.attribute(QStringLiteral("arg")).toLower() == QLatin1String("true");
- for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
- if (e2.tagName() == QLatin1String("parameter")) {
- Param p;
- p.name = e2.attribute(QStringLiteral("name"));
- p.type = e2.attribute(QStringLiteral("type"));
- if (p.type.isEmpty()) {
- p.type = QStringLiteral("String");
- }
- parameters.append(p);
- }
- }
-
- } else if (tag == QLatin1String("group")) {
- QString group = e.attribute(QStringLiteral("name"));
- if (group.isEmpty()) {
- cerr << "Group without name" << endl;
- return 1;
- }
- for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
- if (e2.tagName() != QLatin1String("entry")) {
- continue;
- }
- CfgEntry *entry = parseEntry(group, e2, cfg);
- if (entry) {
- entries.append(entry);
- } else {
- cerr << "Can not parse entry." << endl;
- return 1;
- }
- }
- } else if (tag == QLatin1String("signal")) {
- QString signalName = e.attribute(QStringLiteral("name"));
- if (signalName.isEmpty()) {
- cerr << "Signal without name." << endl;
- return 1;
- }
- Signal theSignal;
- theSignal.name = signalName;
-
- for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) {
- if (e2.tagName() == QLatin1String("argument")) {
- SignalArguments argument;
- argument.type = e2.attribute(QStringLiteral("type"));
- if (argument.type.isEmpty()) {
- cerr << "Signal argument without type." << endl;
- return 1;
- }
- argument.variableName = e2.text();
- theSignal.arguments.append(argument);
- } else if (e2.tagName() == QLatin1String("label")) {
- theSignal.label = e2.text();
- }
- }
- signalList.append(theSignal);
- }
- }
-
- if (cfg.className.isEmpty()) {
- cerr << "Class name missing" << endl;
- return 1;
+ // TODO: Move this to somewhere saner.
+ for (const auto &signal : qAsConst(parseResult.signalList)) {
+ parseResult.hasNonModifySignals |= !signal.modify;
}
- if (cfg.singleton && !parameters.isEmpty()) {
- cerr << "Singleton class can not have parameters" << endl;
- return 1;
- }
-
- if (!cfgFileName.isEmpty() && cfgFileNameArg) {
- cerr << "Having both a fixed filename and a filename as argument is not possible." << endl;
- return 1;
- }
-
- if (entries.isEmpty()) {
- cerr << "No entries." << endl;
- }
-
-#if 0
- CfgEntry *cfg;
- for (cfg = entries.first(); cfg; cfg = entries.next()) {
- cfg->dump();
- }
-#endif
-
- QString headerFileName = baseName + '.' + cfg.headerExtension;
- QString implementationFileName = baseName + '.' + cfg.sourceExtension;
- QString mocFileName = baseName + ".moc";
- QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values
-
- QFile header(baseDir + headerFileName);
- if (!header.open(QIODevice::WriteOnly)) {
- cerr << "Can not open '" << baseDir << headerFileName << "for writing." << endl;
- return 1;
- }
-
- QTextStream h(&header);
-
- h.setCodec("utf-8");
-
- h << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl;
- h << "// All changes you do to this file will be lost." << endl;
-
- h << "#ifndef " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String(""))
- << cfg.className.toUpper() << "_H" << endl;
- h << "#define " << (!cfg.nameSpace.isEmpty() ? QString(QString(cfg.nameSpace).replace(QLatin1String("::"), QLatin1String("_")).toUpper() + '_') : QLatin1String(""))
- << cfg.className.toUpper() << "_H" << endl << endl;
-
- // Includes
- QStringList::ConstIterator it;
- for (it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it) {
- if ((*it).startsWith('"')) {
- h << "#include " << *it << endl;
- } else {
- h << "#include <" << *it << ">" << endl;
- }
- }
-
- if (!cfg.headerIncludes.isEmpty()) {
- h << endl;
- }
-
- if (!cfg.singleton && parameters.isEmpty()) {
- h << "#include <qglobal.h>" << endl;
- }
-
- if (cfg.inherits == QLatin1String("KCoreConfigSkeleton")) {
- h << "#include <kcoreconfigskeleton.h>" << endl;
- } else {
- h << "#include <kconfigskeleton.h>" << endl;
- }
-
- h << "#include <QCoreApplication>" << endl;
- h << "#include <QDebug>" << endl << endl;
-
- // Includes
- for (it = includes.constBegin(); it != includes.constEnd(); ++it) {
- if ((*it).startsWith('"')) {
- h << "#include " << *it << endl;
- } else {
- h << "#include <" << *it << ">" << endl;
- }
- }
-
- beginNamespaces(cfg.nameSpace, h);
-
- // Private class declaration
- if (cfg.dpointer) {
- h << "class " << cfg.className << "Private;" << endl << endl;
- }
-
- // Class declaration header
- h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl;
-
- h << "{" << endl;
- // Add Q_OBJECT macro if the config need signals.
- if (!signalList.isEmpty() || cfg.generateProperties) {
- h << " Q_OBJECT" << endl;
- }
- h << " public:" << endl;
-
- // enums
- QList<CfgEntry *>::ConstIterator itEntry;
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- const CfgEntry::Choices &choices = (*itEntry)->choices();
- const QList<CfgEntry::Choice> chlist = choices.choices;
- if (!chlist.isEmpty()) {
- QStringList values;
- QList<CfgEntry::Choice>::ConstIterator itChoice;
- for (itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice) {
- values.append(choices.prefix + (*itChoice).name);
- }
- if (choices.name().isEmpty()) {
- if (cfg.globalEnums) {
- h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
- } else {
- // Create an automatically named enum
- h << " class " << enumName((*itEntry)->name(), (*itEntry)->choices()) << endl;
- h << " {" << endl;
- h << " public:" << endl;
- h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl;
- h << " };" << endl;
- }
- } else if (!choices.external()) {
- // Create a named enum
- h << " enum " << enumName((*itEntry)->name(), (*itEntry)->choices()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
- }
- }
- const QStringList values = (*itEntry)->paramValues();
- if (!values.isEmpty()) {
- if (cfg.globalEnums) {
- // ### FIXME!!
- // make the following string table an index-based string search!
- // ###
- h << " enum " << enumName((*itEntry)->param()) << " { " << values.join(QStringLiteral(", ")) << " };" << endl;
- h << " static const char* const " << enumName((*itEntry)->param()) << "ToString[];" << endl;
- cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) +
- "ToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n";
- } else {
- h << " class " << enumName((*itEntry)->param()) << endl;
- h << " {" << endl;
- h << " public:" << endl;
- h << " enum type { " << values.join(QStringLiteral(", ")) << ", COUNT };" << endl;
- h << " static const char* const enumToString[];" << endl;
- h << " };" << endl;
- cppPreamble += "const char* const " + cfg.className + "::" + enumName((*itEntry)->param()) +
- "::enumToString[] = { \"" + values.join(QStringLiteral("\", \"")) + "\" };\n";
- }
- }
- }
- h << endl;
-
-
- // Constructor or singleton accessor
- if (!cfg.singleton) {
- h << " " << cfg.className << "(";
- if (cfgFileNameArg) {
- if (cfg.forceStringFilename)
- h << " const QString &cfgfilename"
- << (parameters.isEmpty() ? " = QString()" : ", ");
- else
- h << " KSharedConfig::Ptr config"
- << (parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", ");
- }
- for (QList<Param>::ConstIterator it = parameters.constBegin();
- it != parameters.constEnd(); ++it) {
- if (it != parameters.constBegin()) {
- h << ",";
- }
- h << " " << param((*it).type) << " " << (*it).name;
- }
- if (cfg.parentInConstructor) {
- if (cfgFileNameArg || !parameters.isEmpty()) {
- h << ",";
- }
- h << " QObject *parent = nullptr";
- }
- h << " );" << endl;
- } else {
- h << " static " << cfg.className << " *self();" << endl;
- if (cfgFileNameArg) {
- h << " static void instance(const QString& cfgfilename);" << endl;
- h << " static void instance(KSharedConfig::Ptr config);" << endl;
- }
- }
-
- // Destructor
- h << " ~" << cfg.className << "();" << endl << endl;
-
- // global variables
- if (cfg.staticAccessors) {
- This = QStringLiteral("self()->");
- } else {
- Const = QStringLiteral(" const");
- }
-
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- QString n = (*itEntry)->name();
- QString t = (*itEntry)->type();
-
- // Manipulator
- if (cfg.allMutators || cfg.mutators.contains(n)) {
- h << " /**" << endl;
- h << " Set " << (*itEntry)->label() << endl;
- h << " */" << endl;
- if (cfg.staticAccessors) {
- h << " static" << endl;
- }
- h << " void " << setFunction(n) << "( ";
- if (!(*itEntry)->param().isEmpty()) {
- h << cppType((*itEntry)->paramType()) << " i, ";
- }
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- h << enumType(*itEntry, cfg.globalEnums);
- } else {
- h << param(t);
- }
- h << " v )";
- // function body inline only if not using dpointer
- // for BC mode
- if (!cfg.dpointer) {
- h << endl << " {" << endl;
- h << indent(memberMutatorBody(*itEntry, cfg), 6);
- h << " }" << endl;
- } else {
- h << ";" << endl;
- }
- }
- h << endl;
-
- QString returnType;
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- returnType = enumType(*itEntry, cfg.globalEnums);
- } else {
- returnType = cppType(t);
- }
-
- if (cfg.generateProperties) {
- h << " Q_PROPERTY(" << returnType << ' ' << getFunction(n);
- h << " READ " << getFunction(n);
- if (cfg.allMutators || cfg.mutators.contains(n)) {
- const QString signal = changeSignalName(n);
- h << " WRITE " << setFunction(n);
- h << " NOTIFY " << signal;
-
- //If we have the modified signal, we'll also need
- //the changed signal as well
- Signal s;
- s.name = signal;
- s.modify = true;
- signalList.append(s);
- } else {
- h << " CONSTANT";
- }
- h << ")" << endl;
- }
- // Accessor
- h << " /**" << endl;
- h << " Get " << (*itEntry)->label() << endl;
- h << " */" << endl;
- if (cfg.staticAccessors) {
- h << " static" << endl;
- }
- h << " ";
- h << returnType;
- h << " " << getFunction(n) << "(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- h << ")" << Const;
- // function body inline only if not using dpointer
- // for BC mode
- if (!cfg.dpointer) {
- h << endl << " {" << endl;
- h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6);
- h << " }" << endl;
- } else {
- h << ";" << endl;
- }
-
- // Default value Accessor
- if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) {
- h << endl;
- h << " /**" << endl;
- h << " Get " << (*itEntry)->label() << " default value" << endl;
- h << " */" << endl;
- if (cfg.staticAccessors) {
- h << " static" << endl;
- }
- h << " ";
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- h << enumType(*itEntry, cfg.globalEnums);
- } else {
- h << cppType(t);
- }
- h << " " << getDefaultFunction(n) << "(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- h << ")" << Const << endl;
- h << " {" << endl;
- h << " return ";
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">(";
- }
- h << getDefaultFunction(n) << "_helper(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " i ";
- }
- h << ")";
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- h << ")";
- }
- h << ";" << endl;
- h << " }" << endl;
- }
-
- // Item accessor
- if (cfg.itemAccessors) {
- h << endl;
- h << " /**" << endl;
- h << " Get Item object corresponding to " << n << "()"
- << endl;
- h << " */" << endl;
- h << " Item" << itemType((*itEntry)->type()) << " *"
- << getFunction(n) << "Item(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- h << ")";
- if (!cfg.dpointer) {
- h << endl << " {" << endl;
- h << indent(itemAccessorBody((*itEntry), cfg), 6);
- h << " }" << endl;
- } else {
- h << ";" << endl;
- }
- }
-
- h << endl;
- }
-
- // Signal definition.
- const bool hasSignals = !signalList.isEmpty();
- bool hasNonModifySignals = false;
- if (hasSignals) {
- h << "\n enum {" << endl;
- unsigned val = 1;
- QList<Signal>::ConstIterator it, itEnd = signalList.constEnd();
- for (it = signalList.constBegin(); it != itEnd; val <<= 1) {
- hasNonModifySignals |= !it->modify;
- if (!val) {
- cerr << "Too many signals to create unique bit masks" << endl;
- exit(1);
- }
- Signal signal = *it;
- h << " " << signalEnumName(signal.name) << " = 0x" <<
- #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
- hex
- #else
- Qt::hex
- #endif
- << val;
- if (++it != itEnd) {
- h << ",";
- }
- h << endl;
- }
- h << " };" <<
- #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
- dec
- #else
- Qt::dec
- #endif
- << endl << endl;
-
- h << " Q_SIGNALS:";
- for (const Signal &signal : qAsConst(signalList)) {
- h << endl;
- if (!signal.label.isEmpty()) {
- h << " /**" << endl;
- h << " " << signal.label << endl;
- h << " */" << endl;
- }
- h << " void " << signal.name << "(";
- QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
- for (it = signal.arguments.constBegin(); it != itEnd;) {
- SignalArguments argument = *it;
- QString type = param(argument.type);
- if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) {
- for (int i = 0, end = entries.count(); i < end; ++i) {
- if (entries[i]->name() == argument.variableName) {
- type = enumType(entries[i], cfg.globalEnums);
- break;
- }
- }
- }
- h << type << " " << argument.variableName;
- if (++it != itEnd) {
- h << ", ";
- }
- }
- h << ");" << endl;
- }
- h << endl;
-
- h << " private:" << endl;
- h << " void itemChanged(quint64 flags);" << endl;
- h << endl;
- }
-
- h << " protected:" << endl;
-
- // Private constructor for singleton
- if (cfg.singleton) {
- h << " " << cfg.className << "(";
- if (cfgFileNameArg) {
- h << "KSharedConfig::Ptr config";
- }
- if (cfg.parentInConstructor) {
- if (cfgFileNameArg) {
- h << ", ";
- }
- h << "QObject *parent = nullptr";
- }
- h << ");" << endl;
- h << " friend class " << cfg.className << "Helper;" << endl << endl;
- }
-
- if (hasNonModifySignals) {
- h << " bool usrSave() override;" << endl;
- }
-
- // Member variables
- if (!cfg.memberVariables.isEmpty() && cfg.memberVariables != QLatin1String("private") && cfg.memberVariables != QLatin1String("dpointer")) {
- h << " " << cfg.memberVariables << ":" << endl;
- }
-
- // Class Parameters
- for (QList<Param>::ConstIterator it = parameters.constBegin();
- it != parameters.constEnd(); ++it) {
- h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl;
- }
-
- if (cfg.memberVariables != QLatin1String("dpointer")) {
- QString group;
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- if ((*itEntry)->group() != group) {
- group = (*itEntry)->group();
- h << endl;
- h << " // " << group << endl;
- }
- h << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg);
- if (!(*itEntry)->param().isEmpty()) {
- h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1);
- }
- h << ";" << endl;
-
- if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) {
- h << " ";
- if (cfg.staticAccessors) {
- h << "static ";
- }
- h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- h << ")" << Const << ";" << endl;
- }
- }
-
- h << endl << " private:" << endl;
- if (cfg.itemAccessors) {
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- h << " Item" << itemType((*itEntry)->type()) << " *" << itemVar(*itEntry, cfg);
- if (!(*itEntry)->param().isEmpty()) {
- h << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1);
- }
- h << ";" << endl;
- }
- }
- if (hasNonModifySignals) {
- h << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl;
- }
-
- } else {
- // use a private class for both member variables and items
- h << " private:" << endl;
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- if (cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name())) {
- h << " ";
- if (cfg.staticAccessors) {
- h << "static ";
- }
- h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper(";
- if (!(*itEntry)->param().isEmpty()) {
- h << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- h << ")" << Const << ";" << endl;
- }
- }
- h << " " + cfg.className + "Private *d;" << endl;
- }
-
- if (cfg.customAddons) {
- h << " // Include custom additions" << endl;
- h << " #include \"" << baseName << "_addons." << cfg.headerExtension << '"' << endl;
- }
-
- h << "};" << endl << endl;
-
- endNamespaces(cfg.nameSpace, h);
-
- h << "#endif" << endl << endl;
-
- header.close();
-
- QFile implementation(baseDir + implementationFileName);
- if (!implementation.open(QIODevice::WriteOnly)) {
- cerr << "Can not open '" << implementationFileName << "for writing."
- << endl;
- return 1;
- }
-
- QTextStream cpp(&implementation);
-
- cpp.setCodec("utf-8");
-
- cpp << "// This file is generated by kconfig_compiler_kf5 from " << QFileInfo(inputFilename).fileName() << "." << endl;
- cpp << "// All changes you do to this file will be lost." << endl << endl;
-
- cpp << "#include \"" << headerFileName << "\"" << endl << endl;
-
- for (it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it) {
- if ((*it).startsWith('"')) {
- cpp << "#include " << *it << endl;
- } else {
- cpp << "#include <" << *it << ">" << endl;
- }
- }
-
- if (!cfg.sourceIncludes.isEmpty()) {
- cpp << endl;
- }
-
- if (cfg.setUserTexts && cfg.translationSystem == CfgConfig::KdeTranslation) {
- cpp << "#include <klocalizedstring.h>" << endl << endl;
- }
-
- // Header required by singleton implementation
- if (cfg.singleton) {
- cpp << "#include <qglobal.h>" << endl << "#include <QFile>" << endl << endl;
- }
- if (cfg.singleton && cfgFileNameArg) {
- cpp << "#include <QDebug>" << endl << endl;
- }
-
- if (!cfg.nameSpace.isEmpty()) {
- cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl;
- }
-
- QString group;
-
- // private class implementation
- if (cfg.dpointer) {
- beginNamespaces(cfg.nameSpace, cpp);
- cpp << "class " << cfg.className << "Private" << endl;
- cpp << "{" << endl;
- cpp << " public:" << endl;
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- if ((*itEntry)->group() != group) {
- group = (*itEntry)->group();
- cpp << endl;
- cpp << " // " << group << endl;
- }
- cpp << " " << cppType((*itEntry)->type()) << " " << varName((*itEntry)->name(), cfg);
- if (!(*itEntry)->param().isEmpty()) {
- cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1);
- }
- cpp << ";" << endl;
- }
- cpp << endl << " // items" << endl;
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- const QString declType = (*itEntry)->signalList().isEmpty()
- ? QString(cfg.inherits + "::Item" + itemType((*itEntry)->type()))
- : QStringLiteral("KConfigCompilerSignallingItem");
- cpp << " " << declType << " *" << itemVar( *itEntry, cfg );
- if (!(*itEntry)->param().isEmpty()) {
- cpp << QStringLiteral("[%1]").arg((*itEntry)->paramMax() + 1);
- }
- cpp << ";" << endl;
- }
- if (hasNonModifySignals) {
- cpp << " uint " << varName(QStringLiteral("settingsChanged"), cfg) << ";" << endl;
- }
-
- cpp << "};" << endl << endl;
- endNamespaces(cfg.nameSpace, cpp);
- }
-
- // Singleton implementation
- if (cfg.singleton) {
- beginNamespaces(cfg.nameSpace, cpp);
- cpp << "class " << cfg.className << "Helper" << endl;
- cpp << '{' << endl;
- cpp << " public:" << endl;
- cpp << " " << cfg.className << "Helper() : q(nullptr) {}" << endl;
- cpp << " ~" << cfg.className << "Helper() { delete q; }" << endl;
- cpp << " " << cfg.className << "Helper(const " << cfg.className << "Helper&) = delete;" << endl;
- cpp << " " << cfg.className << "Helper& operator=(const " << cfg.className << "Helper&) = delete;" << endl;
- cpp << " " << cfg.className << " *q;" << endl;
- cpp << "};" << endl;
- endNamespaces(cfg.nameSpace, cpp);
- cpp << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl;
-
- cpp << cfg.className << " *" << cfg.className << "::self()" << endl;
- cpp << "{" << endl;
- if (cfgFileNameArg) {
- cpp << " if (!s_global" << cfg.className << "()->q)" << endl;
- cpp << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl;
- } else {
- cpp << " if (!s_global" << cfg.className << "()->q) {" << endl;
- cpp << " new " << cfg.className << ';' << endl;
- cpp << " s_global" << cfg.className << "()->q->read();" << endl;
- cpp << " }" << endl << endl;
- }
- cpp << " return s_global" << cfg.className << "()->q;" << endl;
- cpp << "}" << endl << endl;
-
- if (cfgFileNameArg) {
- auto instance = [&cfg, &cpp] (const QString &type, const QString &arg, bool isString) {
- cpp << "void " << cfg.className << "::instance(" << type << " " << arg << ")" << endl;
- cpp << "{" << endl;
- cpp << " if (s_global" << cfg.className << "()->q) {" << endl;
- cpp << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl;
- cpp << " return;" << endl;
- cpp << " }" << endl;
- cpp << " new " << cfg.className << "(";
- if (isString) {
- cpp << "KSharedConfig::openConfig(" << arg << ")";
- } else {
- cpp << "std::move(" << arg << ")";
- }
- cpp << ");" << endl;
- cpp << " s_global" << cfg.className << "()->q->read();" << endl;
- cpp << "}" << endl << endl;
- };
- instance(QStringLiteral("const QString&"), QStringLiteral("cfgfilename"), true);
- instance(QStringLiteral("KSharedConfig::Ptr"), QStringLiteral("config"), false);
- }
- }
-
- if (!cppPreamble.isEmpty()) {
- cpp << cppPreamble << endl;
- }
-
- // Constructor
- cpp << cfg.className << "::" << cfg.className << "(";
- if (cfgFileNameArg) {
- if (! cfg.forceStringFilename) {
- cpp << " KSharedConfig::Ptr config";
- } else {
- cpp << " const QString& config";
- }
- cpp << (parameters.isEmpty() ? "" : ",");
- }
-
- for (QList<Param>::ConstIterator it = parameters.constBegin();
- it != parameters.constEnd(); ++it) {
- if (it != parameters.constBegin()) {
- cpp << ",";
- }
- cpp << " " << param((*it).type) << " " << (*it).name;
- }
-
- if (cfg.parentInConstructor) {
- if (cfgFileNameArg || !parameters.isEmpty()) {
- cpp << ",";
- }
- cpp << " QObject *parent";
- }
- cpp << " )" << endl;
-
- cpp << " : " << cfg.inherits << "(";
- if (!cfgFileName.isEmpty()) {
- cpp << " QStringLiteral( \"" << cfgFileName << "\" ";
- }
- if (cfgFileNameArg) {
- if (! cfg.forceStringFilename) {
- cpp << " std::move( config ) ";
- } else {
- cpp << " config ";
- }
- }
- if (!cfgFileName.isEmpty()) {
- cpp << ") ";
- }
- cpp << ")" << endl;
-
- // Store parameters
- for (QList<Param>::ConstIterator it = parameters.constBegin();
- it != parameters.constEnd(); ++it) {
- cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl;
- }
-
- if (hasNonModifySignals && !cfg.dpointer) {
- cpp << " , " << varName(QStringLiteral("settingsChanged"), cfg) << "(0)" << endl;
- }
-
- cpp << "{" << endl;
-
- if (cfg.parentInConstructor) {
- cpp << " setParent(parent);" << endl;
- }
-
- if (cfg.dpointer) {
- cpp << " d = new " + cfg.className + "Private;" << endl;
- if (hasNonModifySignals) {
- cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
- }
- }
- // Needed in case the singleton class is used as baseclass for
- // another singleton.
- if (cfg.singleton) {
- cpp << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl;
- cpp << " s_global" << cfg.className << "()->q = this;" << endl;
- }
-
- group.clear();
-
- if (hasSignals) {
- // this cast to base-class pointer-to-member is valid C++
- // https://stackoverflow.com/questions/4272909/is-it-safe-to-upcast-a-method-pointer-and-use-it-with-base-class-pointer/
- cpp << " KConfigCompilerSignallingItem::NotifyFunction notifyFunction ="
- << " static_cast<KConfigCompilerSignallingItem::NotifyFunction>(&"
- << cfg.className << "::itemChanged);" << endl << endl;
- }
-
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- if ((*itEntry)->group() != group) {
- if (!group.isEmpty()) {
- cpp << endl;
- }
- group = (*itEntry)->group();
- cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
- }
-
- QString key = paramString((*itEntry)->key(), parameters);
- if (!(*itEntry)->code().isEmpty()) {
- cpp << (*itEntry)->code() << endl;
- }
- if ((*itEntry)->type() == QLatin1String("Enum")) {
- cpp << " QList<" + cfg.inherits + "::ItemEnum::Choice> values"
- << (*itEntry)->name() << ";" << endl;
- const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices;
- QList<CfgEntry::Choice>::ConstIterator it;
- for (it = choices.constBegin(); it != choices.constEnd(); ++it) {
- cpp << " {" << endl;
- cpp << " " + cfg.inherits + "::ItemEnum::Choice choice;" << endl;
- cpp << " choice.name = QStringLiteral(\"" << (*it).name << "\");" << endl;
- if (cfg.setUserTexts) {
- if (!(*it).label.isEmpty()) {
- cpp << " choice.label = "
- << translatedString(cfg, (*it).label, (*it).context)
- << ";" << endl;
- }
- if (!(*it).toolTip.isEmpty()) {
- cpp << " choice.toolTip = "
- << translatedString(cfg, (*it).toolTip, (*it).context)
- << ";" << endl;
- }
- if (!(*it).whatsThis.isEmpty()) {
- cpp << " choice.whatsThis = "
- << translatedString(cfg, (*it).whatsThis, (*it).context)
- << ";" << endl;
- }
- }
- cpp << " values" << (*itEntry)->name() << ".append( choice );" << endl;
- cpp << " }" << endl;
- }
- }
-
- if (!cfg.dpointer) {
- cpp << itemDeclaration(*itEntry, cfg);
- }
-
- if ((*itEntry)->param().isEmpty()) {
- // Normal case
- cpp << " " << itemPath(*itEntry, cfg) << " = "
- << newItem((*itEntry), key, (*itEntry)->defaultValue(), cfg) << endl;
-
- if (!(*itEntry)->minValue().isEmpty()) {
- cpp << " " << itemPath(*itEntry, cfg) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl;
- }
- if (!(*itEntry)->maxValue().isEmpty()) {
- cpp << " " << itemPath(*itEntry, cfg) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl;
- }
-
- if (cfg.setUserTexts) {
- cpp << userTextsFunctions((*itEntry), cfg);
- }
-
- if (cfg.allNotifiers || cfg.notifiers.contains((*itEntry)->name())) {
- cpp << " " << itemPath(*itEntry, cfg) << "->setWriteFlags(KConfigBase::Notify);" << endl;
- }
-
- cpp << " addItem( " << itemPath(*itEntry, cfg);
- QString quotedName = (*itEntry)->name();
- addQuotes(quotedName);
- if (quotedName != key) {
- cpp << ", QStringLiteral( \"" << (*itEntry)->name() << "\" )";
- }
- cpp << " );" << endl;
- } else {
- // Indexed
- for (int i = 0; i <= (*itEntry)->paramMax(); i++) {
- QString defaultStr;
- QString itemVarStr(itemPath(*itEntry, cfg) + QStringLiteral("[%1]").arg(i));
-
- if (!(*itEntry)->paramDefaultValue(i).isEmpty()) {
- defaultStr = (*itEntry)->paramDefaultValue(i);
- } else if (!(*itEntry)->defaultValue().isEmpty()) {
- defaultStr = paramString((*itEntry)->defaultValue(), (*itEntry), i);
- } else {
- defaultStr = defaultValue((*itEntry)->type());
- }
-
- cpp << " " << itemVarStr << " = "
- << newItem((*itEntry), paramString(key, *itEntry, i), defaultStr, cfg, QStringLiteral("[%1]").arg(i)) << endl;
-
- if (cfg.setUserTexts) {
- cpp << userTextsFunctions(*itEntry, cfg, itemVarStr, (*itEntry)->paramName());
- }
-
- // Make mutators for enum parameters work by adding them with $(..) replaced by the
- // param name. The check for isImmutable in the set* functions doesn't have the param
- // name available, just the corresponding enum value (int), so we need to store the
- // param names in a separate static list!.
- cpp << " addItem( " << itemVarStr << ", QStringLiteral( \"";
- if ((*itEntry)->paramType() == QLatin1String("Enum")) {
- cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg((*itEntry)->paramValues()[i]);
- } else {
- cpp << (*itEntry)->paramName().replace("$(" + (*itEntry)->param() + ')', QLatin1String("%1")).arg(i);
- }
- cpp << "\" ) );" << endl;
- }
- }
- }
-
- cpp << "}" << endl << endl;
-
- if (cfg.dpointer) {
- // setters and getters go in Cpp if in dpointer mode
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- QString n = (*itEntry)->name();
- QString t = (*itEntry)->type();
-
- // Manipulator
- if (cfg.allMutators || cfg.mutators.contains(n)) {
- cpp << "void " << setFunction(n, cfg.className) << "( ";
- if (!(*itEntry)->param().isEmpty()) {
- cpp << cppType((*itEntry)->paramType()) << " i, ";
- }
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- cpp << enumType(*itEntry, cfg.globalEnums);
- } else {
- cpp << param(t);
- }
- cpp << " v )" << endl;
- // function body inline only if not using dpointer
- // for BC mode
- cpp << "{" << endl;
- cpp << indent(memberMutatorBody(*itEntry, cfg), 6);
- cpp << "}" << endl << endl;
- }
-
- // Accessor
- if (cfg.useEnumTypes && t == QLatin1String("Enum")) {
- cpp << enumType(*itEntry, cfg.globalEnums);
- } else {
- cpp << cppType(t);
- }
- cpp << " " << getFunction(n, cfg.className) << "(";
- if (!(*itEntry)->param().isEmpty()) {
- cpp << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- cpp << ")" << Const << endl;
- // function body inline only if not using dpointer
- // for BC mode
- cpp << "{" << endl;
- cpp << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 2);
- cpp << "}" << endl << endl;
-
- // Default value Accessor -- written by the loop below
-
- // Item accessor
- if (cfg.itemAccessors) {
- cpp << endl;
- cpp << cfg.inherits + "::Item" << itemType((*itEntry)->type()) << " *"
- << getFunction(n, cfg.className) << "Item(";
- if (!(*itEntry)->param().isEmpty()) {
- cpp << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- cpp << ")" << endl;
- cpp << "{" << endl;
- cpp << indent(itemAccessorBody(*itEntry, cfg), 2);
- cpp << "}" << endl;
- }
-
- cpp << endl;
- }
- }
-
- // default value getters always go in Cpp
- for (itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry) {
- QString n = (*itEntry)->name();
- QString t = (*itEntry)->type();
-
- // Default value Accessor, as "helper" function
- if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) {
- cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper(";
- if (!(*itEntry)->param().isEmpty()) {
- cpp << " " << cppType((*itEntry)->paramType()) << " i ";
- }
- cpp << ")" << Const << endl;
- cpp << "{" << endl;
- cpp << memberGetDefaultBody(*itEntry) << endl;
- cpp << "}" << endl << endl;
- }
- }
-
- // Destructor
- cpp << cfg.className << "::~" << cfg.className << "()" << endl;
- cpp << "{" << endl;
- if (cfg.dpointer) {
- cpp << " delete d;" << endl;
- }
- if (cfg.singleton) {
- cpp << " s_global" << cfg.className << "()->q = nullptr;" << endl;
- }
- cpp << "}" << endl << endl;
-
- if (hasNonModifySignals) {
- cpp << "bool " << cfg.className << "::" << "usrSave()" << endl;
- cpp << "{" << endl;
- cpp << " const bool res = " << cfg.inherits << "::usrSave();" << endl;
- cpp << " if (!res) return false;" << endl << endl;
- for (const Signal &signal : qAsConst(signalList)) {
- if (signal.modify) {
- continue;
- }
-
- cpp << " if ( " << varPath(QStringLiteral("settingsChanged"), cfg) << " & " << signalEnumName(signal.name) << " )" << endl;
- cpp << " Q_EMIT " << signal.name << "(";
- QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd();
- for (it = signal.arguments.constBegin(); it != itEnd;) {
- SignalArguments argument = *it;
- bool cast = false;
- if (cfg.useEnumTypes && argument.type == QLatin1String("Enum")) {
- for (int i = 0, end = entries.count(); i < end; ++i) {
- if (entries[i]->name() == argument.variableName) {
- cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">(";
- cast = true;
- break;
- }
- }
- }
- cpp << varPath(argument.variableName, cfg);
- if (cast) {
- cpp << ")";
- }
- if (++it != itEnd) {
- cpp << ", ";
- }
- }
- cpp << ");" << endl;
- }
-
- cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " = 0;" << endl;
- cpp << " return true;" << endl;
- cpp << "}" << endl;
- }
-
- if (hasSignals) {
- cpp << endl;
- cpp << "void " << cfg.className << "::" << "itemChanged(quint64 flags) {" << endl;
- if (hasNonModifySignals)
- cpp << " " << varPath(QStringLiteral("settingsChanged"), cfg) << " |= flags;" << endl;
-
- if (!signalList.isEmpty())
- cpp << endl;
-
- for (const Signal &signal : qAsConst(signalList)) {
- if (signal.modify) {
- cpp << " if ( flags & " << signalEnumName(signal.name) << " ) {" << endl;
- cpp << " Q_EMIT " << signal.name << "();" << endl;
- cpp << " }" << endl;
- }
- }
-
- cpp << "}" << endl;
- }
-
- if (hasSignals || cfg.generateProperties) {
- // Add includemoc if they are signals defined.
- cpp << endl;
- cpp << "#include \"" << mocFileName << "\"" << endl;
- cpp << endl;
- }
+ // remove '.kcfg' from the name.
+ const QString baseName = inputFilename.mid(0, inputFilename.size()-5);
+ KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult);
+ headerGenerator.start();
+ headerGenerator.save();
- // clear entries list
- qDeleteAll(entries);
+ KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult);
+ sourceGenerator.start();
+ sourceGenerator.save();
- implementation.close();
+ qDeleteAll(parseResult.entries);
}