5 changed files with 378 additions and 11 deletions
@ -1,8 +1,57 @@ |
|||||
#include <QCoreApplication> |
#include <QCoreApplication> |
||||
|
#include <QCommandLineParser> |
||||
|
#include <QFile> |
||||
|
#include <QXmlStreamReader> |
||||
|
#include <QDebug> |
||||
|
|
||||
|
#include "settingsgenerator.h" |
||||
|
|
||||
int main(int argc, char *argv[]) |
int main(int argc, char *argv[]) |
||||
{ |
{ |
||||
QCoreApplication a(argc, 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