diff options
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/examples/read_conf.cpp | 4 | ||||
-rw-r--r-- | cpp/pom.cpp | 167 | ||||
-rw-r--r-- | cpp/pom.hpp | 43 |
3 files changed, 199 insertions, 15 deletions
diff --git a/cpp/examples/read_conf.cpp b/cpp/examples/read_conf.cpp index 0a7ef51..df5d3aa 100644 --- a/cpp/examples/read_conf.cpp +++ b/cpp/examples/read_conf.cpp @@ -3,13 +3,13 @@ int main(void) { try { - pom::Configuration conf = pom::Configuration("conf.pom"); + pom::Configuration conf = pom::Configuration("conf.pom", nullptr); auto indentation_type = conf.get("indentation-type"); if (indentation_type.has_value()) std::cout << "Indenting with " << indentation_type.value() << "\n"; else std::cout << "No indentation type set!\n"; } catch (pom::Error &error) { - std::cerr << error.what() << "\n"; + std::cerr << error << "\n"; } } diff --git a/cpp/pom.cpp b/cpp/pom.cpp index 4e4f7e0..7c2651c 100644 --- a/cpp/pom.cpp +++ b/cpp/pom.cpp @@ -41,10 +41,6 @@ std::string_view Error::message() const noexcept { return pom_error_message(static_cast<const pom_error *>(C)); } -const Error *Error::next() const noexcept { - return m_next.get(); -} - const char *Error::what() const noexcept { return m_is_original ? pom_error_to_string(static_cast<pom_error *>(C)) : pom_error_message(static_cast<const pom_error *>(C)); @@ -54,6 +50,10 @@ 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 { std::string name_str(name); const pom_conf *C_section = pom_conf_section( @@ -74,6 +74,12 @@ static void allocator_free(void *udata, void *ptr) { return static_cast<Allocator *>(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<pom_settings *>(C); strcpy(C_settings.error_lang, m_error_lang); @@ -158,7 +164,7 @@ void Configuration::merge(const Configuration &other) { pom_conf_merge(static_cast<pom_conf *>(C), static_cast<const pom_conf *>(other.C)); } -std::optional<std::string_view> Configuration::get(std::string_view key) const { +std::optional<std::string> Configuration::get(std::string_view key) const { if (!C) return {}; std::string key_str(key); const char *value = pom_conf_get(static_cast<const pom_conf *>(C), key_str.c_str()); @@ -168,8 +174,155 @@ std::optional<std::string_view> Configuration::get(std::string_view key) const { return value; } -std::string_view Configuration::get_or_default(std::string_view key, std::string_view dflt) const { - return get(key).value_or(dflt); +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<std::string> Configuration::unread_keys() const { + std::vector<std::string> unread; + pom_unread_key_iter *iter = nullptr; + const char *key; + while ((key = pom_conf_next_unread_key(static_cast<const pom_conf *>(C), &iter))) { + unread.push_back(key); + } + return unread; +} + +std::vector<std::string> Configuration::keys() const { + std::vector<std::string> keys; + pom_key_iter *iter = nullptr; + const char *key; + while ((key = pom_conf_next_key(static_cast<const pom_conf *>(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<std::shared_ptr<Item>> Configuration::items() const { + std::vector<std::shared_ptr<Item>> items; + pom_item_iter *iter = nullptr; + const pom_item *item; + while ((item = pom_conf_next_item(static_cast<const pom_conf *>(C), &iter))) { + items.push_back(std::shared_ptr<Item>(new ItemImpl(item))); + } + return items; +} + +std::optional<int64_t> Configuration::get_int(std::string_view key) const { + std::string key_str(key); + if (!pom_conf_has(static_cast<const pom_conf *>(C), key_str.c_str())) { + return {}; + } + int64_t value; + pom_error *error = pom_conf_get_int(static_cast<const pom_conf *>(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 { + std::string key_str(key); + int64_t value; + pom_error *error = pom_conf_get_int_or_default(static_cast<const pom_conf *>(C), key_str.c_str(), &value, dflt); + if (error) + throw Error(error); + return value; +} + +std::optional<uint64_t> Configuration::get_uint(std::string_view key) const { + std::string key_str(key); + if (!pom_conf_has(static_cast<const pom_conf *>(C), key_str.c_str())) { + return {}; + } + uint64_t value; + pom_error *error = pom_conf_get_uint(static_cast<const pom_conf *>(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 { + std::string key_str(key); + uint64_t value; + pom_error *error = pom_conf_get_uint_or_default(static_cast<const pom_conf *>(C), key_str.c_str(), &value, dflt); + if (error) + throw Error(error); + return value; +} + +std::optional<double> Configuration::get_float(std::string_view key) const { + std::string key_str(key); + if (!pom_conf_has(static_cast<const pom_conf *>(C), key_str.c_str())) { + return {}; + } + double value; + pom_error *error = pom_conf_get_float(static_cast<const pom_conf *>(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 { + std::string key_str(key); + double value; + pom_error *error = pom_conf_get_float_or_default(static_cast<const pom_conf *>(C), key_str.c_str(), &value, dflt); + if (error) + throw Error(error); + return value; +} + +std::optional<bool> Configuration::get_bool(std::string_view key) const { + std::string key_str(key); + if (!pom_conf_has(static_cast<const pom_conf *>(C), key_str.c_str())) { + return {}; + } + bool value; + pom_error *error = pom_conf_get_bool(static_cast<const pom_conf *>(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 { + std::string key_str(key); + bool value; + pom_error *error = pom_conf_get_bool_or_default(static_cast<const pom_conf *>(C), key_str.c_str(), &value, dflt); + if (error) + throw Error(error); + return value; +} + +Configuration &Configuration::operator=(const Configuration &other) { + C = static_cast<void *>(pom_conf_copy(static_cast<const pom_conf *>(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; +} + + } // namespace pom diff --git a/cpp/pom.hpp b/cpp/pom.hpp index bf16a29..f9d7475 100644 --- a/cpp/pom.hpp +++ b/cpp/pom.hpp @@ -4,6 +4,8 @@ #include <exception> #include <cstdint> #include <string_view> +#include <string> +#include <vector> #include <memory> #include <optional> @@ -12,10 +14,11 @@ namespace pom { class Error: public std::exception { public: ~Error(); + Error(Error &other) = delete; std::string_view file() const noexcept; uint64_t line() const noexcept; std::string_view message() const noexcept; - const Error *next() const noexcept; + inline const Error *next() const noexcept { return m_next.get(); } std::string_view to_string() noexcept; /// You should only call this on the first error in an error list. /// (This can't be enforced with constness because it needs to @@ -31,10 +34,11 @@ private: bool m_is_original; std::unique_ptr<const Error> m_next; }; +std::ostream &operator<<(std::ostream &, Error &); class Allocator { public: - virtual ~Allocator() = 0; + inline virtual ~Allocator() {}; virtual void *calloc(size_t, size_t) = 0; virtual void *realloc(void *, size_t) = 0; virtual void free(void *) = 0; @@ -42,9 +46,9 @@ public: class Settings { public: - Settings(); + inline Settings() {}; /// Set allocator. - void set_allocator(std::shared_ptr<Allocator> allocator) { + inline void set_allocator(std::shared_ptr<Allocator> allocator) { m_allocator = allocator; } void set_error_language(std::string_view lang); @@ -61,22 +65,49 @@ public: virtual size_t read(char *buf, size_t count) = 0; }; +/// An item in a configuration +/// +/// This is an abstract class so that items can be given +/// more members in the future. +class Item { +public: + inline virtual ~Item() {}; + virtual std::string_view key() const noexcept = 0; + virtual std::string_view value() const noexcept = 0; + virtual std::string_view file() const noexcept = 0; + virtual uint64_t line() const noexcept = 0; +}; + class Configuration { public: Configuration(); + Configuration &operator=(const Configuration &other); + inline Configuration(const Configuration &other) { *this = other; }; Configuration(std::string_view filename, Reader &source, const Settings *settings = nullptr); Configuration(std::string_view filename, std::istream &stream, const Settings *settings = nullptr); Configuration(std::string_view path, const Settings *settings = nullptr); Configuration(std::string_view filename, std::string_view string, const Settings *settings = nullptr); ~Configuration(); - std::optional<std::string_view> get(std::string_view key) const; - std::string_view get_or_default(std::string_view key, std::string_view dflt) const; + std::optional<std::string> get(std::string_view key) const; + std::string get_or_default(std::string_view key, std::string_view dflt) const; + std::optional<int64_t> get_int(std::string_view key) const; + int64_t get_int_or_default(std::string_view key, int64_t dflt) const; + std::optional<uint64_t> get_uint(std::string_view key) const; + uint64_t get_uint_or_default(std::string_view key, uint64_t dflt) const; + std::optional<double> get_float(std::string_view key) const; + double get_float_or_default(std::string_view key, double dflt) const; + std::optional<bool> get_bool(std::string_view key) const; + bool get_bool_or_default(std::string_view key, bool dflt) const; Configuration section(std::string_view name) const; + std::vector<std::string> unread_keys() const; + std::vector<std::string> keys() const; + std::vector<std::shared_ptr<Item>> items() const; void merge(const Configuration &other); private: explicit Configuration(void *c): C(c) {} void *C; }; +std::ostream &operator<<(std::ostream &, const Configuration &); |