From d592ee191e8aedc84c670e6d818fcf97c0bd7a92 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Wed, 17 Jan 2018 13:32:13 +0100 Subject: Configuration creates missing items based on defaults --- lib/settings/configuration.cpp | 233 ++++++++++++++++++----------------------- lib/settings/configuration.h | 50 ++++----- 2 files changed, 122 insertions(+), 161 deletions(-) (limited to 'lib') diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp index 06ee0bd..af5af65 100644 --- a/lib/settings/configuration.cpp +++ b/lib/settings/configuration.cpp @@ -7,22 +7,20 @@ */ #include "configuration.h" -#include +#include #include using namespace libconfig; -Configuration::Configuration() +Configuration::Configuration(const std::string &path, const std::string &home) { m_userCfg = new Config(); -#ifdef C_LIKE_CONFIG + // prettier output m_userCfg->setOptions(Config::OptionSemicolonSeparators | Config::OptionOpenBraceOnSeparateLine); -#endif - // fsync after writing and before closing m_userCfg->setOption(Config::OptionFsync, true); - // make sure the cfgPath is empty - m_userCfgPath = std::string(); + m_userCfgPath = path; + m_homePath = home; m_defaultCfg = new Config(); } @@ -33,14 +31,13 @@ Configuration::~Configuration() delete m_defaultCfg; } -bool Configuration::readUserConfiguration(const std::string &path) +bool Configuration::read() { - m_userCfgPath = path; try { - m_userCfg->readFile(path.c_str()); - } catch(FileIOException) { + m_userCfg->readFile(m_userCfgPath.c_str()); + } catch(const FileIOException &e) { return false; - } catch(ParseException) { + } catch(const ParseException &e) { return false; } return true; @@ -50,30 +47,27 @@ bool Configuration::parse(const std::string &contents) { try { m_userCfg->readString(contents); - } catch(ParseException) { + } catch(const ParseException &e) { return false; } return true; } -bool Configuration::writeUserConfiguration(const std::string &path) +bool Configuration::writeIfNeeded(const std::string &path) { - m_userCfgPath = path; - try { - m_userCfg->writeFile(m_userCfgPath.c_str()); - } catch(FileIOException) { - return false; - } - return true; -} + if(!path.empty()) + m_userCfgPath = path; + + if(!changed) + return true; -bool Configuration::writeIfNeeded() -{ try { m_userCfg->writeFile(m_userCfgPath.c_str()); - } catch(FileIOException) { + } catch(const FileIOException &e) { return false; } + + changed = false; return true; } @@ -81,7 +75,7 @@ bool Configuration::parseDefaultConfiguration(const std::string &contents) { try { m_defaultCfg->readString(contents); - } catch(ParseException) { + } catch(const ParseException &e) { return false; } return true; @@ -94,7 +88,8 @@ std::vector Configuration::childrenSettings(const char *name) for(const Setting &setting : root) { if(setting.getType() != Setting::TypeGroup) { - groupNames.push_back(setting.getName()); + groupNames.emplace_back(setting.getName()); + //groupNames.push_back(setting.getName()); } } @@ -108,7 +103,8 @@ std::vector Configuration::childrenGroups(const char *name) for(const Setting &setting : root) { if(setting.getType() == Setting::TypeGroup) { - groupNames.push_back(setting.getName()); + groupNames.emplace_back(setting.getName()); + //groupNames.push_back(setting.getName()); } } return groupNames; @@ -116,139 +112,109 @@ std::vector Configuration::childrenGroups(const char *name) void Configuration::resetValue(const char *path) { - if(m_userCfg->exists(path)) { - Setting &v = m_userCfg->lookup(path); - switch(v.getType()) { - case Setting::TypeNone: - break; - case Setting::TypeInt: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeInt64: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeFloat: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeString: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeBoolean: - v = static_cast(m_defaultCfg->lookup(path)); - break; - case Setting::TypeGroup: - break; - case Setting::TypeArray: - break; - case Setting::TypeList: - break; + if(!m_userCfg->exists(path) && m_defaultCfg->exists(path)) { + // entry doesn't exist, create path to it + // split path into array of items, sep=. + std::string s(path); + std::vector pathTokens; + std::string::size_type prev_pos = 0, pos = 0; + while((pos = s.find('.', pos)) != std::string::npos) { + std::string substring(s.substr(prev_pos, pos - prev_pos)); + pathTokens.push_back(substring); + prev_pos = ++pos; } - } -} + pathTokens.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word -template -std::optional Configuration::value(const char *path) const -{ - // if setting doesn't exist, give back a nullopt - if(!m_userCfg->exists(path)) { - return std::nullopt; + s.clear(); + // iterate through items, creating the path along the way + for(const std::string &t : pathTokens) { + Setting &v = m_userCfg->lookup(s); + Setting &d = m_defaultCfg->lookup(s).lookup(t); + + if(!v.exists(t)) { + v.add(t, d.getType()); + } + + if(s.empty()) + s.append(t); + else + s.append('.' + t); + } } - // setting was found - const Setting &setting = m_userCfg->lookup(path); - std::optional r; + // if the path doesn't exist in the defaultCfg, this will crash - // cast depending on type - // type checks are done during compile time - switch(setting.getType()) { + // entry exists, reset it + Setting &v = m_userCfg->lookup(path); + switch(v.getType()) { case Setting::TypeNone: - r = std::nullopt; break; - case Setting::TypeInt: - // int, unsigned int, long, unsigned long - if constexpr(std::is_same_v) { - r = std::optional(std::to_string(static_cast(setting))); - } else if constexpr(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { - r = std::optional(static_cast(setting)); - } else { - r = std::nullopt; - } + v = static_cast(m_defaultCfg->lookup(path)); break; - case Setting::TypeInt64: - // int, unsigned int; long long, unsigned long long - if constexpr(std::is_same_v) { - r = std::optional(std::to_string(static_cast(setting))); - } else if constexpr(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { - r = std::optional(static_cast(setting)); - } else { - r = std::nullopt; - } + v = static_cast(m_defaultCfg->lookup(path)); break; - case Setting::TypeFloat: - // float, double - if constexpr(std::is_same_v) { - r = std::optional(std::to_string(static_cast(setting))); - } else if constexpr(std::is_same_v || std::is_same_v) { - r = std::optional(static_cast(setting)); - } else { - r = std::nullopt; - } + v = static_cast(m_defaultCfg->lookup(path)); break; - case Setting::TypeString: - // const char*, std::string - if constexpr(std::is_same::value) { - r = std::optional(static_cast(setting)); - } else { - r = std::nullopt; - } + v = static_cast(m_defaultCfg->lookup(path)); break; - case Setting::TypeBoolean: - // bool - if constexpr(std::is_same::value) { - r = std::optional(static_cast(setting) ? "true" : "false"); - } else if constexpr(std::is_same::value) { - r = std::optional(static_cast(setting)); - } else { - r = std::nullopt; - } + v = static_cast(m_defaultCfg->lookup(path)); break; - case Setting::TypeGroup: - r = std::nullopt; break; - case Setting::TypeArray: - r = std::nullopt; break; - case Setting::TypeList: - r = std::nullopt; break; } - return r; + // if it's a string, it may contain a path + if(v.getType() == Setting::TypeString) { + std::string val(static_cast(v)); + v = patchHome(val, m_homePath).c_str(); + } + + changed = true; } -// tell the compiler to export these functions, otherwise you get linking errors -template std::optional Configuration::value(const char *path) const; -template std::optional Configuration::value(const char *path) const; -template std::optional Configuration::value(const char *path) const; -template std::optional Configuration::value(const char *path) const; +std::string Configuration::castToString(const libconfig::Setting &v) const +{ + // cast depending on type + // type checks are done during compile time + switch(v.getType()) { + case Setting::TypeNone: + return std::string(); + + case Setting::TypeInt: + // int, unsigned int, long, unsigned long + return std::to_string(static_cast(v)); -template std::optional Configuration::value(const char *path) const; -template std::optional Configuration::value(const char *path) const; + case Setting::TypeInt64: + // int, unsigned int; long long, unsigned long long + return std::to_string(static_cast(v)); -template std::optional Configuration::value(const char *path) const; -template std::optional Configuration::value(const char *path) const; + case Setting::TypeFloat: + // float, double + return std::to_string(static_cast(v)); + + case Setting::TypeString: + // const char*, std::string + return std::string(static_cast(v)); -template std::optional Configuration::value(const char *path) const; + case Setting::TypeBoolean: + // bool + return std::string(static_cast(v) ? "true" : "false"); -template std::optional Configuration::value(const char *path) const; + case Setting::TypeGroup: + case Setting::TypeArray: + case Setting::TypeList: + return std::string(); + } +} template bool Configuration::setValue(std::string path, const T &val) @@ -319,11 +285,12 @@ template bool Configuration::setValue(std::string path, const bool &val); template bool Configuration::setValue(std::string path, const std::string &val); -std::string &patchHome(std::string &path, const std::string &home) +std::string patchHome(const std::string &path, const std::string &home) { + std::string r = path; const size_t location = path.find('~'); if(location != std::string::npos) { - return path.replace(location, 1, home); + return r.replace(location, 1, home); } - return path; + return r; } diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h index 4fc614e..67ba7b1 100644 --- a/lib/settings/configuration.h +++ b/lib/settings/configuration.h @@ -9,26 +9,20 @@ #ifndef CONFIGURATION_H #define CONFIGURATION_H +#include #include #include #include -namespace libconfig -{ -class Config; -class Setting; -} - class Configuration { public: - Configuration(); + explicit Configuration(const std::string &path, const std::string &home); ~Configuration(); - bool readUserConfiguration(const std::string &path); + bool read(); bool parse(const std::string &contents); - bool writeUserConfiguration(const std::string &path); - bool writeIfNeeded(); + bool writeIfNeeded(const std::string &path = std::string()); bool parseDefaultConfiguration(const std::string &contents); @@ -38,39 +32,39 @@ public: void resetValue(const char *path); template - std::optional value(const char *path) const; + std::optional value(const char *path) const + { + // if setting doesn't exist, give back a nullopt + if(!m_userCfg->exists(path)) { + const_cast(this)->resetValue(path); + return value(path); + } + + const libconfig::Setting &v = m_userCfg->lookup(path); + if constexpr(std::is_same_v) + return std::optional(castToString(v)); + else + return std::optional(static_cast(v)); + } template bool setValue(std::string path, const T &val); private: + std::string castToString(const libconfig::Setting &v) const; + bool changed = false; + std::string m_homePath; std::string m_userCfgPath; libconfig::Config *m_userCfg, *m_defaultCfg; }; // replace ~ with home -std::string &patchHome(std::string &path, const std::string &home); +std::string patchHome(const std::string &path, const std::string &home); // instantiate functions // this needs to be done because the implementation is in the cpp file -// Settings::value<> -extern template std::optional Configuration::value(const char *path) const; -extern template std::optional Configuration::value(const char *path) const; -extern template std::optional Configuration::value(const char *path) const; -extern template std::optional Configuration::value(const char *path) const; - -extern template std::optional Configuration::value(const char *path) const; -extern template std::optional Configuration::value(const char *path) const; - -extern template std::optional Configuration::value(const char *path) const; -extern template std::optional Configuration::value(const char *path) const; - -extern template std::optional Configuration::value(const char *path) const; - -extern template std::optional Configuration::value(const char *path) const; - // Settings::setValue<> extern template bool Configuration::setValue(std::string path, const int &val); extern template bool Configuration::setValue(std::string path, const unsigned int &val); -- cgit v1.2.1