From a6160dc890262bbf4a0504ec3a3df6556275c60e Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Thu, 30 Nov 2017 14:07:47 +0100 Subject: libconfig test --- lib/settings/configuration.cpp | 244 +++++++++++++++++++++++++++++++++++++++++ lib/settings/configuration.h | 92 ++++++++++++++++ lib/settings/settings.qbs | 18 +++ 3 files changed, 354 insertions(+) create mode 100644 lib/settings/configuration.cpp create mode 100644 lib/settings/configuration.h create mode 100644 lib/settings/settings.qbs (limited to 'lib') diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp new file mode 100644 index 0000000..543ea60 --- /dev/null +++ b/lib/settings/configuration.cpp @@ -0,0 +1,244 @@ +/******************************************************************************* + ** + ** nyamp: yet another media player + ** Copyright (C) 2017 Aqua-sama + ** + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program. If not, see . + ** + ******************************************************************************/ + +#include "configuration.h" +#include +#include + +Configuration::Configuration() +{ + m_userCfg = new libconfig::Config(); + m_defaultCfg = new libconfig::Config(); +} + +Configuration::~Configuration() +{ + if(!m_userCfgPath.empty()) { + m_userCfg->writeFile(m_userCfgPath.c_str()); + } + + delete m_userCfg; + delete m_defaultCfg; +} + +bool Configuration::readUserConfiguration(const std::string &path) +{ + m_userCfgPath = path; + try { + m_userCfg->readFile(path.c_str()); + } catch (libconfig::FileIOException) { + return false; + } catch (libconfig::ParseException) { + return false; + } + return true; +} + +bool Configuration::readDefaultConfiguration(const std::string &data) +{ + try { + m_defaultCfg->readString(data); + } catch(libconfig::ParseException) { + return false; + } + return true; +} + +std::vector Configuration::children(const char* name) +{ + std::vector groupNames; + const libconfig::Setting &root = m_defaultCfg->lookup(name); + + for(auto i = root.begin(); i != root.end(); ++i) { + groupNames.push_back(std::string(i->getName())); + } + + return groupNames; +} + +template +std::optional Configuration::value(const char* path) const +{ + libconfig::Config *conf = getConfig(path); + if(conf == nullptr) { + return std::nullopt; + } + + // setting was found + const libconfig::Setting &setting = conf->lookup(path); + std::optional r; + + // cast depending on type + // type checks are done during compile time + switch (setting.getType()) { + case libconfig::Setting::TypeNone: + r = std::nullopt; + break; + + case libconfig::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; + } + break; + + case libconfig::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; + } + break; + + case libconfig::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; + } + break; + + case libconfig::Setting::TypeString: + // const char*, std::string + if constexpr(std::is_same::value) { + r = std::optional(static_cast(setting)); + } else { + r = std::nullopt; + } + break; + + case libconfig::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; + } + break; + + case libconfig::Setting::TypeGroup: + r = std::nullopt; + break; + + case libconfig::Setting::TypeArray: + r = std::nullopt; + break; + + case libconfig::Setting::TypeList: + r = std::nullopt; + break; + } + + return r; +} + +// 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; + +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; + +template std::optional Configuration::value(const char* path) const; + +template std::optional Configuration::value(const char* path) const; + +template +void Configuration::setValue(std::string path, const T &val) +{ + if(m_userCfg->exists(path)) { + libconfig::Setting &setting = m_userCfg->lookup(path); + // compiler complained about operator= not taking unsinged ints, longs and long longs + if constexpr(std::is_unsigned_v && !std::is_same_v) { + setting = static_cast>(val); + } else { + setting = val; + } + return; + } + + // the entry doesn't exist, so we need to create it + // libconfig can't create an entry from a path, we need to get its root, and then add it + + // this will error out if entry being added is not in the default config + + std::istringstream p(path); + libconfig::Setting *userSetting = &m_userCfg->getRoot(); + libconfig::Setting *defaultSetting = &m_defaultCfg->getRoot(); + + std::string i; + while (std::getline(p, i, '.')) { + defaultSetting = &defaultSetting->lookup(i); + // check if user setting exists, if not, create it + if(!userSetting->exists(i)) { + userSetting = &userSetting->add(i, defaultSetting->getType()); + } + } + + if constexpr(std::is_unsigned_v && !std::is_same_v) { + *userSetting = static_cast>(val); + } else { + *userSetting = val; + } + +} + +template void Configuration::setValue(std::string path, const int &val); +template void Configuration::setValue(std::string path, const unsigned int &val); +template void Configuration::setValue(std::string path, const long &val); +template void Configuration::setValue(std::string path, const unsigned long &val); + +template void Configuration::setValue(std::string path, const long long &val); +template void Configuration::setValue(std::string path, const unsigned long long &val); + +template void Configuration::setValue(std::string path, const float &val); +template void Configuration::setValue(std::string path, const double &val); + +template void Configuration::setValue(std::string path, const bool &val); + +template void Configuration::setValue(std::string path, const std::string &val); + +libconfig::Config *Configuration::getConfig(const char* path) const +{ + if(m_userCfg->exists(path)) { + return m_userCfg; + } else if(m_defaultCfg->exists(path)) { + return m_defaultCfg; + } else { + return nullptr; + } +} diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h new file mode 100644 index 0000000..e0f1872 --- /dev/null +++ b/lib/settings/configuration.h @@ -0,0 +1,92 @@ +/******************************************************************************* + ** + ** nyamp: yet another media player + ** Copyright (C) 2017 Aqua-sama + ** + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program. If not, see . + ** + ******************************************************************************/ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +namespace libconfig { +class Config; +class Setting; +} + +class Configuration +{ +public: + Configuration(); + ~Configuration(); + + bool readUserConfiguration(const std::string &path); + bool readDefaultConfiguration(const std::string &data); + + std::vector children(const char *name = ""); + + template + std::optional value(const char* path) const; + + template + void setValue(std::string path, const T &val); + +private: + libconfig::Config* getConfig(const char* path) const; + + std::string m_userCfgPath; + libconfig::Config *m_userCfg; + libconfig::Config *m_defaultCfg; +}; + +// 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 void Configuration::setValue(std::string path, const int &val); +extern template void Configuration::setValue(std::string path, const unsigned int &val); +extern template void Configuration::setValue(std::string path, const long &val); +extern template void Configuration::setValue(std::string path, const unsigned long &val); + +extern template void Configuration::setValue(std::string path, const long long &val); +extern template void Configuration::setValue(std::string path, const unsigned long long &val); + +extern template void Configuration::setValue(std::string path, const float &val); +extern template void Configuration::setValue(std::string path, const double &val); + +extern template void Configuration::setValue(std::string path, const bool &val); + +extern template void Configuration::setValue(std::string path, const std::string &val); + +#endif // SETTINGS_H diff --git a/lib/settings/settings.qbs b/lib/settings/settings.qbs new file mode 100644 index 0000000..e49339f --- /dev/null +++ b/lib/settings/settings.qbs @@ -0,0 +1,18 @@ +import qbs + +Project { + name: "Settings" + + StaticLibrary { + name: "settings" + + Depends { name: "cpp" } + + cpp.cxxLanguageVersion: "c++17" + + files: [ + "configuration.cpp", + "configuration.h" + ] + } +} -- cgit v1.2.1