aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/settings/configuration.cpp244
-rw-r--r--lib/settings/configuration.h92
-rw-r--r--lib/settings/settings.qbs18
3 files changed, 354 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+ **
+ ******************************************************************************/
+
+#include "configuration.h"
+#include <libconfig.h++>
+#include <sstream>
+
+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<std::string> Configuration::children(const char* name)
+{
+ std::vector<std::string> 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<typename T>
+std::optional<T> 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<T> 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<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;
+ }
+ break;
+
+ case libconfig::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;
+ }
+ break;
+
+ case libconfig::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;
+ }
+ break;
+
+ case libconfig::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;
+ }
+ break;
+
+ case libconfig::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;
+ }
+ 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<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;
+
+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;
+
+template std::optional<float> Configuration::value<float>(const char* path) const;
+template std::optional<double> Configuration::value<double>(const char* path) const;
+
+template std::optional<bool> Configuration::value<bool>(const char* path) const;
+
+template std::optional<std::string> Configuration::value<std::string>(const char* path) const;
+
+template<typename T>
+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<T> && !std::is_same_v<T, bool>) {
+ setting = static_cast<typename std::make_signed_t<T>>(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<T> && !std::is_same_v<T, bool>) {
+ *userSetting = static_cast<typename std::make_signed_t<T>>(val);
+ } else {
+ *userSetting = val;
+ }
+
+}
+
+template void Configuration::setValue<int>(std::string path, const int &val);
+template void Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);
+template void Configuration::setValue<long>(std::string path, const long &val);
+template void Configuration::setValue<unsigned long>(std::string path, const unsigned long &val);
+
+template void Configuration::setValue<long long>(std::string path, const long long &val);
+template void Configuration::setValue<unsigned long long>(std::string path, const unsigned long long &val);
+
+template void Configuration::setValue<float>(std::string path, const float &val);
+template void Configuration::setValue<double>(std::string path, const double &val);
+
+template void Configuration::setValue<bool>(std::string path, const bool &val);
+
+template void Configuration::setValue<std::string>(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 <http://www.gnu.org/licenses/>.
+ **
+ ******************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <optional>
+#include <vector>
+
+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<std::string> children(const char *name = "");
+
+ template<typename T>
+ std::optional<T> value(const char* path) const;
+
+ template<typename T>
+ 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<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 void Configuration::setValue<int>(std::string path, const int &val);
+extern template void Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);
+extern template void Configuration::setValue<long>(std::string path, const long &val);
+extern template void Configuration::setValue<unsigned long>(std::string path, const unsigned long &val);
+
+extern template void Configuration::setValue<long long>(std::string path, const long long &val);
+extern template void Configuration::setValue<unsigned long long>(std::string path, const unsigned long long &val);
+
+extern template void Configuration::setValue<float>(std::string path, const float &val);
+extern template void Configuration::setValue<double>(std::string path, const double &val);
+
+extern template void Configuration::setValue<bool>(std::string path, const bool &val);
+
+extern template void Configuration::setValue<std::string>(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"
+ ]
+ }
+}