summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2025-09-10 15:26:05 -0400
committerpommicket <pommicket@gmail.com>2025-09-10 15:26:05 -0400
commitbe7b1a115b97dc543d0840d10d2d443ab066ce5b (patch)
tree2ba025519ed804e724e8fb45fe322ceb3ee47856
Initial commit
-rw-r--r--.gitignore4
-rw-r--r--Doxyfile24
-rw-r--r--pom.h202
3 files changed, 230 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..caa3880
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/doc
+/build*
+/debug
+/release
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..01993ae
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,24 @@
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = libpom
+PROJECT_BRIEF = "Parser for the POM configuration language"
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+OPTIMIZE_OUTPUT_FOR_C = YES
+MARKDOWN_SUPPORT = YES
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = pom.h
+RECURSIVE = NO
+GENERATE_HTML = YES
+HTML_OUTPUT = .
+HTML_FILE_EXTENSION = .html
+GENERATE_LATEX = NO
+ENABLE_PREPROCESSING = YES
+MULTILINE_CPP_IS_BRIEF = YES
+AUTOLINK_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = YES
+EXTRACT_STATIC = YES
+COLLABORATION_GRAPH = NO
+WARN_IF_UNDOCUMENTED = NO
+QUIET = YES
+INCLUDE_GRAPH = NO
diff --git a/pom.h b/pom.h
new file mode 100644
index 0000000..465d042
--- /dev/null
+++ b/pom.h
@@ -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