5 changed files with 378 additions and 11 deletions
@ -1,8 +1,57 @@ |
|||
#include <QCoreApplication> |
|||
#include <QCommandLineParser> |
|||
#include <QFile> |
|||
#include <QXmlStreamReader> |
|||
#include <QDebug> |
|||
|
|||
#include "settingsgenerator.h" |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
QCoreApplication a(argc, argv); |
|||
QCoreApplication::setApplicationName(QStringLiteral(TARGET)); |
|||
QCoreApplication::setApplicationVersion(QStringLiteral(VERSION)); |
|||
QCoreApplication::setOrganizationName(QStringLiteral(COMPANY)); |
|||
QCoreApplication::setOrganizationDomain(QStringLiteral(BUNDLE_PREFIX)); |
|||
|
|||
QCommandLineParser parser; |
|||
parser.setApplicationDescription(QStringLiteral("A tool to...")); //TODO description
|
|||
parser.addVersionOption(); |
|||
parser.addHelpOption(); |
|||
|
|||
parser.addOption({ |
|||
{QStringLiteral("t"), QStringLiteral("translate")}, |
|||
QStringLiteral("Translate the given settings file. The output will be" |
|||
"a dummy cpp file, writte to --impl.") |
|||
}); |
|||
parser.addOption({ |
|||
QStringLiteral("in"), |
|||
QStringLiteral("The input XML <file> containing the settings definition"), |
|||
QStringLiteral("file") |
|||
}); |
|||
parser.addOption({ |
|||
QStringLiteral("header"), |
|||
QStringLiteral("The <name> of the header file to generate"), |
|||
QStringLiteral("name") |
|||
}); |
|||
parser.addOption({ |
|||
QStringLiteral("impl"), |
|||
QStringLiteral("The <name> of the implementation file to generate"), |
|||
QStringLiteral("name") |
|||
}); |
|||
|
|||
return a.exec(); |
|||
parser.process(a); |
|||
|
|||
try { |
|||
SettingsGenerator generator { |
|||
parser.value(QStringLiteral("in")), |
|||
parser.value(QStringLiteral("header")), |
|||
parser.value(QStringLiteral("impl")) |
|||
}; |
|||
generator.process(); |
|||
return EXIT_SUCCESS; |
|||
} catch (const QString &str) { |
|||
qCritical() << qUtf8Printable(str); |
|||
return EXIT_FAILURE; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,214 @@ |
|||
#include "settingsgenerator.h" |
|||
#include <QDebug> |
|||
|
|||
SettingsGenerator::SettingsGenerator(const QString &inPath, const QString &hdrPath, const QString &srcPath) : |
|||
_inFile{inPath}, |
|||
_hdrFile{hdrPath}, |
|||
_srcFile{srcPath}, |
|||
_xml{&_inFile}, |
|||
_hdr{&_hdrFile}, |
|||
_src{&_srcFile} |
|||
{} |
|||
|
|||
void SettingsGenerator::process() |
|||
{ |
|||
if(!_inFile.open(QIODevice::ReadOnly | QIODevice::Text)) |
|||
throwFile(_inFile); |
|||
if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) |
|||
throwFile(_hdrFile); |
|||
if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) |
|||
throwFile(_srcFile); |
|||
|
|||
readData(); |
|||
} |
|||
|
|||
void SettingsGenerator::readData() |
|||
{ |
|||
if(!_xml.readNextStartElement()) |
|||
throwReader(); |
|||
if(_xml.name() != QStringLiteral("Settings")) |
|||
throwChild(); |
|||
|
|||
_data = readSettings(); |
|||
checkError(); |
|||
qDebug() << "Completed parsing xml - it is valid"; |
|||
} |
|||
|
|||
SettingsGenerator::Include SettingsGenerator::readInclude() |
|||
{ |
|||
Include include; |
|||
include.local = readAttrib<bool>(QStringLiteral("local"), false); |
|||
include.include = _xml.readElementText(); |
|||
checkError(); |
|||
return include; |
|||
} |
|||
|
|||
SettingsGenerator::Param SettingsGenerator::readParam() |
|||
{ |
|||
Param param; |
|||
param.key = readAttrib(QStringLiteral("key"), {}, true); |
|||
param.type = readAttrib(QStringLiteral("type"), {}, true); |
|||
param.asStr = readAttrib<bool>(QStringLiteral("asStr"), false); |
|||
param.value = _xml.readElementText(); |
|||
checkError(); |
|||
return param; |
|||
} |
|||
|
|||
QSharedPointer<SettingsGenerator::Backend> SettingsGenerator::readBackend() |
|||
{ |
|||
auto backend = QSharedPointer<Backend>::create(); |
|||
backend->className = readAttrib(QStringLiteral("class"), {}, true); |
|||
while(_xml.readNextStartElement()) { |
|||
if(_xml.name() == QStringLiteral("Param")) |
|||
backend->params.append(readParam()); |
|||
else |
|||
throwChild(); |
|||
} |
|||
checkError(); |
|||
return backend; |
|||
} |
|||
|
|||
QPair<QString, QString> SettingsGenerator::readTypeMapping() |
|||
{ |
|||
QPair<QString, QString> mapping; |
|||
mapping.first = readAttrib(QStringLiteral("key"), {}, true); |
|||
mapping.second = readAttrib(QStringLiteral("type"), {}, true); |
|||
checkError(); |
|||
return mapping; |
|||
} |
|||
|
|||
SettingsGenerator::Node SettingsGenerator::readNode() |
|||
{ |
|||
Node node; |
|||
node.key = readAttrib(QStringLiteral("key"), {}, true); |
|||
while(_xml.readNextStartElement()) { |
|||
if(_xml.name() == QStringLiteral("Node")) |
|||
node.subNodes.append(readNode()); |
|||
else if(_xml.name() == QStringLiteral("Entry")) |
|||
node.subEntries.append(readEntry()); |
|||
else if(_xml.name() == QStringLiteral("Import")) |
|||
node.subImports.append(readImport()); |
|||
else |
|||
throwChild(); |
|||
} |
|||
checkError(); |
|||
return node; |
|||
} |
|||
|
|||
SettingsGenerator::Entry SettingsGenerator::readEntry() |
|||
{ |
|||
Entry entry; |
|||
entry.key = readAttrib(QStringLiteral("key"), {}, true); |
|||
entry.type = readAttrib(QStringLiteral("type"), {}, true); |
|||
entry.qmlGroupKey = readAttrib(QStringLiteral("qmlGroupKey")); |
|||
entry.defaultValue = readAttrib(QStringLiteral("default")); |
|||
entry.tr = readAttrib<bool>(QStringLiteral("tr"), false); |
|||
entry.trContext = readAttrib(QStringLiteral("trContext")); |
|||
while(_xml.readNextStartElement()) { |
|||
if(_xml.name() == QStringLiteral("Code")) { |
|||
if(!entry.defaultValue.isNull()) |
|||
throwChild(); |
|||
entry.defaultValue = _xml.readElementText(); |
|||
entry.defaultIsCode = true; |
|||
checkError(); |
|||
} else if(_xml.name() == QStringLiteral("Node")) |
|||
entry.subNodes.append(readNode()); |
|||
else if(_xml.name() == QStringLiteral("Entry")) |
|||
entry.subEntries.append(readEntry()); |
|||
else if(_xml.name() == QStringLiteral("Import")) |
|||
entry.subImports.append(readImport()); |
|||
else |
|||
throwChild(); |
|||
} |
|||
checkError(); |
|||
return entry; |
|||
} |
|||
|
|||
SettingsGenerator::Import SettingsGenerator::readImport() |
|||
{ |
|||
Import import; |
|||
import.required = readAttrib<bool>(QStringLiteral("required"), true); |
|||
import.rootNode = readAttrib(QStringLiteral("rootNode")); |
|||
import.import = _xml.readElementText(); |
|||
checkError(); |
|||
return import; |
|||
} |
|||
|
|||
SettingsGenerator::Settings SettingsGenerator::readSettings() |
|||
{ |
|||
Settings settings; |
|||
settings.name = readAttrib(QStringLiteral("name"), {}, true); |
|||
settings.prefix = readAttrib(QStringLiteral("prefix")); |
|||
|
|||
while(_xml.readNextStartElement()) { |
|||
if(_xml.name() == QStringLiteral("Include")) |
|||
settings.includes.append(readInclude()); |
|||
else if(_xml.name() == QStringLiteral("Backend")) |
|||
settings.backend = readBackend(); |
|||
else if(_xml.name() == QStringLiteral("TypeMapping")) { |
|||
auto mapping = readTypeMapping(); |
|||
settings.typeMapping.insert(mapping.first, mapping.second); |
|||
} else if(_xml.name() == QStringLiteral("Node")) |
|||
settings.subNodes.append(readNode()); |
|||
else if(_xml.name() == QStringLiteral("Entry")) |
|||
settings.subEntries.append(readEntry()); |
|||
else if(_xml.name() == QStringLiteral("Import")) |
|||
settings.subImports.append(readImport()); |
|||
else |
|||
throwChild(); |
|||
} |
|||
checkError(); |
|||
return settings; |
|||
} |
|||
|
|||
void SettingsGenerator::checkError() const |
|||
{ |
|||
if(_xml.hasError()) |
|||
throwReader(); |
|||
} |
|||
|
|||
template<typename T> |
|||
T SettingsGenerator::readAttrib(const QString &key, const T &defaultValue, bool required) const |
|||
{ |
|||
if(_xml.attributes().hasAttribute(key)) |
|||
return QVariant(_xml.attributes().value(key).toString()).template value<T>(); |
|||
else if(required) |
|||
throwReader(QStringLiteral("Required attribute \"%1\" but was not set").arg(key)); |
|||
else |
|||
return defaultValue; |
|||
} |
|||
|
|||
template<> |
|||
bool SettingsGenerator::readAttrib<bool>(const QString &key, const bool &defaultValue, bool required) const |
|||
{ |
|||
if(_xml.attributes().hasAttribute(key)) { |
|||
if(_xml.attributes().value(key) == QStringLiteral("true")) |
|||
return true; |
|||
else if(_xml.attributes().value(key) == QStringLiteral("false")) |
|||
return false; |
|||
else |
|||
throwReader(QStringLiteral("Value of attribute \"%1\" is not a xs:boolean!").arg(key)); |
|||
} else if(required) |
|||
throwReader(QStringLiteral("Required attribute \"%1\" but was not set").arg(key)); |
|||
else |
|||
return defaultValue; |
|||
} |
|||
|
|||
void SettingsGenerator::throwFile(const QFileDevice &file) const |
|||
{ |
|||
throw QStringLiteral("%1: %2").arg(file.fileName(), file.errorString()); |
|||
} |
|||
|
|||
void SettingsGenerator::throwReader(const QString &overwriteError) const |
|||
{ |
|||
throw QStringLiteral("%1:%2:%3: %4") |
|||
.arg(dynamic_cast<QFileDevice*>(_xml.device())->fileName()) |
|||
.arg(_xml.lineNumber()) |
|||
.arg(_xml.columnNumber()) |
|||
.arg(overwriteError.isNull() ? _xml.errorString() : overwriteError); |
|||
} |
|||
|
|||
void SettingsGenerator::throwChild() |
|||
{ |
|||
throwReader(QStringLiteral("Unexpected child element: %1").arg(_xml.name())); |
|||
} |
@ -0,0 +1,102 @@ |
|||
#ifndef SETTINGSGENERATOR_H |
|||
#define SETTINGSGENERATOR_H |
|||
|
|||
#include <QFile> |
|||
#include <QXmlStreamReader> |
|||
#include <QTextStream> |
|||
#include <QSharedPointer> |
|||
|
|||
class SettingsGenerator |
|||
{ |
|||
public: |
|||
SettingsGenerator(const QString &inPath, |
|||
const QString &hdrPath, |
|||
const QString &srcPath); |
|||
|
|||
void process(); |
|||
|
|||
private: |
|||
QFile _inFile; |
|||
QFile _hdrFile; |
|||
QFile _srcFile; |
|||
|
|||
QXmlStreamReader _xml; |
|||
QTextStream _hdr; |
|||
QTextStream _src; |
|||
|
|||
struct Include{ |
|||
bool local; |
|||
QString include; |
|||
}; |
|||
|
|||
struct Param { |
|||
QString key; |
|||
QString type; |
|||
bool asStr; |
|||
QString value; |
|||
}; |
|||
|
|||
struct Backend { |
|||
QString className; |
|||
QList<Param> params; |
|||
}; |
|||
|
|||
struct Entry; |
|||
struct Import; |
|||
struct Node { |
|||
QString key; |
|||
QList<Node> subNodes; |
|||
QList<Entry> subEntries; |
|||
QList<Import> subImports; |
|||
}; |
|||
|
|||
struct Entry : public Node { |
|||
QString type; |
|||
QString qmlGroupKey; |
|||
QString defaultValue; |
|||
bool defaultIsCode = false; |
|||
bool tr; |
|||
QString trContext; |
|||
}; |
|||
|
|||
struct Import { |
|||
bool required; |
|||
QString rootNode; |
|||
QString import; |
|||
}; |
|||
|
|||
struct Settings : public Node { |
|||
QString name; |
|||
QString prefix; |
|||
|
|||
QList<Include> includes; |
|||
QSharedPointer<Backend> backend; |
|||
QHash<QString, QString> typeMapping; |
|||
} _data; |
|||
|
|||
void readData(); |
|||
|
|||
Include readInclude(); |
|||
Param readParam(); |
|||
QSharedPointer<Backend> readBackend(); |
|||
QPair<QString, QString> readTypeMapping(); |
|||
|
|||
Node readNode(); |
|||
Entry readEntry(); |
|||
Import readImport(); |
|||
|
|||
Settings readSettings(); |
|||
|
|||
template <typename T = QString> |
|||
T readAttrib(const QString &key, const T &defaultValue = {}, bool required = false) const; |
|||
|
|||
void checkError() const; |
|||
Q_NORETURN void throwFile(const QFileDevice &file) const; |
|||
Q_NORETURN void throwReader(const QString &overwriteError = {}) const; |
|||
Q_NORETURN void throwChild(); |
|||
}; |
|||
|
|||
template<> |
|||
bool SettingsGenerator::readAttrib<bool>(const QString &key, const bool &defaultValue, bool required) const; |
|||
|
|||
#endif // SETTINGSGENERATOR_H
|
Loading…
Reference in new issue