diff options
author | pommicket <pommicket@gmail.com> | 2025-09-15 22:00:24 -0400 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2025-09-15 22:00:24 -0400 |
commit | 2fc802b267092ad647672bcbfcd31f0117eec27c (patch) | |
tree | 9b45ae643adfba9e23e761599d5d8240f6ed3180 | |
parent | b93385c0fded8d6c232267a8bd9293153baea777 (diff) |
Switch back to `pom_error` for typed get functions
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | errors.c | 15 | ||||
-rw-r--r-- | examples/all_functions.c | 39 | ||||
-rw-r--r-- | pom.c | 112 | ||||
-rw-r--r-- | pom.h | 89 | ||||
-rw-r--r-- | tests/interpretation.c | 12 |
6 files changed, 145 insertions, 128 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index bc4eb26..5a24f75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,13 @@ endif() add_library(pom STATIC pom.c) add_library(pom-shared SHARED pom.c) set_target_properties(pom-shared PROPERTIES OUTPUT_NAME pom) + +# Tests add_executable(tests tests/errors.c tests/location.c tests/parsing.c tests/interpretation.c tests/main.c) target_include_directories(tests PRIVATE .) target_link_libraries(tests pom) + +# Examples add_executable(example_read_conf examples/read_conf.c) target_include_directories(example_read_conf PRIVATE .) target_link_libraries(example_read_conf pom) @@ -24,6 +28,6 @@ add_executable(example_all_functions examples/all_functions.c) target_include_directories(example_all_functions PRIVATE .) target_link_libraries(example_all_functions pom) +# Installation install(TARGETS pom pom-shared DESTINATION lib) -install(FILES pom.pc DESTINATION lib) install(FILES pom.h DESTINATION include) @@ -18,6 +18,11 @@ enum error_id { ERROR_EMPTY_KEY, ERROR_REDEFINITION, ERROR_NO_CLOSING_QUOTE, + ERROR_KEY_NOT_FOUND, + ERROR_INVALID_INT, + ERROR_INVALID_UINT, + ERROR_INVALID_FLOAT, + ERROR_INVALID_BOOL, ERROR_COUNT, }; @@ -39,6 +44,11 @@ static const char *const error_messages_en[ERROR_COUNT] = { [ERROR_EMPTY_KEY] = "Expected key name before =", [ERROR_REDEFINITION] = "Re-definition of %s (previously defined on line %" PRIu64 ")", [ERROR_NO_CLOSING_QUOTE] = "Missing closing %c", + [ERROR_KEY_NOT_FOUND] = "Key %s not found", + [ERROR_INVALID_INT] = "Value '%s' for %s is not a valid integer", + [ERROR_INVALID_UINT] = "Value '%s' for %s is not a valid (non-negative) integer", + [ERROR_INVALID_FLOAT] = "Value '%s' for %s is not a valid number", + [ERROR_INVALID_BOOL] = "Value '%s' for %s is invalid (want on/off/yes/no/true/false)", }; @@ -60,6 +70,11 @@ static const char *const error_messages_fr[ERROR_COUNT] = { [ERROR_EMPTY_KEY] = "Nom de clé devrait précéder =", [ERROR_REDEFINITION] = "Redéfinition de %s (définition précédente à ligne %" PRIu64 ")", [ERROR_NO_CLOSING_QUOTE] = "Aucun %c fermant", + [ERROR_KEY_NOT_FOUND] = "Clé %s n'existe pas", + [ERROR_INVALID_INT] = "Valeur '%s' du clé %s n'est pas un nombre entier", + [ERROR_INVALID_UINT] = "Valeur '%s' du clé %s n'est pas un nombre entier (positif)", + [ERROR_INVALID_FLOAT] = "Valeur '%s' du clé %s n'est pas un nombre valide", + [ERROR_INVALID_BOOL] = "Valeur '%s' du clé %s est invalide (veut on/off/yes/no/true/false)", }; static struct { diff --git a/examples/all_functions.c b/examples/all_functions.c index 843cf03..18cce6f 100644 --- a/examples/all_functions.c +++ b/examples/all_functions.c @@ -63,38 +63,36 @@ int main(void) { // parse value as signed integer int64_t int_val; - const char *bad_val; - if ((bad_val = pom_conf_get_int(conf, "tab-size", &int_val))) { - printf("bad tab size: %s\n", *bad_val ? bad_val : "<missing>"); + if ((error = pom_conf_get_int(conf, "tab-size", &int_val))) { + pom_error_print(error); + free(error); } else { printf("tab size: %" PRId64 "\n", int_val); } // parse value as unsigned integer, use default of 2 uint64_t uint_val; - if ((bad_val = pom_conf_get_uint_or_default(conf, "padding-pixels", &uint_val, 2))) { - printf("bad padding pixels: %s\n", bad_val); + if ((error = pom_conf_get_uint_or_default(conf, "padding-pixels", &uint_val, 2))) { + pom_error_print(error); + free(error); } else { printf("padding pixels: %" PRIu64 "\n", uint_val); } // parse value as double double float_val; - if ((bad_val = pom_conf_get_float_or_default(conf, "font-size", &float_val, 12.0))) { - printf("bad font size: %s\n", bad_val); + if ((error = pom_conf_get_float_or_default(conf, "font-size", &float_val, 12.0))) { + pom_error_print(error); + free(error); } else { printf("font size: %f\n", float_val); } // parse value as boolean bool bool_val; - if ((bad_val = pom_conf_get_bool_or_default(conf, "show-line-numbers", &bool_val, true))) { - // get location where key was defined - const char *file; - uint64_t line; - pom_conf_location(conf, "show-line-numbers", &file, &line); - printf("bad show-line-numbers: %s (defined at %s:%" PRIu64 ")\n", - bad_val, file, line); + if ((error = pom_conf_get_bool_or_default(conf, "show-line-numbers", &bool_val, true))) { + pom_error_print(error); + free(error); } else { printf("show line numbers: %d\n", bool_val); } @@ -120,8 +118,17 @@ int main(void) { const pom_conf *plugin = pom_conf_section(plugins, key); const char *path = pom_conf_get_or_default(plugin, "path", "(none)"); bool enabled; - pom_conf_get_bool_or_default(plugin, "enabled", &enabled, true); - printf("plug-in: %s (path = %s, enabled = %d)\n", key, path, enabled); + if ((error = pom_conf_get_bool_or_default(plugin, "enabled", &enabled, true))) { + pom_error_print(error); + free(error); + // (enabled will still be true in this case) + } + // get location where key was defined + const char *file; + uint64_t line; + pom_conf_location(plugins, key, &file, &line); + printf("%s:%" PRIu64 ": plug-in: %s (path = %s, enabled = %d)\n", + file, line, key, path, enabled); } // load config from string @@ -1,8 +1,3 @@ -/* -TODO: -- clean up read_conf.c example -- interpretation tests -*/ #include "pom.h" #include <stdio.h> // still needed for sprintf, even if POM_NO_STDIO is defined. @@ -1743,108 +1738,85 @@ parse_bool(const char *s, bool *val) { return false; } -const char * + +pom_error * pom_conf_get_uint(const pom_conf *conf, const char *key, uint64_t *value_uint) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_uint) fatal_error("NULL value passed to %s", __func__); *value_uint = 0; - const char *value_str = pom_conf_get(conf, key); - if (!value_str) - return ""; - if (parse_uint(value_str, value_uint)) + struct conf_item *item = conf_get_item(conf, key); + if (!item) + return make_error(&conf->main->settings, "", 0, ERROR_KEY_NOT_FOUND, key); + if (parse_uint(item->value, value_uint)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_UINT, item->value, item->key); } -const char * +pom_error * pom_conf_get_uint_or_default(const pom_conf *conf, const char *key, uint64_t *value_uint, uint64_t dflt) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_uint) fatal_error("NULL value passed to %s", __func__); *value_uint = dflt; - const char *value_str = pom_conf_get(conf, key); - if (!value_str || parse_uint(value_str, value_uint)) + struct conf_item *item = conf_get_item(conf, key); + if (!item || parse_uint(item->value, value_uint)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_UINT, item->value, item->key); } -const char * +pom_error * pom_conf_get_int(const pom_conf *conf, const char *key, int64_t *value_int) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_int) fatal_error("NULL value passed to %s", __func__); *value_int = 0; - const char *value_str = pom_conf_get(conf, key); - if (!value_str) - return ""; - if (parse_int(value_str, value_int)) + struct conf_item *item = conf_get_item(conf, key); + if (!item) + return make_error(&conf->main->settings, "", 0, ERROR_KEY_NOT_FOUND, key); + if (parse_int(item->value, value_int)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_INT, item->value, item->key); } -const char * +pom_error * pom_conf_get_int_or_default(const pom_conf *conf, const char *key, int64_t *value_int, int64_t dflt) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_int) fatal_error("NULL value passed to %s", __func__); *value_int = dflt; - const char *value_str = pom_conf_get(conf, key); - if (!value_str || parse_int(value_str, value_int)) + struct conf_item *item = conf_get_item(conf, key); + if (!item || parse_int(item->value, value_int)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_INT, item->value, item->key); } -const char * +pom_error * pom_conf_get_float(const pom_conf *conf, const char *key, double *value_double) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_double) fatal_error("NULL value passed to %s", __func__); - *value_double = 0; - const char *value_str = pom_conf_get(conf, key); - if (!value_str) - return ""; - if (parse_double(value_str, value_double)) + *value_double = 0.0; + struct conf_item *item = conf_get_item(conf, key); + if (!item) + return make_error(&conf->main->settings, "", 0, ERROR_KEY_NOT_FOUND, key); + if (parse_double(item->value, value_double)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_FLOAT, item->value, item->key); } -const char * +pom_error * pom_conf_get_float_or_default(const pom_conf *conf, const char *key, double *value_double, double dflt) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_double) fatal_error("NULL value passed to %s", __func__); *value_double = dflt; - const char *value_str = pom_conf_get(conf, key); - if (!value_str || parse_double(value_str, value_double)) + struct conf_item *item = conf_get_item(conf, key); + if (!item || parse_double(item->value, value_double)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_FLOAT, item->value, item->key); } -const char * +pom_error * pom_conf_get_bool(const pom_conf *conf, const char *key, bool *value_bool) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_bool) fatal_error("NULL value passed to %s", __func__); *value_bool = false; - const char *value_str = pom_conf_get(conf, key); - if (!value_str) - return ""; - if (parse_bool(value_str, value_bool)) + struct conf_item *item = conf_get_item(conf, key); + if (!item) + return make_error(&conf->main->settings, "", 0, ERROR_KEY_NOT_FOUND, key); + if (parse_bool(item->value, value_bool)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_BOOL, item->value, item->key); } -const char * +pom_error * pom_conf_get_bool_or_default(const pom_conf *conf, const char *key, bool *value_bool, bool dflt) { - check_conf(conf); - if (!key) fatal_error("NULL key passed to %s", __func__); - if (!value_bool) fatal_error("NULL value passed to %s", __func__); *value_bool = dflt; - const char *value_str = pom_conf_get(conf, key); - if (!value_str || parse_bool(value_str, value_bool)) + struct conf_item *item = conf_get_item(conf, key); + if (!item || parse_bool(item->value, value_bool)) return NULL; - return value_str; + return make_error(&conf->main->settings, item->file, item->line, ERROR_INVALID_BOOL, item->value, item->key); } char ** @@ -268,15 +268,16 @@ pom_conf_get_or_default(const pom_conf *conf, const char *key, const char *dflt) /// /// Returns `NULL` on success, putting the integer value in `*value`. /// -/// If `key` is not set, returns `""`. -/// If `key` is set but not a valid integer +/// If `key` is not set or is not a valid integer /// (decimal or `0x`/`0X`-prefixed hexadecimal, absolute value less than 2<sup>53</sup>), -/// returns the value of `key`. +/// returns an error. /// `*value` is set to 0 in these cases. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_int(const pom_conf *conf, const char *key, int64_t *value); +/// The returned error must be `free()`d. +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. /// @@ -284,25 +285,29 @@ pom_conf_get_int(const pom_conf *conf, const char *key, int64_t *value); /// /// If `key` is set but not a valid integer /// (decimal or `0x`/`0X`-prefixed hexadecimal, absolute value less than 2<sup>53</sup>), -/// returns the value of `key`. +/// returns an error. /// `*value` is still set to `dflt` in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_int_or_default(const pom_conf *conf, const char *key, int64_t *value, int64_t dflt); +/// The returned error must be `free()`d. +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`. /// -/// If `key` is not set, returns `""`. If `key` is set but not a valid unsigned integer +/// If `key` is not set or is not a valid unsigned integer /// (decimal or `0x`/`0X`-prefixed hexadecimal, less than 2<sup>53</sup>), -/// returns the value of `key`. +/// returns an error. /// `*value` is set to 0 in these case cases. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_uint(const pom_conf *conf, const char *key, uint64_t *value); +/// The returned error must be `free()`d. +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. /// @@ -310,49 +315,57 @@ pom_conf_get_uint(const pom_conf *conf, const char *key, uint64_t *value); /// /// If `key` is set but not a valid unsigned integer /// (decimal or `0x`/`0X`-prefixed hexadecimal, less than 2<sup>53</sup>), -/// returns the value of `key`. +/// returns an error. /// `*value` is set to 0 in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_uint_or_default(const pom_conf *conf, const char *key, uint64_t *value, uint64_t dflt); +/// The returned error must be `free()`d. +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`. /// -/// If `key` is not set, returns `""`. If `key` is set but not a valid floating-point number, -/// returns the value of `key`. +/// If `key` is not set or is set but not a valid floating-point number, +/// returns an error. /// `*value` is set to 0.0 in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_float(const pom_conf *conf, const char *key, double *value); +/// The returned error must be `free()`d. +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`. /// /// If `key` is set but not a valid floating-point number, -/// returns the value of `key`. +/// returns an error. /// `*value` is still set to `dflt` in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_float_or_default(const pom_conf *conf, const char *key, double *value, double dflt); +/// The returned error must be `free()`d. +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`. /// -/// If `key` is not set, returns `""`. If `key` is set but not a valid boolean +/// If `key` is not set or is set but not a valid boolean /// (`off`/`false`/`no`/`on`/`true`/`yes`), -/// returns the value of `key`. +/// returns an error. /// `*value` is set to `false` in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_bool(const pom_conf *conf, const char *key, bool *value); +/// The returned error must be `free()`d. +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. /// @@ -360,12 +373,14 @@ pom_conf_get_bool(const pom_conf *conf, const char *key, bool *value); /// /// If `key` is set but not a valid boolean /// (`off`/`false`/`no`/`on`/`true`/`yes`), -/// returns the value of `key`. +/// returns an error. /// `*value` is still set to `dflt` in this case. /// -/// The returned pointer is valid until \ref pom_conf_free is called. -const char * -pom_conf_get_bool_or_default(const pom_conf *conf, const char *key, bool *value, bool dflt); +/// The returned error must be `free()`d. +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`. /// diff --git a/tests/interpretation.c b/tests/interpretation.c index bdae290..26846a1 100644 --- a/tests/interpretation.c +++ b/tests/interpretation.c @@ -26,9 +26,10 @@ void test_interpretation(void) { if (strstr(conf_path, "uint.pom")) { uint64_t val, val2; while ((key = pom_conf_next_key(bad, &iter))) { - if (!pom_conf_get_uint(bad, key, &val)) { + if (!(error = pom_conf_get_uint(bad, key, &val))) { test_fail("Key %s should be rejected as a uint", key); } + free(error); } while ((key = pom_conf_next_key(good, &iter))) { const pom_conf *section = pom_conf_section(good, key); @@ -49,9 +50,10 @@ void test_interpretation(void) { } else if (strstr(conf_path, "int.pom")) { int64_t val, val2; while ((key = pom_conf_next_key(bad, &iter))) { - if (!pom_conf_get_int(bad, key, &val)) { + if (!(error = pom_conf_get_int(bad, key, &val))) { test_fail("Key %s should be rejected as an int", key); } + free(error); } while ((key = pom_conf_next_key(good, &iter))) { const pom_conf *section = pom_conf_section(good, key); @@ -72,9 +74,10 @@ void test_interpretation(void) { } else if (strstr(conf_path, "float.pom")) { double val, val2; while ((key = pom_conf_next_key(bad, &iter))) { - if (!pom_conf_get_float(bad, key, &val)) { + if (!(error = pom_conf_get_float(bad, key, &val))) { test_fail("Key %s should be rejected as a float", key); } + free(error); } while ((key = pom_conf_next_key(good, &iter))) { const pom_conf *section = pom_conf_section(good, key); @@ -95,9 +98,10 @@ void test_interpretation(void) { } else if (strstr(conf_path, "bool.pom")) { bool val, val2; while ((key = pom_conf_next_key(bad, &iter))) { - if (!pom_conf_get_bool(bad, key, &val)) { + if (!(error = pom_conf_get_bool(bad, key, &val))) { test_fail("Key %s should be rejected as a bool", key); } + free(error); } while ((key = pom_conf_next_key(good, &iter))) { const pom_conf *section = pom_conf_section(good, key); |