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