From e0ea4d7a7b19f1a1f541ee8cb37077f525e9f179 Mon Sep 17 00:00:00 2001 From: tastytea Date: Fri, 10 Aug 2018 02:22:06 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + CMakeLists.txt | 41 ++++++++++++++++++ README.md | 30 ++++++++++++++ src/example.cpp | 22 ++++++++++ src/xdgcfg.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ src/xdgcfg.hpp | 87 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 src/example.cpp create mode 100644 src/xdgcfg.cpp create mode 100644 src/xdgcfg.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a9cf5ab --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required (VERSION 3.7) +project(xdgcfg + VERSION 0.1.0 + LANGUAGES CXX +) + +include(GNUInstallDirs) +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir) +pkg_check_modules(LIBCONFIG REQUIRED libconfig++) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") + +include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS}) +include_directories(${LIBCONFIG_INCLUDE_DIRS}) + +link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS}) +link_directories(${LIBCONFIG_LIBRARY_DIRS}) + +add_library(xdgcfg SHARED src/xdgcfg.cpp) +set_target_properties(xdgcfg PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${xdgcfg_VERSION_MAJOR}) +target_link_libraries(xdgcfg + ${LIBXDG_BASEDIR_LIBRARIES} ${LIBCONFIG_LIBRARIES} + stdc++fs) + +add_library(xdgcfg_static STATIC src/xdgcfg.cpp) +set_target_properties(xdgcfg_static PROPERTIES + OUTPUT_NAME xdgcfg) + +add_executable(example src/example.cpp) +target_link_libraries(example xdgcfg) + +install(TARGETS xdgcfg LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS xdgcfg_static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(FILES src/xdgcfg.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/README.md b/README.md new file mode 100644 index 0000000..92ac7ab --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +**xdgcfg** is a very simple wrapper around libconfig written in C++. It reads +and writes files into `${XDG_CONFIG_HOME}`. It creates subdirectories if +necessary. + +### Dependencies + +* C++ compiler +* [cmake](https://cmake.org/) +* [pkgconfig](https://pkgconfig.freedesktop.org/wiki/) +* [libconfig++](https://github.com/hyperrealm/libconfig) +* [libxdg-basedir](http://repo.or.cz/w/libxdg-basedir.git) + +### Usage + +You can create dynamic and static libraries: + +```SH +mkdir build +cd build +cmake .. +make +make install +``` + +Or just copy `xdgcfg.hpp` and `xdgcfg.cpp` into your project folder. + +### Documentation + +`xdgcfg.hpp` has explanatory comments in it and there is an +[example](src/example.cpp). diff --git a/src/example.cpp b/src/example.cpp new file mode 100644 index 0000000..31f7f2c --- /dev/null +++ b/src/example.cpp @@ -0,0 +1,22 @@ +#include +#include +#include "xdgcfg.hpp" + +int main(int argc, char *argv[]) +{ + xdgcfg config("test.cfg", "xdgcfg"); + config.set_verbose(true); + if (config.read() != 0) + { + config.write(); + } + libconfig::Config &cfg = config.get_cfg(); + libconfig::Setting &root = cfg.getRoot(); + if (!root.exists("Hello")) + { + root.add("Hello", libconfig::Setting::TypeString) = "World"; + } + config.write(); + + std::cout << "Hello: " << root["Hello"].c_str() << std::endl; +} diff --git a/src/xdgcfg.cpp b/src/xdgcfg.cpp new file mode 100644 index 0000000..a79969c --- /dev/null +++ b/src/xdgcfg.cpp @@ -0,0 +1,108 @@ +/* Public Domain / CC-0 + * Author: tastytea + */ + +#if __cplusplus >= 201703L + #include +#else + #include +#endif +#include +#include +#include "xdgcfg.hpp" + +#if __cplusplus >= 201703L + namespace fs = std::filesystem; +#else + namespace fs = std::experimental::filesystem; +#endif + +using std::cerr; +using std::endl; + +xdgcfg::xdgcfg(const string &filename, const string &subdir) +: _cfg() +, _verbose(false) +{ + xdgHandle xdg; + xdgInitHandle(&xdg); + _filepath = xdgConfigHome(&xdg); + xdgWipeHandle(&xdg); + + if (!subdir.empty()) + { + _filepath += '/' + subdir; + if (!fs::exists(_filepath)) + { + fs::create_directory(_filepath); + } + } + _filepath += '/' + filename; +} + +const uint_fast8_t xdgcfg::read() +{ + try + { + _cfg.readFile(_filepath.c_str()); + } + catch (const libconfig::FileIOException &e) + { + if (_verbose) + { + cerr << "I/O error while reading " << _filepath + << " - " << e.what() << endl; + } + return 1; + } + catch (const libconfig::ParseException &e) + { + if (_verbose) + { + cerr << "Parse error at " << e.getFile() << ":" << e.getLine() + << " - " << e.getError() << endl; + } + return 2; + } + + return 0; +} + +const bool xdgcfg::write() +{ + try + { + _cfg.writeFile(_filepath.c_str()); + } + catch (const libconfig::FileIOException &e) + { + if (_verbose) + { + cerr << "I/O error while writing " << _filepath + << " - " << e.what() << endl; + } + return false; + } + + return true; +} + +libconfig::Config &xdgcfg::get_cfg() +{ + return _cfg; +} + +const string xdgcfg::get_filepath() const +{ + return _filepath; +} + +const void xdgcfg::set_verbose(bool verbose) +{ + _verbose = verbose; +} + +const bool xdgcfg::get_verbose() const +{ + return _verbose; +} diff --git a/src/xdgcfg.hpp b/src/xdgcfg.hpp new file mode 100644 index 0000000..a21a2ea --- /dev/null +++ b/src/xdgcfg.hpp @@ -0,0 +1,87 @@ +/* Public Domain / CC-0 + * Author: tastytea + */ + +#ifndef XDGCFG_HPP +#define XDGCFG_HPP + +#include +#include +#include + +using std::string; +using std::uint_fast8_t; + +class xdgcfg +{ +public: + /*! + * @brief Checks if subdir is present, creates it if necessary + * + * Example: + * @code + * xdgcfg config("test.cfg", "subdirectory"); + * @endcode + * + * @param filename The name of the file, including extension + * @param subdir The subdir (optional) + */ + explicit xdgcfg(const string &filename, const string &subdir = ""); + + /*! + * @brief Read the file + * + * @return 0 on success, 1 on I/O error, 2 on parse error. + */ + const uint_fast8_t read(); + + /*! + * @brief Write the file + * + * @return `true` on success + */ + const bool write(); + + /*! + * @brief Returns a reference to the config as libconfig::Config + * + * Example: + * @code + * libconfig::Config &cfg = config.get_cfg(); + * @endcode + */ + libconfig::Config &get_cfg(); + + /*! + * @brief Returns the complete filepath + */ + const string get_filepath() const; + + /*! + * @brief Sets verbosity + */ + const void set_verbose(bool verbose); + + /*! + * @brief Returns verbosity + */ + const bool get_verbose() const; + +private: + /*! + * Holds the contents of the CFG file + */ + libconfig::Config _cfg; + + /*! + * Complete filepath + */ + string _filepath; + + /*! + * Print out error messages if true + */ + bool _verbose; +}; + +#endif // XDGCFG_HPP