diff options
author | pommicket <pommicket@gmail.com> | 2025-09-10 15:26:05 -0400 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2025-09-10 15:26:05 -0400 |
commit | be7b1a115b97dc543d0840d10d2d443ab066ce5b (patch) | |
tree | 2ba025519ed804e724e8fb45fe322ceb3ee47856 /pom.h |
Initial commit
Diffstat (limited to 'pom.h')
-rw-r--r-- | pom.h | 202 |
1 files changed, 202 insertions, 0 deletions
@@ -0,0 +1,202 @@ +/// \file +/// POM configuration parser for C. +/// +/// ## Thread-safety +/// +/// A single configuration should not be used in multiple threads +/// (even for seemingly "read-only" operations) +/// without proper synchronization. +/// +/// Other than that, all these functions are fully thread-safe. + +/// \mainpage libpom doxygen documentation +/// +/// See \ref pom.h for all types/functions. +#ifndef POM_H_ +#define POM_H_ + +#ifndef POM_NO_STDIO +#include <stdio.h> +#endif +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +/// A POM configuration +typedef struct pom_conf pom_conf; +/// A POM-related error +typedef struct pom_error pom_error; + +/// Load a configuration using a `read`-like function. +/// +/// On success, a configuration is returned and `*error` is set to `NULL` +/// if `error` is not `NULL`. +/// +/// On failure, `NULL` is returned, and `*error` is filled out if `error` is not `NULL`, +/// in which case it must be freed with `free`. +/// +/// Most of the time, you won't need this function: +/// use \ref pom_load_file to load from a `FILE *`, +/// \ref pom_load_path to load from a path, +/// and \ref pom_load_string to load from a string. +/// +/// `read_func` will be passed the `userdata` pointer passed to this function, +/// a buffer, and the length of that buffer (which will be nonzero). +/// It must fill out the buffer as much as possible, +/// and return the number of bytes read. +/// A return value less than `len` indicates the end of the file was reached. +/// +/// `filename` is only used for errors. +pom_conf *pom_load(const char *filename, size_t (*read_func)(void *userdata, char *buf, size_t len), void *userdata, pom_error **error); +#ifndef POM_NO_STDIO +/// Load configuration from a `FILE *`. +/// +/// On success, a configuration is returned and `*error` is set to `NULL` +/// if `error` is not `NULL`. +/// +/// On failure, `NULL` is returned, and `*error` is filled out if `error` is not `NULL`, +/// in which case it must be freed with `free`. +/// +/// `filename` is only used for errors. +pom_conf *pom_load_file(const char *filename, FILE *file, pom_error **error); +/// Load configuration from a file path. +/// +/// On success, a configuration is returned and `*error` is set to `NULL` +/// if `error` is not `NULL`. +/// +/// On failure, `NULL` is returned, and `*error` is filled out if `error` is not `NULL`, +/// in which case it must be freed with `free`. +pom_conf *pom_load_path(const char *path, pom_error **error); +#endif +/// Load configuration from a string. +/// +/// On success, a configuration is returned and `*error` is set to `NULL` +/// if `error` is not `NULL`. +/// +/// On failure, `NULL` is returned, and `*error` is filled out if `error` is not `NULL`, +/// in which case it must be freed with `free`. +/// +/// `filename` is only used for errors. +pom_conf *pom_load_string(const char *filename, const char *string, pom_error **error); +/// Get the message of this error. +/// +/// This will be a string such as `"Duplicate key: foo.bar"` +/// +/// See also \ref pom_error_print and \ref pom_error_to_string, which +/// 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`. +/// +/// Includes every error in an error list (see \ref pom_error_next). +void pom_error_print(const pom_error *error); +#endif +/// Convert error to string. Return value must be freed. +/// +/// Includes every error in an error list (see \ref pom_error_next). +char *pom_error_to_string(const pom_error *error); +/// Get error from a POM function. Returns `NULL` if there was no error. +/// +/// This does not need to be freed, and remainly valid only until \ref pom_conf_free, +/// `pom_conf_get_<type>`, or `pom_conf_get_<type>_or_default` +/// is called on `conf`. +const pom_error *pom_conf_error(const pom_conf *conf); +#ifndef POM_NO_STDIO +/// Print last error to `stderr`. +void pom_conf_print_last_error(const pom_conf *conf); +#endif +/// 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`. +/// +/// If `key` is not set, returns `false`, and \ref pom_conf_error will be `NULL` +/// (`*value` is set to 0 in this case). +/// +/// If `key` is set but not a valid integer, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is set to 0 in this case). +bool pom_conf_get_int(const pom_conf *conf, const char *key, int64_t *value); +/// Get signed integer value of `key`, or `dflt` if not present. +/// +/// If `key` is set but not a valid integer, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is still set to `dflt` in this case). +bool pom_conf_get_int_or_default(const pom_conf *conf, const char *key, int64_t *value, int64_t dflt); +/// Get unsigned integer value of `key`. +/// +/// If `key` is not set, returns `false`, and \ref pom_conf_error will be `NULL` +/// (`*value` is set to 0 in this case). +/// +/// If `key` is set but not a valid unsigned integer, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is set to 0 in this case). +bool pom_conf_get_uint(const pom_conf *conf, const char *key, uint64_t *value); +/// Get unsigned integer value of `key`, or `dflt` if not present. +/// +/// If `key` is set but not a valid unsigned integer, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is still set to `dflt` in this case). +bool pom_conf_get_uint_or_default(const pom_conf *conf, const char *key, uint64_t *value, uint64_t dflt); +/// Get floating-point value of `key`. +/// +/// If `key` is not set, returns `false`, and \ref pom_conf_error will be `NULL` +/// (`*value` is set to 0.0 in this case). +/// +/// If `key` is set but not a valid floating-point number, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is set to 0.0 in this case). +bool pom_conf_get_float(const pom_conf *conf, const char *key, double *value); +/// Get floating-point value of `key`, or `dflt` if not present. +/// +/// If `key` is set but not a valid floating-point number, +/// returns `false`, and \ref pom_conf_error will be non-`NULL` +/// (`*value` is still set to `dflt` in this case). +bool pom_conf_get_float_or_default(const pom_conf *conf, const char *key, double *value, double dflt); +/// 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. +/// +/// Commas can be escaped in list entries using `\,`. +/// +/// (`free`ing the list also frees the entries thanks to a "hack" where list entries are stored +/// inline after the entry pointers.) +char **pom_conf_get_list(const pom_conf *conf, const char *key); +/// Extract section out of POM configuration. +/// +/// 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); +/// Create a copy of `conf`. +/// +/// The copy must be freed with \ref pom_conf_free. +/// +/// Returns `NULL` (but does not set `conf`'s error) in the (rare) case of out-of-memory. +/// +/// The copy is entirely independent from `conf` — it can be passed to a separate +/// thread without worry. +pom_conf *pom_conf_copy(const pom_conf *conf); +/// 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.) +char **pom_conf_unread_keys(pom_conf *conf); +#ifndef POM_NO_STDIO +/// Print `key: value` for each `key` in `conf` to `stdout`. +void pom_conf_print(const pom_conf *conf); +#endif +/// Free a POM configuration. +void pom_conf_free(pom_conf *conf); + +#endif |