From 681f2be56c45e3945cd6cbc56ac14317a97ec9c1 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Tue, 16 Feb 2016 15:18:14 +0100 Subject: Initial commit --- ConfigBase.hpp | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 ConfigBase.hpp (limited to 'ConfigBase.hpp') diff --git a/ConfigBase.hpp b/ConfigBase.hpp new file mode 100644 index 0000000..ade454a --- /dev/null +++ b/ConfigBase.hpp @@ -0,0 +1,330 @@ +#ifndef CONFIGBASE +#define CONFIGBASE + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Util.hpp" + +using ConfigException = std::logic_error; + +namespace ConfigValueType { +enum Type { + None, + String, + Integer, + Boolean, + List, + Map +}; +} + +class ConfigValueBase { +public: + + virtual void setValue(const QString&) { } + virtual QString value() { return ""; } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::None; } + + + + template + static Type getValue(const QString& value); + + template + static QString getStringValue(Type val); +}; + +template +class ConfigValue : public ConfigValueBase { +public: + virtual void setValue(const QString&) { throw ConfigException("Cannot assign"); } + virtual QString value() { throw ConfigException("Cannot get the value"); } +}; + +using String = QString; +using Integer = int; +using Port = ushort; +using Boolean = bool; +#define List(Type) QList +#define Map(KeyType, ValueType) QMap + + +#define ConfigVal(Value) {#Value, mkConfigValue(Value)} +#define ConfigValEx(Value, ...) {#Value, mkConfigValue(Value, __VA_ARGS__)} + +template<> +class ConfigValue : public ConfigValueBase { + String& config; + bool trimmedQuotes = false; + +public: + ConfigValue(String& config) : config(config) { } + + virtual void setValue(const QString& value) { config = Util::trimQuotes(value, trimmedQuotes); } + virtual QString value() + { + static QRegularExpression quoteExp(R"(^(\s.*|.*\s)$)"); + if(trimmedQuotes || quoteExp.match(config).hasMatch()) + { + return "\"" + config + "\""; + } + else + { + return config; + } + } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::String; } +}; + +template +class ConfigValue::value>::type> : public ConfigValueBase { + Type& config; + +public: + ConfigValue(Type& config) : config(config) { } + + virtual void setValue(const QString& value) + { + bool ok = true; + long long longLongVal = value.toLongLong(&ok, 0); + if(!ok) throw ConfigException("\"" + value.toStdString() + "\" could not be parsed as an Integer"); + if(longLongVal < std::numeric_limits::min() || longLongVal > std::numeric_limits::max()) throw ConfigException((QString::number(longLongVal) + " is out of range (" + QString::number(std::numeric_limits::min()) + " - " + QString::number(std::numeric_limits::max()) + ")").toStdString()); + config = static_cast(longLongVal); + } + virtual QString value() { return QString::number(config); } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::Integer; } +}; + +template<> +class ConfigValue : public ConfigValueBase { + Boolean& config; + +public: + ConfigValue(Boolean& config) : config(config) { } + + virtual void setValue(const QString& value) + { + if(value == "true") + { + config = true; + } + else if(value == "false") + { + config = false; + } + else + { + throw ConfigException("\"" + value.toStdString() + "\" could not be parsed as a Boolean"); + } + } + virtual QString value() { return config ? "true" : "false"; } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::Boolean; } +}; + +class ConfigValueList : public ConfigValueBase { +public: + virtual void append(const QString& entry) = 0; + virtual void remove(const QString& entry) = 0; + virtual QStringList getValues() = 0; +}; + +class ConfigValueMap : public ConfigValueBase { +public: + virtual void setKeyValue(const QString& key, const QString& value) = 0; + virtual void remove(const QString& key) = 0; + virtual QMap getValues() = 0; +}; + +template +class ConfigValue> : public ConfigValueList { + using ListType = QList; + + ListType& config; + const bool deduplicate; + const QChar splitChar; + +public: + ConfigValue(ListType& config, bool deduplicate = true, const QChar splitChar = ';') : config(config), deduplicate(deduplicate), splitChar(splitChar) {} + + virtual ListType& list() { return config; } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::List; } + + virtual void append(const QString &entry) + { + Type val = ConfigValueBase::getValue(entry); + if(!deduplicate || !config.contains(val)) + { + config.append(val); + } + } + + virtual void remove(const QString &entry) { config.removeAll(ConfigValueBase::getValue(entry)); } + + virtual QStringList getValues() + { + QStringList ret; + + foreach(Type val, config) + { + ret.append(ConfigValueBase::getStringValue(val)); + } + + return ret; + } + + void setValue(const QString& value) + { + config.clear(); + if(value.isEmpty()) + { + return; + } + QStringList parts = Util::splitEscaped(value, splitChar); + foreach(const QString& part, parts) + { + config.append(ConfigValueBase::getValue(part)); + } + } + + QString value() + { + QStringList parts; + foreach(const Type& part, config) + { + parts.append(ConfigValueBase::getStringValue(part)); + } + return Util::joinEscape(parts, splitChar); + } +}; + +template +class ConfigValue> : public ConfigValueMap { + using MapType = QMap; + + MapType& config; + const QChar assignChar; + const QChar splitChar; + +public: + ConfigValue(MapType& config, const QChar assignChar = ':', const QChar splitChar = ';') : config(config), assignChar(assignChar), splitChar(splitChar) {} + + virtual MapType& map() { return config; } + virtual ConfigValueType::Type type() { return ConfigValueType::Type::Map; } + + virtual void setKeyValue(const QString& key, const QString& value) + { + config[ConfigValueBase::getValue(key)] = ConfigValueBase::getValue(value); + } + + virtual QMap getValues() + { + QMap ret; + + foreach(KeyType key, config.keys()) + { + ret[ConfigValueBase::getStringValue(key)] = ConfigValueBase::getStringValue(config[key]); + } + + return ret; + } + + virtual void remove(const QString &key) + { + config.remove(ConfigValueBase::getValue(key)); + } + + QString value() + { + QStringList ret; + foreach(const KeyType& key, config.keys()) + { + ret.append(Util::joinEscape({ConfigValueBase::getStringValue(key), ConfigValueBase::getStringValue(config.value(key))}, assignChar)); + } + return Util::joinEscape(ret, splitChar); + } + + void setValue(const QString& value) + { + config.clear(); + if(value.isEmpty()) + { + return; + } + QStringList parts = Util::splitEscaped(value, splitChar); + foreach(const QString& part, parts) + { + QStringList parts = Util::splitEscaped(part, assignChar); + if(parts.length() != 2) + { + throw ConfigException("Cannot parse corrupt map key-value-pair"); + } + config[ConfigValueBase::getValue(parts.first())] = ConfigValueBase::getValue(parts.at(1)); + } + } +}; + +template +class ConfigValue::value>::type> : public ConfigValue::type> { + using UndType = typename std::underlying_type::type; +public: + ConfigValue(Type& config) : ConfigValue::ConfigValue((UndType&)config) {} +}; + +template +ConfigValue* mkConfigValue(Type& Value, Types... values) +{ + return new ConfigValue(Value, values...); +} + +template +Type ConfigValueBase::getValue(const QString& value) +{ + Type ret; + ConfigValue val(ret); + val.setValue(value); + return ret; +} + +template +QString ConfigValueBase::getStringValue(Type value) +{ + ConfigValue val(value); + return val.value(); +} + +class ConfigBase +{ +public: + explicit ConfigBase(QMap configValues) : configValues(configValues) {} + + void setConfigValue(const QString& name, const QString& value); + QString getConfigValueLine(const QString& name); + void addConfigListEntry(const QString& name, const QString& value); + void removeConfigMapListEntry(const QString &name, const QString &value); + void setConfigMapValue(const QString& name, const QString& key, const QString& value); + + QString read(const QString& fileName, bool writeDefault = true); + bool write(QString fileName = ""); + + void setConfigLine(const QString& line); + +protected: + void addConfigValue(QString name, ConfigValueBase *value); + ConfigValueBase& getConfigValue(const QString &name); + + QMap configValues; + +private: + QString curFileName = ""; +}; + +#endif // CONFIGBASE + -- cgit v1.2.3-54-g00ecf