#include "pom.hpp" #include #include #include #include #include #include namespace pom { Configuration::~Configuration() { pom_conf_free(static_cast(C)); } Configuration::Configuration(): C(nullptr) {} Error::~Error() { if (m_is_original) free(C); } Error::Error(void *C_error): C(C_error), m_is_original(true) { const pom_error *next = pom_error_next(static_cast(C)); if (next) m_next = std::unique_ptr(new Error(static_cast(next))); } // const_cast here to avoid creating a separate ConstError type Error::Error(const void *C_error): C(const_cast(C_error)), m_is_original(false) { const pom_error *next = pom_error_next(static_cast(C)); if (next) m_next = std::unique_ptr(new Error(static_cast(next))); } std::string_view Error::file() const noexcept { return pom_error_file(static_cast(C)); } uint64_t Error::line() const noexcept { return pom_error_line(static_cast(C)); } std::string_view Error::message() const noexcept { return pom_error_message(static_cast(C)); } const char *Error::what() const noexcept { return m_is_original ? pom_error_to_string(static_cast(C)) : pom_error_message(static_cast(C)); } std::string_view Error::to_string() noexcept { return what(); } std::ostream &operator<<(std::ostream &o, Error &e) { return o << e.to_string(); } Configuration Configuration::section(std::string_view name) const { if (!C) return {}; std::string name_str(name); const pom_conf *C_section = pom_conf_section( static_cast(C), name_str.c_str()); pom_conf *C_section_copy = pom_conf_copy(C_section); return Configuration(static_cast(C_section_copy)); } void Settings::set_error_language(std::string_view lang) { size_t len = std::min(sizeof m_error_lang - 1, lang.size()); memcpy(m_error_lang, lang.data(), len); m_error_lang[len] = 0; } void Settings::to_C(void *C) const { pom_settings &C_settings = *static_cast(C); strcpy(C_settings.error_lang, m_error_lang); } static size_t readable_read(void *udata, char *buf, size_t count) { return static_cast(udata)->read(buf, count); } void Configuration::load(std::string_view filename, Reader &source, const Settings *settings) { pom_settings C_settings = {}; if (settings) { settings->to_C(static_cast(&C_settings)); } pom_error *error; std::string filename_str(filename); C = pom_load(&C_settings, filename_str.c_str(), readable_read, &source, &error); if (error) { throw Error(static_cast(error)); } } Configuration::Configuration(std::string_view filename, Reader &source, const Settings *settings) { load(filename, source, settings); } Configuration::Configuration(std::string_view path, const Settings *settings) { pom_settings C_settings = {}; if (settings) { settings->to_C(static_cast(&C_settings)); } pom_error *error; std::string path_str(path); C = pom_load_path(&C_settings, path_str.c_str(), &error); if (error) { throw Error(static_cast(error)); } } class StringViewReader: public Reader { public: explicit StringViewReader(std::string_view v): string(v) {} virtual size_t read(char *buf, size_t count) { count = std::min(count, string.size()); memcpy(buf, string.data(), count); return count; } private: std::string_view string; }; Configuration::Configuration(std::string_view filename, std::string_view string, const Settings *settings) { StringViewReader reader(string); load(filename, reader, settings); } class IStreamReader: public Reader { public: explicit IStreamReader(std::istream &stream): ifstream(stream) {} virtual size_t read(char *buf, size_t count) { ifstream.read(buf, count); return ifstream.gcount(); } private: std::istream &ifstream; }; Configuration::Configuration(std::string_view filename, std::istream &stream, const Settings *settings) { IStreamReader reader(stream); load(filename, reader, settings); } void Configuration::merge(const Configuration &other) { if (!other.C) return; if (!C) { C = pom_conf_copy(static_cast(other.C)); return; } pom_conf_merge(static_cast(C), static_cast(other.C)); } std::optional Configuration::get(std::string_view key) const { if (!C) return {}; std::string key_str(key); const char *value = pom_conf_get(static_cast(C), key_str.c_str()); if (!value) return {}; else return value; } std::string Configuration::get_or_default(std::string_view key, std::string_view dflt) const { auto value = get(key); if (value.has_value()) return value.value(); else return std::string(dflt); } std::vector Configuration::unread_keys() const { if (!C) return {}; std::vector unread; pom_unread_key_iter *iter = nullptr; const char *key; while ((key = pom_conf_next_unread_key(static_cast(C), &iter))) { unread.push_back(key); } return unread; } std::vector Configuration::keys() const { if (!C) return {}; std::vector keys; pom_key_iter *iter = nullptr; const char *key; while ((key = pom_conf_next_key(static_cast(C), &iter))) { keys.push_back(key); } return keys; } std::vector> Configuration::items() const { if (!C) return {}; std::vector> items; pom_item_iter *iter = nullptr; const pom_item *item; while ((item = pom_conf_next_item(static_cast(C), &iter))) { items.push_back(std::unique_ptr(new Item(item->key, item->value, item->file, item->line))); } return items; } std::optional Configuration::get_int(std::string_view key) const { if (!C) return {}; std::string key_str(key); if (!pom_conf_has(static_cast(C), key_str.c_str())) { return {}; } int64_t value; pom_error *error = pom_conf_get_int(static_cast(C), key_str.c_str(), &value); if (error) throw Error(error); return value; } int64_t Configuration::get_int_or_default(std::string_view key, int64_t dflt) const { return get_int(key).value_or(dflt); } std::optional Configuration::get_uint(std::string_view key) const { if (!C) return {}; std::string key_str(key); if (!pom_conf_has(static_cast(C), key_str.c_str())) { return {}; } uint64_t value; pom_error *error = pom_conf_get_uint(static_cast(C), key_str.c_str(), &value); if (error) throw Error(error); return value; } uint64_t Configuration::get_uint_or_default(std::string_view key, uint64_t dflt) const { return get_uint(key).value_or(dflt); } std::optional Configuration::get_float(std::string_view key) const { if (!C) return {}; std::string key_str(key); if (!pom_conf_has(static_cast(C), key_str.c_str())) { return {}; } double value; pom_error *error = pom_conf_get_float(static_cast(C), key_str.c_str(), &value); if (error) throw Error(error); return value; } double Configuration::get_float_or_default(std::string_view key, double dflt) const { return get_float(key).value_or(dflt); } std::optional Configuration::get_bool(std::string_view key) const { if (!C) return {}; std::string key_str(key); if (!pom_conf_has(static_cast(C), key_str.c_str())) { return {}; } bool value; pom_error *error = pom_conf_get_bool(static_cast(C), key_str.c_str(), &value); if (error) throw Error(error); return value; } bool Configuration::get_bool_or_default(std::string_view key, bool dflt) const { return get_bool(key).value_or(dflt); } std::optional> Configuration::get_list(std::string_view key) const { if (!C) return {}; std::string key_str(key); char **list = pom_conf_get_list(static_cast(C), key_str.c_str()); std::vector vec; for (size_t i = 0; list[i]; i++) vec.emplace_back(list[i]); free(list); return vec; } std::vector Configuration::get_list_or_default(std::string_view key, const std::vector &dflt) const { auto list = get_list(key); if (list.has_value()) return list.value(); else return dflt; } Configuration &Configuration::operator=(const Configuration &other) { pom_conf_free(static_cast(C)); C = static_cast(pom_conf_copy(static_cast(other.C))); return *this; } std::ostream &operator<<(std::ostream &o, const Configuration &conf) { for (const auto &item: conf.items()) o << item->key() << ": " << item->value() << "\n"; return o; } std::optional Configuration::location(std::string_view key) const { if (!C) return {}; const char *file; uint64_t line; std::string key_str(key); if (pom_conf_location(static_cast(C), key_str.c_str(), &file, &line)) return Location(file, line); else return {}; } bool Configuration::has(std::string_view key) const { if (!C) return false; std::string key_str(key); return pom_conf_has(static_cast(C), key_str.c_str()); } std::ostream &operator<<(std::ostream &o, const Location &location) { return o << location.file() << ":" << location.line(); } } // namespace pom