aboutsummaryrefslogtreecommitdiff
path: root/lib/settings
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2018-01-17 13:32:13 +0100
committerAqua-sama <aqua@iserlohn-fortress.net>2018-01-17 13:32:13 +0100
commitd592ee191e8aedc84c670e6d818fcf97c0bd7a92 (patch)
treeb2bd8413332cd1567b9ae954835a7a4c930de730 /lib/settings
parentFixed build scripts for use with the mercurial repository (diff)
downloadsmolbote-d592ee191e8aedc84c670e6d818fcf97c0bd7a92.tar.xz
Configuration creates missing items based on defaults
Diffstat (limited to 'lib/settings')
-rw-r--r--lib/settings/configuration.cpp233
-rw-r--r--lib/settings/configuration.h50
2 files changed, 122 insertions, 161 deletions
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 <libconfig.h++>
+#include <QtCore/QStandardPaths>
#include <sstream>
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<std::string> 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<std::string> 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<std::string> 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<int>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeInt64:
- v = static_cast<long>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeFloat:
- v = static_cast<double>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeString:
- v = static_cast<const char *>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeBoolean:
- v = static_cast<bool>(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<std::string> 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 <typename T>
-std::optional<T> 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<T> 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<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<int>(setting)));
- } else if constexpr(std::is_same_v<T, int> || std::is_same_v<T, unsigned int> || std::is_same_v<T, long> || std::is_same_v<T, unsigned long>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<int>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeInt64:
- // int, unsigned int; long long, unsigned long long
- if constexpr(std::is_same_v<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<long long>(setting)));
- } else if constexpr(std::is_same_v<T, int> || std::is_same_v<T, unsigned int> || std::is_same_v<T, long long> || std::is_same_v<T, unsigned long long>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<long>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeFloat:
- // float, double
- if constexpr(std::is_same_v<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<float>(setting)));
- } else if constexpr(std::is_same_v<T, float> || std::is_same_v<T, double>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<double>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeString:
- // const char*, std::string
- if constexpr(std::is_same<T, std::string>::value) {
- r = std::optional<std::string>(static_cast<const char *>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<const char *>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeBoolean:
- // bool
- if constexpr(std::is_same<T, std::string>::value) {
- r = std::optional<std::string>(static_cast<bool>(setting) ? "true" : "false");
- } else if constexpr(std::is_same<T, bool>::value) {
- r = std::optional<bool>(static_cast<bool>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<bool>(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<const char *>(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<int> Configuration::value<int>(const char *path) const;
-template std::optional<unsigned int> Configuration::value<unsigned int>(const char *path) const;
-template std::optional<long> Configuration::value<long>(const char *path) const;
-template std::optional<unsigned long> Configuration::value<unsigned long>(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<int32_t>(v));
-template std::optional<long long> Configuration::value<long long>(const char *path) const;
-template std::optional<unsigned long long> Configuration::value<unsigned long long>(const char *path) const;
+ case Setting::TypeInt64:
+ // int, unsigned int; long long, unsigned long long
+ return std::to_string(static_cast<int64_t>(v));
-template std::optional<float> Configuration::value<float>(const char *path) const;
-template std::optional<double> Configuration::value<double>(const char *path) const;
+ case Setting::TypeFloat:
+ // float, double
+ return std::to_string(static_cast<double>(v));
+
+ case Setting::TypeString:
+ // const char*, std::string
+ return std::string(static_cast<const char *>(v));
-template std::optional<bool> Configuration::value<bool>(const char *path) const;
+ case Setting::TypeBoolean:
+ // bool
+ return std::string(static_cast<bool>(v) ? "true" : "false");
-template std::optional<std::string> Configuration::value<std::string>(const char *path) const;
+ case Setting::TypeGroup:
+ case Setting::TypeArray:
+ case Setting::TypeList:
+ return std::string();
+ }
+}
template <typename T>
bool Configuration::setValue(std::string path, const T &val)
@@ -319,11 +285,12 @@ template bool Configuration::setValue<bool>(std::string path, const bool &val);
template bool Configuration::setValue<std::string>(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 <libconfig.h++>
#include <optional>
#include <string>
#include <vector>
-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 <typename T>
- std::optional<T> value(const char *path) const;
+ std::optional<T> value(const char *path) const
+ {
+ // if setting doesn't exist, give back a nullopt
+ if(!m_userCfg->exists(path)) {
+ const_cast<Configuration *>(this)->resetValue(path);
+ return value<T>(path);
+ }
+
+ const libconfig::Setting &v = m_userCfg->lookup(path);
+ if constexpr(std::is_same_v<T, std::string>)
+ return std::optional<std::string>(castToString(v));
+ else
+ return std::optional<T>(static_cast<T>(v));
+ }
template <typename T>
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<int> Configuration::value<int>(const char *path) const;
-extern template std::optional<unsigned int> Configuration::value<unsigned int>(const char *path) const;
-extern template std::optional<long> Configuration::value<long>(const char *path) const;
-extern template std::optional<unsigned long> Configuration::value<unsigned long>(const char *path) const;
-
-extern template std::optional<long long> Configuration::value<long long>(const char *path) const;
-extern template std::optional<unsigned long long> Configuration::value<unsigned long long>(const char *path) const;
-
-extern template std::optional<float> Configuration::value<float>(const char *path) const;
-extern template std::optional<double> Configuration::value<double>(const char *path) const;
-
-extern template std::optional<bool> Configuration::value<bool>(const char *path) const;
-
-extern template std::optional<std::string> Configuration::value<std::string>(const char *path) const;
-
// Settings::setValue<>
extern template bool Configuration::setValue<int>(std::string path, const int &val);
extern template bool Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);