/// \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 #endif #include #include #include /// 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_`, or `pom_conf_get__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