diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 27 | ||||
| -rw-r--r-- | configpp.cpp | 84 | ||||
| -rw-r--r-- | configpp.hpp | 94 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | tests/test1.cpp | 19 |
6 files changed, 234 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..394decf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +CMakeLists.txt.user +build* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0d9ab6a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,27 @@ + +cmake_minimum_required(VERSION 3.6.1) +#this is the my current development version, it could probably be lower. + +Project(configpp) + +find_package(Boost COMPONENTS filesystem REQUIRED) + +add_library(configpp SHARED + configpp.hpp configpp.cpp +) + +target_include_directories(configpp + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(configpp + PRIVATE Boost::boost + PRIVATE Boost::filesystem +) + +target_compile_options(configpp + PUBLIC -std=c++14 +) + +enable_testing() +add_subdirectory(tests)
\ No newline at end of file diff --git a/configpp.cpp b/configpp.cpp new file mode 100644 index 0000000..c434979 --- /dev/null +++ b/configpp.cpp @@ -0,0 +1,84 @@ + +#include "configpp.hpp" + +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/property_tree/json_parser.hpp> + +#include <fstream> + +namespace configpp { + +std::unique_ptr<Config> Config::config_ptr = nullptr; + +#if defined( _WIN32 ) || defined( _WIN64 ) +boost::filesystem::path get_config_base_dir() { + if(!std::getenv("APPDATA")) { + throw std::runtime_error("Environment variable \"APPDATA\" is not set, could not find suitable config home."); + } + boost::filesystem::path appdata(std::getenv("APPDATA")); + return appdata +} +#endif + +#if defined( __unix__ ) && !defined( __APPLE__) && !defined( __MACH__ ) +boost::filesystem::path get_config_base_dir() { + boost::filesystem::path config_home; + boost::filesystem::path path; + if(!std::getenv("XDG_CONFIG_HOME")) { + if(!std::getenv("HOME")) { + throw std::runtime_error("Neither \"XDG_CONFIG_HOME\" nor \"HOME\" environment variable are set, could not find suitable config home."); + } else { + config_home = getenv("HOME"); + path = config_home / boost::filesystem::path(".config"); + } + } else { + path = getenv("XDG_CONFIG_HOME"); + } + return path; +} + +#endif + +#if defined( __APPLE__ ) && defined( __MACH__ ) +boost::filesystem::path get_config_base_dir(std::string subdir) { + boost::filesystem::path path; + if(!std::getenv("HOME")) { + throw std::runtime_error("\"HOME\" environment variable is not set, could not find a suitable config home."); + } else { + path = boost::filesystem::path(std::getenv("HOME")); + } + return path; +} +#endif + +using namespace boost::filesystem; + +Config::Config(std::string subdir, std::string filename) +: config() +, subdir(subdir) +, filename(filename) +{ + auto dir = get_config_base_dir() / path(subdir); + auto file_path = dir / filename; + + if(exists(file_path)) { + std::ifstream file_stream(file_path.string()); + boost::property_tree::read_json(file_stream, config); + } +} + +Config::~Config() +{ + auto dir = get_config_base_dir() / path(subdir); + auto file_path = dir / filename; + + if(!exists(dir)) { + boost::filesystem::create_directories(dir); + } + + std::ofstream file_stream(file_path.string()); + boost::property_tree::write_json(file_stream, config); +} + +} //namespace configpp
\ No newline at end of file diff --git a/configpp.hpp b/configpp.hpp new file mode 100644 index 0000000..90038af --- /dev/null +++ b/configpp.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include <boost/property_tree/ptree.hpp> +#include <boost/hana.hpp> + +#include <memory> +#include <type_traits> + +struct X { + int a; + int b; +}; + +BOOST_HANA_ADAPT_STRUCT(X, a, b); + +struct X2 { + int a; + int b; +}; + +namespace configpp { + + struct ConfigStructure{}; + + class Config { + Config(std::string subdir, std::string filename = "config.json"); + + boost::property_tree::ptree config; + std::string subdir; + std::string filename; + + static std::unique_ptr<Config> config_ptr; + + void set(std::string const& key, std::string const& value, boost::property_tree::ptree& base) const { + base.put(key, value); + } + + public: + + Config() = delete; + Config(Config const&) = delete; + Config(Config&&) = delete; + Config& operator=(Config const&) = delete; + Config& operator=(Config&&) = delete; + + ~Config(); + + static Config& get(std::string subdir, std::string filename = "config.json") { + if(!config_ptr) { + config_ptr.reset(new Config(subdir, filename)); + } + return *config_ptr; + } + + void set(std::string const& key, std::string const& value) { + set(key, value, config); + } + + template <typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr> + void set(std::string const & key, T const& value) { + std::ostringstream oss; + oss << value; + + set(key, oss.str()); + } + + template <typename T, typename std::enable_if<boost::hana::Struct<T>::value>::type* = nullptr> + void set(std::string const& key, T const& value) { + auto top_element = config.get_child_optional(key); + + if(!top_element) { + boost::property_tree::ptree array; + config.add_child(key, array); + top_element = config.get_child(key); + } + + boost::hana::for_each(value, boost::hana::fuse([&top_element, this](auto&& key, auto&& value) { + std::ostringstream oss; + oss << value; + + set(boost::hana::to<const char*>(key), oss.str(), *top_element); + })); + } + + template <typename T> + void get(std::string key, T const& value) { + + } + + }; + +} //namespace configpp + +//configpp::Config& config = configpp::Config::get({}); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..1260e05 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,8 @@ +set(CTEST_ENVIRONMENT + "XDG_CONFIG_HOME=${CMAKE_CURRENT_BINARY_DIR}" + "HOME=${CMAKE_CURRENT_BINARY_DIR}" +) + +add_executable(test1 test1.cpp) +target_link_libraries(test1 PRIVATE configpp) +add_test(NAME test1 COMMAND test1)
\ No newline at end of file diff --git a/tests/test1.cpp b/tests/test1.cpp new file mode 100644 index 0000000..fedcb48 --- /dev/null +++ b/tests/test1.cpp @@ -0,0 +1,19 @@ + +#include "configpp.hpp" + +struct Data { + int i; + float f; + std::string str; +}; + +BOOST_HANA_ADAPT_STRUCT(Data, i, f, str); + +int main() { + configpp::Config& config = configpp::Config::get("configpp_test1"); + + config.set("int", 1); + config.set("float", 1.0f); + config.set("string", "yolo"); + config.set("struct", Data{1, 1.0f, "yolo"}); +} |
