summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-11 13:25:17 -0400
committerpommicket <pommicket@gmail.com>2025-09-11 13:25:17 -0400
commit4dbbeb1e85390d7c5e24fce4e61c8d29dda6aa00 (patch)
treeb0ec0700bdb824bfbc4db54029f3619ae2a5df74
parent7b8b6367492453958dd0eff6a264ca003002c4b5 (diff)
Add iterators
-rw-r--r--pom.h160
1 files changed, 151 insertions, 9 deletions
diff --git a/pom.h b/pom.h
index 7a86dd1..ca90568 100644
--- a/pom.h
+++ b/pom.h
@@ -10,7 +10,7 @@
/// Other than that, all these functions are fully thread-safe
/// provided that C11 atomics are available
/// (`__STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)`).
-/// But beware of race conditions when using \ref pom_conf_unread_keys
+/// But beware of race conditions when using \ref pom_conf_next_unread_key
/// (ensure there is synchronization so that all threads
/// have certainly read their keys before calling it).
///
@@ -49,9 +49,37 @@
/// A POM configuration
typedef struct pom_conf pom_conf;
+
/// A POM-related error
typedef struct pom_error pom_error;
+/// An opaque iterator produced by \ref pom_conf_next_unread_key.
+typedef struct pom_unread_key_iter pom_unread_key_iter;
+
+/// An opaque iterator produced by \ref pom_conf_next_item.
+typedef struct pom_item_iter pom_item_iter;
+
+/// An opaque iterator produced by \ref pom_conf_next_key.
+typedef struct pom_key_iter pom_key_iter;
+
+/// Item returned by \ref pom_conf_next_item
+typedef struct pom_item {
+ /// The key.
+ ///
+ /// This pointer is valid until \ref pom_conf_free is called.
+ const char *key;
+ /// The value of the key.
+ ///
+ /// This pointer is valid until \ref pom_conf_free is called.
+ const char *val;
+ /// The file where the key was defined.
+ ///
+ /// This pointer is valid until \ref pom_conf_free is called.
+ const char *file;
+ /// The line number where the key was defined.
+ uint64_t line;
+} pom_item;
+
/// Load a configuration using a `read`-like function.
///
/// On success, a configuration is returned and `*error` is set to `NULL`
@@ -81,6 +109,7 @@ pom_load(const char *filename,
size_t (*read_func)(void *userdata, char *buf, size_t len),
void *userdata, pom_error **error)
POM__MUST_USE_R;
+
#ifndef POM_NO_STDIO
/// Load configuration from a `FILE *`.
///
@@ -95,6 +124,7 @@ POM__MUST_USE_L
pom_conf *
pom_load_file(const char *filename, FILE *file, pom_error **error)
POM__MUST_USE_R;
+
/// Load configuration from a file path.
///
/// On success, a configuration is returned and `*error` is set to `NULL`
@@ -107,6 +137,7 @@ pom_conf *
pom_load_path(const char *path, pom_error **error)
POM__MUST_USE_R;
#endif
+
/// Load configuration from a string.
///
/// On success, a configuration is returned and `*error` is set to `NULL`
@@ -120,6 +151,7 @@ POM__MUST_USE_L
pom_conf *
pom_load_string(const char *filename, const char *string, pom_error **error)
POM__MUST_USE_R;
+
/// Get the message of this error.
///
/// This will be a string such as `"Duplicate key: foo.bar"`
@@ -128,15 +160,19 @@ POM__MUST_USE_R;
/// are probably actually what you want in most cases.
const char *
pom_error_message(const pom_error *error);
+
/// Get the name of the file where this error occured.
const char *
pom_error_file(const pom_error *error);
+
/// Get line number where this error occured.
uint64_t
pom_error_line(const pom_error *error);
+
/// Get next error in error list.
const pom_error *
pom_error_next(const pom_error *error);
+
#ifndef POM_NO_STDIO
/// Print error to `stderr`.
///
@@ -144,6 +180,7 @@ pom_error_next(const pom_error *error);
void
pom_error_print(const pom_error *error);
#endif
+
/// Convert error to string. Return value must be `free()`d.
///
/// Includes every error in an error list (see \ref pom_error_next).
@@ -151,12 +188,30 @@ POM__MUST_USE_L
char *
pom_error_to_string(const pom_error *error)
POM__MUST_USE_R;
+
+/// Returns `true` if `key` is present in `conf`, `false` otherwise.
+bool
+pom_conf_has(const pom_conf *conf, const char *key);
+
+/// Get location where `key` was defined in `conf`.
+///
+/// Returns `true` and sets `*file` and `*line` if the `key` is present.
+/// The pointer which `*file` is set to is valid until \ref pom_conf_free is called.
+///
+/// Returns `false` and sets `*file = NULL`, `*line = 0` if `key` is not present.
+///
+/// Either of `file`, `line` may be `NULL`, in which case it is not set.
+bool
+pom_conf_location(const pom_conf *conf, const char *key, const char **file, uint64_t *line);
+
/// Get value of `key` in configuration, or `NULL` if key is not present.
const char *
pom_conf_get(const pom_conf *conf, const char *key);
+
/// Get value of `key` in configuration, or use `dflt` if not present.
const char *
pom_conf_get_or_default(const pom_conf *conf, const char *key, const char *dflt);
+
/// Get signed integer value of `key`.
///
/// Returns `NULL` on success, putting the integer value in `*value`.
@@ -168,6 +223,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_int(const pom_conf *conf, const char *key, int64_t *value)
POM__MUST_USE_R;
+
/// Get signed integer value of `key`, or `dflt` if not present.
///
/// Returns `NULL` on success, putting the integer value in `*value`.
@@ -179,6 +235,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_int_or_default(const pom_conf *conf, const char *key, int64_t *value, int64_t dflt)
POM__MUST_USE_R;
+
/// Get unsigned integer value of `key`.
///
/// Returns `NULL` on success, putting the unsigned integer value in `*value`.
@@ -190,6 +247,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_uint(const pom_conf *conf, const char *key, uint64_t *value)
POM__MUST_USE_R;
+
/// Get unsigned integer value of `key`, or `dflt` if not present.
///
/// Returns `NULL` on success, putting the unsigned integer value in `*value`.
@@ -201,6 +259,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_uint_or_default(const pom_conf *conf, const char *key, uint64_t *value, uint64_t dflt)
POM__MUST_USE_R;
+
/// Get floating-point value of `key`.
///
/// Returns `NULL` on success, putting the floating-point value in `*value`.
@@ -212,6 +271,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_float(const pom_conf *conf, const char *key, double *value)
POM__MUST_USE_R;
+
/// Get floating-point value of `key`, or `dflt` if not present.
///
/// Returns `NULL` on success, putting the floating-point value in `*value`.
@@ -223,6 +283,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_float_or_default(const pom_conf *conf, const char *key, double *value, double dflt)
POM__MUST_USE_R;
+
/// Get boolean value of `key`.
///
/// Returns `NULL` on success, putting the boolean value in `*value`.
@@ -234,6 +295,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_bool(const pom_conf *conf, const char *key, bool *value)
POM__MUST_USE_R;
+
/// Get boolean value of `key`, or `dflt` if not present.
///
/// Returns `NULL` on success, putting the boolean value in `*value`.
@@ -245,6 +307,7 @@ POM__MUST_USE_L
pom_error *
pom_conf_get_bool_or_default(const pom_conf *conf, const char *key, bool *value, bool dflt)
POM__MUST_USE_R;
+
/// Get comma-separated list value of `key`, or `NULL` if not present. The return value must be freed with `free`.
///
/// The list is `NULL`-terminated.
@@ -257,12 +320,72 @@ POM__MUST_USE_L
char **
pom_conf_get_list(const pom_conf *conf, const char *key)
POM__MUST_USE_R;
+
/// Extract section out of POM configuration.
///
+/// Specifically, this returns the configuration consisting of all keys
+/// prefixed by `section.`, with that prefix removed, and their corresponding
+/// values.
+///
/// The returned section doesn't need to be freed, and is valid until
/// \ref pom_conf_free is called on the original configuration.
const pom_conf *
pom_conf_section(const pom_conf *conf, const char *section);
+
+/// Get all ‘direct’ keys in `conf` (i.e. all first components of defined keys).
+///
+/// The first call to this function should be with `*iter = NULL`.
+/// Each time it is called with the same `iter`, it returns the next
+/// direct key in the `conf`.
+/// After all direct keys have been returned (or if an out-of-memory error occurs),
+/// `NULL` is returned, any memory
+/// associated with the iterator is freed, and `*iter` is set to `NULL`.
+/// This function may modify `*iter` arbitrarily — do not attempt
+/// to copy `*iter` or compare it with other iterators.
+/// The keys are returned in an arbitrary order that may change in future versions.
+/// If you decide to stop iterating halfway through,
+/// you should still call this function repeatedly until you get `NULL`;
+/// otherwise memory associated with the iterator may be leaked.
+///
+/// The correct usage for this function is:
+///
+/// ```C
+/// pom_key_iter *iter = NULL;
+/// const char *key;
+/// while ((key = pom_conf_next_key(conf, &iter))) {
+/// printf("Key: %s\n", key);
+/// }
+/// ```
+const char *
+pom_conf_next_key(const pom_conf *conf, pom_key_iter **iter);
+
+/// Get all key-value pairs in `conf`.
+///
+/// The first call to this function should be with `*iter = NULL`.
+/// Each time it is called with the same `iter`, it returns the next
+/// key-value pair in `conf`.
+/// After all items have been returned (or if an out-of-memory error occurs),
+/// `NULL` is returned, any memory
+/// associated with the iterator is freed, and `*iter` is set to `NULL`.
+/// This function may modify `*iter` arbitrarily — do not attempt
+/// to copy `*iter` or compare it with other iterators.
+/// The items are returned in an arbitrary order that may change in future versions.
+/// If you decide to stop iterating halfway through,
+/// you should still call this function repeatedly until you get `NULL`;
+/// otherwise memory associated with the iterator may be leaked.
+///
+/// The correct usage for this function is:
+///
+/// ```C
+/// pom_item_iter *iter = NULL;
+/// const pom_item *item;
+/// while ((item = pom_conf_next_item(conf, &iter))) {
+/// printf("Key: %s, Value: %s\n", item->key, item->value);
+/// }
+/// ```
+const pom_item *
+pom_conf_next_item(const pom_conf *conf, pom_item_iter **iter);
+
/// Create a copy of `conf`.
///
/// The copy must be freed with \ref pom_conf_free.
@@ -275,19 +398,38 @@ POM__MUST_USE_L
pom_conf *
pom_conf_copy(const pom_conf *conf)
POM__MUST_USE_R;
+
/// Merge keys from `other` into `conf`, preferring keys in `other`.
void
pom_conf_merge(pom_conf *conf, const pom_conf *other);
+
/// Get all unread keys in `conf`.
///
-/// The returned array is `NULL`-terminated, and must be freed with `free`.
-///
-/// (The entries of the array are stored inline with the array,
-/// so they are freed when it is.)
-POM__MUST_USE_L
-char **
-pom_conf_unread_keys(pom_conf *conf)
-POM__MUST_USE_R;
+/// The first call to this function should be with `*iter = NULL`.
+/// Each time it is called with the same `iter`, it returns the next
+/// key in the `conf` that has not been accessed with a `pom_conf_get*` function.
+/// After all such keys have been returned (or if an out-of-memory error occurs),
+/// `NULL` is returned, any memory
+/// associated with the iterator is freed, and `*iter` is set to `NULL`.
+/// This function may modify `*iter` arbitrarily — do not attempt
+/// to copy `*iter` or compare it with other iterators.
+/// The keys are returned in an arbitrary order that may change in future versions.
+/// If you decide to stop iterating halfway through,
+/// you should still call this function repeatedly until you get `NULL`;
+/// otherwise memory associated with the iterator may be leaked.
+///
+/// The correct usage for this function is:
+///
+/// ```C
+/// pom_unread_key_iter *iter = NULL;
+/// const char *key;
+/// while ((key = pom_conf_next_unread_key(conf, &iter))) {
+/// printf("Unknown key: %s\n", key);
+/// }
+/// ```
+const char *
+pom_conf_next_unread_key(pom_conf *conf, pom_unread_key_iter **iter);
+
#ifndef POM_NO_STDIO
/// Print `key: value` for each `key` in `conf` to `stdout`.
void