#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)); } static void *allocator_calloc(void *udata, size_t n, size_t sz) { return static_cast(udata)->calloc(n, sz); } static void *allocator_realloc(void *udata, void *ptr, size_t sz) { return static_cast(udata)->realloc(ptr, sz); } static void allocator_free(void *udata, void *ptr) { return static_cast(udata)->free(ptr); } 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); if (m_allocator) { C_settings.allocator_udata = m_allocator.get(); C_settings.calloc = allocator_calloc; C_settings.realloc = allocator_realloc; C_settings.free = allocator_free; } } 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; } class ItemImpl: public Item { public: ItemImpl(const pom_item *C) { m_key = C->key; m_value = C->value; m_file = C->file; m_line = C->line; } virtual ~ItemImpl() {} virtual std::string_view key() const noexcept override { return m_key; } virtual std::string_view value() const noexcept override { return m_value; } virtual std::string_view file() const noexcept override { return m_file; } virtual uint64_t line() const noexcept override { return m_line; } std::string m_key, m_value, m_file; uint64_t m_line; }; 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::shared_ptr(new ItemImpl(item))); } 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 (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 {}; } std::ostream &operator<<(std::ostream &o, const Location &location) { return o << location.file() << ":" << location.line(); } } // namespace pom