diff options
| author | Tomaz Canabrava <tcanabrava@kde.org> | 2020-01-17 10:03:43 +0000 | 
|---|---|---|
| committer | Tomaz Canabrava <tcanabrava@kde.org> | 2020-01-17 10:03:43 +0000 | 
| commit | 5f8c2ce63499d05dfb4753eb1acc21dccf21d434 (patch) | |
| tree | fed718a3c8f4c4974411d612a79c4125ae3fffd8 /src/kconfig_compiler | |
| parent | 98c32e29f50465d4d4e16bafdf0491edbfb422b0 (diff) | |
| download | kconfig-5f8c2ce63499d05dfb4753eb1acc21dccf21d434.tar.gz kconfig-5f8c2ce63499d05dfb4753eb1acc21dccf21d434.tar.bz2 | |
Revert "WIP: Refactor KConfigXT"
This reverts commit 98c32e29f50465d4d4e16bafdf0491edbfb422b0.
This broke kdevelop and kmymoney. I'm workin on the fixes and more
unittests for them.
Diffstat (limited to 'src/kconfig_compiler')
| -rw-r--r-- | src/kconfig_compiler/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/kconfig_compiler/KCFGXmlParser.cpp | 564 | ||||
| -rw-r--r-- | src/kconfig_compiler/KCFGXmlParser.h | 82 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigCodeGeneratorBase.cpp | 276 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigCodeGeneratorBase.h | 118 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigCommonStructs.h | 195 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigHeaderGenerator.cpp | 612 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigHeaderGenerator.h | 78 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigSourceGenerator.cpp | 657 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigSourceGenerator.h | 86 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigXTParameters.cpp | 100 | ||||
| -rw-r--r-- | src/kconfig_compiler/KConfigXTParameters.h | 81 | ||||
| -rw-r--r-- | src/kconfig_compiler/kconfig_compiler.cpp | 2208 | 
13 files changed, 2089 insertions, 2977 deletions
| diff --git a/src/kconfig_compiler/CMakeLists.txt b/src/kconfig_compiler/CMakeLists.txt index 3543dfa2..dc0a08db 100644 --- a/src/kconfig_compiler/CMakeLists.txt +++ b/src/kconfig_compiler/CMakeLists.txt @@ -1,13 +1,6 @@ -set(kconfig_compiler_SRCS -    KConfigXTParameters.cpp -    KConfigCodeGeneratorBase.cpp -    KConfigHeaderGenerator.cpp -    KConfigSourceGenerator.cpp -    KCFGXmlParser.cpp -    kconfig_compiler.cpp -) +set(kconfig_compiler_SRCS kconfig_compiler.cpp)  add_executable(kconfig_compiler ${kconfig_compiler_SRCS}) diff --git a/src/kconfig_compiler/KCFGXmlParser.cpp b/src/kconfig_compiler/KCFGXmlParser.cpp deleted file mode 100644 index 214335c3..00000000 --- a/src/kconfig_compiler/KCFGXmlParser.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* 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 deleted file mode 100644 index 8c85d878..00000000 --- a/src/kconfig_compiler/KCFGXmlParser.h +++ /dev/null @@ -1,82 +0,0 @@ -/* 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 deleted file mode 100644 index 024af19c..00000000 --- a/src/kconfig_compiler/KConfigCodeGeneratorBase.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* 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 ¶meters, -    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 deleted file mode 100644 index fdf3b7e3..00000000 --- a/src/kconfig_compiler/KConfigCodeGeneratorBase.h +++ /dev/null @@ -1,118 +0,0 @@ -/* -    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 ¶meters, // 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 deleted file mode 100644 index c78c7b76..00000000 --- a/src/kconfig_compiler/KConfigCommonStructs.h +++ /dev/null @@ -1,195 +0,0 @@ -/* 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 ¶m = QString(), -    const QString ¶mValue = QString()); - -// TODO: Sanitize those functions. -QString newItem( -    const CfgEntry* entry,  -    const QString &key, -    const QString& defaultValue, -    const KConfigXTParameters &cfg,  -    const QString ¶m = 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> ¶meters); - -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 deleted file mode 100644 index 088f64e7..00000000 --- a/src/kconfig_compiler/KConfigHeaderGenerator.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/* 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 ¶meter : 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 deleted file mode 100644 index 30f09ac4..00000000 --- a/src/kconfig_compiler/KConfigHeaderGenerator.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -    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 ¶meters,  -        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 deleted file mode 100644 index 1949b420..00000000 --- a/src/kconfig_compiler/KConfigSourceGenerator.cpp +++ /dev/null @@ -1,657 +0,0 @@ -/* 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 ¶meter : 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 deleted file mode 100644 index 77409329..00000000 --- a/src/kconfig_compiler/KConfigSourceGenerator.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -    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 ¶meters,  -        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 deleted file mode 100644 index 1d488e9e..00000000 --- a/src/kconfig_compiler/KConfigXTParameters.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* 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 deleted file mode 100644 index db2cbcb5..00000000 --- a/src/kconfig_compiler/KConfigXTParameters.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -    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 00699c36..848595f2 100644 --- a/src/kconfig_compiler/kconfig_compiler.cpp +++ b/src/kconfig_compiler/kconfig_compiler.cpp @@ -34,19 +34,15 @@  #include <QDomAttr>  #include <QRegularExpression>  #include <QStringList> -#include <QCommandLineParser> -#include <QCommandLineOption> + +#include <qcommandlineparser.h> +#include <qcommandlineoption.h>  #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  { @@ -54,7 +50,444 @@ QTextStream cout(stdout);  QTextStream cerr(stderr);  } -QString varName(const QString &n, const KConfigXTParameters &cfg) +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 result;      if (!cfg.dpointer) { @@ -67,7 +500,7 @@ QString varName(const QString &n, const KConfigXTParameters &cfg)      return result;  } -QString varPath(const QString &n, const KConfigXTParameters &cfg) +static QString varPath(const QString &n, const CfgConfig &cfg)  {      QString result;      if (cfg.dpointer) { @@ -78,14 +511,14 @@ QString varPath(const QString &n, const KConfigXTParameters &cfg)      return result;  } -QString enumName(const QString &n) +static QString enumName(const QString &n)  {      QString result = QLatin1String("Enum") + n;      result[4] = result[4].toUpper();      return result;  } -QString enumName(const QString &n, const CfgEntry::Choices &c) +static QString enumName(const QString &n, const CfgEntry::Choices &c)  {      QString result = c.name();      if (result.isEmpty()) { @@ -95,11 +528,11 @@ QString enumName(const QString &n, const CfgEntry::Choices &c)      return result;  } -QString enumType(const CfgEntry *e, bool globalEnums) +static 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");          } @@ -108,7 +541,7 @@ QString enumType(const CfgEntry *e, bool globalEnums)      return result;  } -QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) +static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)  {      QString result = c.name();      if (result.isEmpty()) { @@ -122,7 +555,7 @@ QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c)      return result;  } -QString setFunction(const QString &n, const QString &className) +static QString setFunction(const QString &n, const QString &className = QString())  {      QString result = QLatin1String("set") + n;      result[3] = result[3].toUpper(); @@ -133,12 +566,12 @@ QString setFunction(const QString &n, const QString &className)      return result;  } -QString changeSignalName(const QString &n) +static QString changeSignalName(const QString &n)  {      return n+QStringLiteral("Changed");  } -QString getDefaultFunction(const QString &n, const QString &className) +static QString getDefaultFunction(const QString &n, const QString &className = QString())  {      QString result = QLatin1String("default") +  n + QLatin1String("Value");      result[7] = result[7].toUpper(); @@ -149,7 +582,7 @@ QString getDefaultFunction(const QString &n, const QString &className)      return result;  } -QString getFunction(const QString &n, const QString &className) +static QString getFunction(const QString &n, const QString &className = QString())  {      QString result = n;      result[0] = result[0].toLower(); @@ -160,7 +593,7 @@ QString getFunction(const QString &n, const QString &className)      return result;  } -void addQuotes(QString &s) +static void addQuotes(QString &s)  {      if (!s.startsWith(QLatin1Char('"'))) {          s.prepend(QLatin1Char('"')); @@ -180,7 +613,7 @@ static QString quoteString(const QString &s)      return QLatin1Char('\"') + r + QLatin1Char('\"');  } -QString literalString(const QString &s) +static QString literalString(const QString &s)  {      bool isAscii = true;      for (int i = s.length(); i--;) @@ -195,8 +628,20 @@ QString literalString(const QString &s)      }  } +static QString dumpNode(const QDomNode &node) +{ +    QString msg; +    QTextStream s(&msg, QIODevice::WriteOnly); +    node.save(s, 0); -QString signalEnumName(const QString &signalName) +    msg = msg.simplified(); +    if (msg.length() > 40) { +        return msg.left(37) + QLatin1String("..."); +    } +    return msg; +} + +static QString signalEnumName(const QString &signalName)  {      QString result;      result = QLatin1String("signal") + signalName; @@ -205,8 +650,345 @@ 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; +        } -bool isUnsigned(const QString &type) +        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)  {      if (type == QLatin1String("UInt")) {          return true; @@ -386,47 +1168,47 @@ QString itemType(const QString &type)      return t;  } -QString itemDeclaration(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemDeclaration(const CfgEntry *e, const CfgConfig &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 -QString itemVar(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemVar(const CfgEntry *e, const CfgConfig &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;  } -QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg) +static QString itemPath(const CfgEntry *e, const CfgConfig &cfg)  {      QString result;      if (cfg.dpointer) { @@ -438,18 +1220,18 @@ QString itemPath(const CfgEntry *e, const KConfigXTParameters &cfg)  }  QString newItem(const CfgEntry* entry, const QString &key, const QString& defaultValue, -                const KConfigXTParameters &cfg, const QString ¶m) { +                const CfgConfig &cfg, const QString ¶m = QString()) { -    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; @@ -473,11 +1255,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);          } @@ -507,12 +1289,12 @@ QString paramString(const QString &group, const QList<Param> ¶meters)      return "QStringLiteral( \"" + paramString + "\" )" + arguments;  } -QString translatedString(const KConfigXTParameters &cfg, const QString &string, const QString &context, const QString ¶m, const QString ¶mValue) +QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString ¶m = QString(), const QString ¶mValue = QString())  {      QString result;      switch (cfg.translationSystem) { -    case KConfigXTParameters::QtTranslation: +    case CfgConfig::QtTranslation:          if (!context.isEmpty()) {              result += "/*: " + context + " */ QCoreApplication::translate(\"";          } else { @@ -521,7 +1303,7 @@ QString translatedString(const KConfigXTParameters &cfg, const QString &string,          result += cfg.className + "\", ";          break; -    case KConfigXTParameters::KdeTranslation: +    case CfgConfig::KdeTranslation:          if (!cfg.translationDomain.isEmpty() && !context.isEmpty()) {              result += "i18ndc(" + quoteString(cfg.translationDomain) + ", " + quoteString(context) + ", ";          } else if (!cfg.translationDomain.isEmpty()) { @@ -548,36 +1330,62 @@ QString translatedString(const KConfigXTParameters &cfg, const QString &string,  }  /* int i is the value of the parameter */ -QString userTextsFunctions(const CfgEntry *e, const KConfigXTParameters &cfg, QString itemVarStr, const QString &i) +QString userTextsFunctions(CfgEntry *e, const CfgConfig &cfg, QString itemVarStr = QString(), const QString &i = QString())  {      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 -//TODO: Fix add Debug Method, it should also take the debug string. -void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QString &n) + +void addDebugMethod(QTextStream &out, const CfgConfig &cfg, const QString &n)  {      if (cfg.qCategoryLoggingName.isEmpty()) {         out << "  qDebug() << \"" << setFunction(n); @@ -586,30 +1394,101 @@ void addDebugMethod(QTextStream &out, const KConfigXTParameters &cfg, const QStr      }  } +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(const CfgEntry *e) +QString memberGetDefaultBody(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->paramDefaultValues[i].isEmpty()) { -                out << "  case " << i << ": return " << e->paramDefaultValues[i] << ';' << endl; +        for (int i = 0; i <= e->paramMax(); ++i) { +            if (!e->paramDefaultValue(i).isEmpty()) { +                out << "  case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl;              }          } -        QString defaultValue = e->defaultValue; -          out << "  default:" << endl; -        out << "    return " << defaultValue.replace("$(" + e->param + ')', QLatin1String("i")) << ';' << endl; +        out << "    return " << e->defaultValue().replace("$(" + e->param() + ')', QLatin1String("i")) << ';' << endl;          out << "  }" << endl;      } else { -        out << "  return " << e->defaultValue << ';'; +        out << "  return " << e->defaultValue() << ';';      }      return result; @@ -618,13 +1497,13 @@ QString memberGetDefaultBody(const 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(const CfgEntry *e, const KConfigXTParameters &cfg) +QString itemAccessorBody(CfgEntry *e, const CfgConfig &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; @@ -650,29 +1529,30 @@ QString indent(QString text, int spaces)      return result;  } -bool hasErrors(KCFGXmlParser &parser, const ParseResult& parseResult, const KConfigXTParameters &cfg) +// 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)  { -    if (cfg.className.isEmpty()) { -        cerr << "Class name missing" << endl; -        return true; -    } - -    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 (!p_ns.isEmpty()) { +        const QStringList nameSpaces = p_ns.split(QStringLiteral("::")); +        for (const QString &ns : nameSpaces) { +            p_out << "namespace " << ns << " {" << endl; +        } +        p_out << endl;      } +} -    if (parseResult.entries.isEmpty()) { -        cerr << "No entries." << 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;      } - -    return false;  }  int main(int argc, char **argv) @@ -681,22 +1561,22 @@ int main(int argc, char **argv)      app.setApplicationName(QStringLiteral("kconfig_compiler"));      app.setApplicationVersion(QStringLiteral(KCONFIG_VERSION_STRING)); -    QString inputFilename, codegenFilename; +    validNameRegexp = new QRegularExpression(QRegularExpression::anchoredPattern( +                                             QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); -    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.")); +    QString inputFilename, codegenFilename;      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(); @@ -704,7 +1584,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; @@ -715,18 +1595,16 @@ 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 @@ -736,34 +1614,1124 @@ int main(int argc, char **argv)  #endif          baseDir.append("/"); -    KConfigXTParameters cfg(codegenFilename); +    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); -    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(); +    QFile input(inputFilename); -    ParseResult parseResult = xmlParser.getParseResult(); +    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; +    } -    if (hasErrors(xmlParser, parseResult, cfg)) { +    QDomElement cfgElement = doc.documentElement(); + +    if (cfgElement.isNull()) { +        cerr << "No document in kcfg file" << endl;          return 1;      } -    // TODO: Move this to somewhere saner. -    for (const auto &signal : qAsConst(parseResult.signalList)) { -        parseResult.hasNonModifySignals |= !signal.modify; +    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;      } -    // remove '.kcfg' from the name. -    const QString baseName = inputFilename.mid(0, inputFilename.size()-5); -    KConfigHeaderGenerator headerGenerator(baseName, baseDir, cfg, parseResult); -    headerGenerator.start(); -    headerGenerator.save(); +    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; +    } -    KConfigSourceGenerator sourceGenerator(baseName, baseDir, cfg, parseResult); -    sourceGenerator.start(); -    sourceGenerator.save(); +    // clear entries list +    qDeleteAll(entries); -    qDeleteAll(parseResult.entries); +    implementation.close();  } | 
