summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--errors.c15
-rw-r--r--examples/all_functions.c39
-rw-r--r--pom.c112
-rw-r--r--pom.h89
-rw-r--r--tests/interpretation.c12
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)
diff --git a/errors.c b/errors.c
index 24f51f9..3b2c496 100644
--- a/errors.c
+++ b/errors.c
@@ -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
diff --git a/pom.c b/pom.c
index 451d7b7..792c039 100644
--- a/pom.c
+++ b/pom.c
@@ -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 **
diff --git a/pom.h b/pom.h
index a812f7c..4078a1a 100644
--- a/pom.h
+++ b/pom.h
@@ -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);