summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-16 15:02:39 -0400
committerpommicket <pommicket@gmail.com>2025-09-16 15:02:39 -0400
commit7ededc16f36099acbfac457f8e4e268879b0ce62 (patch)
tree35543f851383a5002566b3b0a8ea5f38d97e94c7
parent76f68d6c93b55f9cd96a369bf2e5785ed16fa184 (diff)
Finish up implementation of C++ library
-rw-r--r--cpp/examples/read_conf.cpp4
-rw-r--r--cpp/pom.cpp167
-rw-r--r--cpp/pom.hpp43
-rw-r--r--examples/Makefile4
4 files changed, 199 insertions, 19 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 &);
diff --git a/examples/Makefile b/examples/Makefile
deleted file mode 100644
index 18bb7a5..0000000
--- a/examples/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-PROFILE?=release
-build/read_conf: read_conf.c ../$(PROFILE)/libpom.a
- @mkdir -p build
- $(CC) -I.. -Wall -o $@ read_conf.c ../$(PROFILE)/libpom.a