summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--Doxyfile2
-rw-r--r--cpp/Doxyfile2
-rw-r--r--cpp/pom.cpp31
-rw-r--r--cpp/pom.hpp118
5 files changed, 118 insertions, 41 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4a44c39..4a3b896 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,12 @@
-cmake_minimum_required(VERSION 3.0...3.31)
+# NB: ≥3.8 required for C++17
+cmake_minimum_required(VERSION 3.8...3.31)
project(pom)
option(LIBPOM_CXX "Build C++ library" ON)
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
+
if (MSVC)
add_compile_options(/W4)
else()
diff --git a/Doxyfile b/Doxyfile
index f70c18f..fc5e9d6 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -20,7 +20,7 @@ AUTOLINK_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = YES
EXTRACT_STATIC = YES
COLLABORATION_GRAPH = NO
-WARN_IF_UNDOCUMENTED = NO
+WARN_IF_UNDOCUMENTED = YES
QUIET = YES
INCLUDE_GRAPH = NO
WARN_AS_ERROR = FAIL_ON_WARNINGS
diff --git a/cpp/Doxyfile b/cpp/Doxyfile
index 03da967..5c4d038 100644
--- a/cpp/Doxyfile
+++ b/cpp/Doxyfile
@@ -19,7 +19,7 @@ AUTOLINK_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = YES
EXTRACT_STATIC = YES
COLLABORATION_GRAPH = NO
-WARN_IF_UNDOCUMENTED = NO
+WARN_IF_UNDOCUMENTED = YES
QUIET = YES
INCLUDE_GRAPH = NO
WARN_AS_ERROR = FAIL_ON_WARNINGS
diff --git a/cpp/pom.cpp b/cpp/pom.cpp
index 058040e..29dc7e1 100644
--- a/cpp/pom.cpp
+++ b/cpp/pom.cpp
@@ -192,30 +192,13 @@ std::vector<std::string> Configuration::keys() const {
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::unique_ptr<Item>> Configuration::items() const {
if (!C) return {};
- std::vector<std::shared_ptr<Item>> items;
+ std::vector<std::unique_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)));
+ items.push_back(std::unique_ptr<Item>(new Item(item->key, item->value, item->file, item->line)));
}
return items;
}
@@ -314,7 +297,7 @@ Configuration &Configuration::operator=(const Configuration &other) {
}
std::ostream &operator<<(std::ostream &o, const Configuration &conf) {
- for (auto item: conf.items())
+ for (const auto &item: conf.items())
o << item->key() << ": " << item->value() << "\n";
return o;
}
@@ -330,6 +313,12 @@ std::optional<Location> Configuration::location(std::string_view key) const {
return {};
}
+bool Configuration::has(std::string_view key) const {
+ if (!C) return false;
+ std::string key_str(key);
+ return pom_conf_has(static_cast<const pom_conf *>(C), key_str.c_str());
+}
+
std::ostream &operator<<(std::ostream &o, const Location &location) {
return o << location.file() << ":" << location.line();
}
diff --git a/cpp/pom.hpp b/cpp/pom.hpp
index 4e20727..ba65b25 100644
--- a/cpp/pom.hpp
+++ b/cpp/pom.hpp
@@ -42,6 +42,7 @@
#include <memory>
#include <optional>
+/// libpom++ namespace
namespace pom {
/// A libpom++ error.
@@ -100,12 +101,11 @@ public:
inline Settings() {}
/// Set language for error messages.
///
- /// `lang` should be an IETF-like language tag.
+ /// Currently supported languages: `en`, `fr`.
///
+ /// \param lang IETF-like language tag.
/// The closest supported language will be used
/// (e.g. `fr-CA` will currently redirect to `fr`).
- ///
- /// Currently supported: `en`, `fr`.
void set_error_language(std::string_view lang);
private:
void check_version() const;
@@ -122,25 +122,51 @@ private:
class Reader {
public:
/// Read up to `count` bytes of data into `buf`.
+ ///
+ /// This method will not be called excessively/with lots of tiny reads—it's
+ /// okay to do unbuffered reads in it.
+ ///
+ /// \param buf Place to put data.
+ /// \param count (Non-zero) number of bytes to read
+ ///
+ /// \returns 0 to indicate the end of the file,
+ /// or a positive value ≤ `count`, to indicate the number of bytes read.
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.
+/// An item in a configuration (returned by \ref Configuration::items).
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;
+ /// Name of the key.
+ ///
+ /// The returned string view is valid for the lifetime of `this`.
+ std::string_view key() const noexcept { return m_key; }
+ /// Value of the key.
+ ///
+ /// The returned string view is valid for the lifetime of `this`.
+ std::string_view value() const noexcept { return m_value; }
+ /// File name where key was defined.
+ ///
+ /// The returned string view is valid for the lifetime of `this`.
+ std::string_view file() const noexcept { return m_file; }
+ /// Line number where key was defined.
+ uint64_t line() const noexcept { return m_line; }
+private:
+ Item(std::string_view key, std::string_view value, std::string_view file, uint64_t line):
+ m_key(key), m_value(value), m_file(file), m_line(line) {}
+ friend class Configuration;
+ std::string m_key, m_value, m_file;
+ uint64_t m_line;
};
+/// A source location.
class Location {
public:
+ /// File name
+ ///
+ /// The returned string view is valid for the lifetime of `this`.
inline std::string_view file() const { return m_file; }
+ /// Line number
inline uint64_t line() const { return m_line; }
private:
inline Location(std::string file, uint64_t line):
@@ -151,40 +177,100 @@ private:
// to allow for future extensions without breaking backwards compatibility
const uint32_t version = 1;
};
+/// Print location as `file``:``line` (exact format may change in future).
std::ostream &operator<<(std::ostream &, const Location &);
+/// A POM configuration.
class Configuration {
public:
+ /// Create empty configuration.
Configuration();
+ /// Set `this` to `other`, deleting the current configuration in `this`.
Configuration &operator=(const Configuration &other);
+ /// Copy configuration from `other`.
inline Configuration(const Configuration &other) { *this = other; };
/// Load configuration from abstract \ref Reader.
///
/// Most of the time, you will be able to use another constructor to load a configuration.
/// But if you have special functions for performing reads, you may need this.
+ ///
+ /// \param filename File name for error messages.
+ /// \param source Abstract reader to get file data from.
+ /// \param settings Settings for parsing the file, or `nullptr` to use defaults.
Configuration(std::string_view filename, Reader &source, const Settings *settings = nullptr);
+ /// Load configuration from a `std::istream`.
+ ///
+ /// \param filename File name for error messages.
+ /// \param stream Stream to read file from.
+ /// \param settings Settings for parsing the file, or `nullptr` to use defaults.
Configuration(std::string_view filename, std::istream &stream, const Settings *settings = nullptr);
+ /// Load configuration from a file path.
+ ///
+ /// \param path File name for error messages and to load configuration from.
+ /// \param settings Settings for parsing the file, or `nullptr` to use defaults.
Configuration(std::string_view path, const Settings *settings = nullptr);
+ /// Load configuration from a string.
+ ///
+ /// \param filename File name for error messages.
+ /// \param string String containing the configuration.
+ /// \param settings Settings for parsing the file, or `nullptr` to use defaults.
Configuration(std::string_view filename, std::string_view string, const Settings *settings = nullptr);
~Configuration();
- std::optional<Location> location(std::string_view key) const;
+ /// Get value of `key` in configuration.
std::optional<std::string> get(std::string_view key) const;
+ /// Get value of `key` in configuration, or `dflt` if `key` isn't defined.
std::string get_or_default(std::string_view key, std::string_view dflt) const;
+ /// Get signed integer value of `key` in configuration.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid signed integer.
std::optional<int64_t> get_int(std::string_view key) const;
+ /// Get signed integer value of `key` in configuration, or `dflt` if `key` isn't defined.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid signed integer.
int64_t get_int_or_default(std::string_view key, int64_t dflt) const;
+ /// Get unsigned integer value of `key` in configuration.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid unsigned integer.
std::optional<uint64_t> get_uint(std::string_view key) const;
+ /// Get unsigned integer value of `key` in configuration, or `dflt` if `key` isn't defined.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid unsigned integer.
uint64_t get_uint_or_default(std::string_view key, uint64_t dflt) const;
+ /// Get floating-point value of `key` in configuration.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid floating-point number.
std::optional<double> get_float(std::string_view key) const;
+ /// Get floating-point value of `key` in configuration, or `dflt` if `key` isn't defined.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid floating-point number.
double get_float_or_default(std::string_view key, double dflt) const;
+ /// Get boolean value of `key` in configuration.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid boolean (`on`/`off`/`yes`/`no`/`true`/`false`).
std::optional<bool> get_bool(std::string_view key) const;
+ /// Get boolean value of `key` in configuration, or `dflt` if `key` isn't defined.
+ ///
+ /// Throws an \ref Error if `key` exists but isn't a valid boolean (`on`/`off`/`yes`/`no`/`true`/`false`).
bool get_bool_or_default(std::string_view key, bool dflt) const;
+ /// Get list value of `key` in configuration.
std::optional<std::vector<std::string>> get_list(std::string_view key) const;
+ /// Get list value of `key` in configuration, or `dflt` if `key` isn't defined.
std::vector<std::string> get_list_or_default(std::string_view key, const std::vector<std::string> &dflt) const;
+ /// Returns whether `key` is in this configuration.
+ bool has(std::string_view key) const;
+ /// Returns location of `key` in this configuration.
+ std::optional<Location> location(std::string_view key) const;
+ /// Extract section of configuration consisting of all keys starting with `name.` and their values.
Configuration section(std::string_view name) const;
/// Get list of keys which haven't been the target of a `get_*` method.
std::vector<std::string> unread_keys() const;
+ /// Get list of all "direct" keys (unique first components of keys) in this configuration.
std::vector<std::string> keys() const;
- std::vector<std::shared_ptr<Item>> items() const;
+ /// Get all key-value pairs in this configuration.
+ ///
+ /// This returns a vector of pointers, so that more fields can be added to items in the future
+ /// without breaking binary backwards compatibility.
+ std::vector<std::unique_ptr<Item>> items() const;
/// Merge `other` configuration into `this`.
///
/// Puts all the key-value pairs of `other` into this configuration.
@@ -196,11 +282,9 @@ private:
explicit Configuration(void *c): C(c) {}
void *C;
};
+/// Print configuration.
std::ostream &operator<<(std::ostream &, const Configuration &);
-
-
-
} // namespace pom
#endif // POM_HPP_