/******************************************************************************* ** ** 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; } }