diff options
author | pommicket <pommicket@gmail.com> | 2025-09-12 13:10:53 -0400 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2025-09-12 13:10:53 -0400 |
commit | 81c1cecf40b0733446fb0d945505155d87bf74c6 (patch) | |
tree | 2649bf5e70359c24e8c906438efe48304fa1be9c | |
parent | 9865b70c855500ea3cae76fb8c9986bdf6f249ca (diff) |
Getting items
-rw-r--r-- | examples/conf.pom | 7 | ||||
-rw-r--r-- | examples/read_conf.c | 8 | ||||
-rw-r--r-- | pom.c | 109 | ||||
-rw-r--r-- | pom.h | 11 | ||||
-rwxr-xr-x | pre-commit.sh | 1 |
5 files changed, 132 insertions, 4 deletions
diff --git a/examples/conf.pom b/examples/conf.pom index 1054e41..8df17e7 100644 --- a/examples/conf.pom +++ b/examples/conf.pom @@ -2,8 +2,13 @@ bar = 10 # testing - +Hello = 5 # here's another comment [jibjabjobdsfajkha] win = yes + +[number] + one = 1 +[] +thing=yup diff --git a/examples/read_conf.c b/examples/read_conf.c index ed33e21..966f0a2 100644 --- a/examples/read_conf.c +++ b/examples/read_conf.c @@ -1,5 +1,6 @@ #include <stdlib.h> #include <string.h> +#include <inttypes.h> #include "pom.h" @@ -11,6 +12,13 @@ int main(int argc, char **argv) { free(error); return EXIT_FAILURE; } + printf("number.one: %s\n", pom_conf_get(conf, "number.one")); + printf("number.tow: %s\n", pom_conf_get_or_default(conf, "number.tow", "(none)")); + printf("has thing? %d\n", pom_conf_has(conf, "thing")); + const char *file; uint64_t line; + if (pom_conf_location(conf, "thing", &file, &line)) { + printf("\tthing location: %s:%" PRIu64 "\n", file,line); + } const pom_item *item; pom_item_iter *iter = NULL; while ((item = pom_conf_next_item(conf, &iter))) { @@ -13,12 +13,18 @@ #else #define ATTRIBUTE_PRINTF(fmt, args) #endif + #if _MSC_VER >= 1600 #define PRINTF_FORMAT_STRING _Printf_format_string_ #else #define PRINTF_FORMAT_STRING #endif +#if __STDC_VERSION__ >= 201112 && !defined(__STDC_NO_ATOMICS__) +#define HAVE_ATOMICS 1 +#include <stdatomic.h> +#endif + struct pom_error { const pom_error *next; const char *file; @@ -44,7 +50,7 @@ struct pom_conf { // to detect when a section is used after a merge uint64_t version_number; size_t prefix_len; - const struct conf_item *items; + struct conf_item *items; size_t items_count; }; @@ -58,6 +64,11 @@ struct conf_item { const char *key, *value, *file; uint64_t line; const struct pom_conf *section; +#if HAVE_ATOMICS + atomic_bool read; +#else + bool read; +#endif }; struct main_conf { @@ -650,6 +661,13 @@ static void conf_free(struct main_conf *conf) { free(conf); } +static int +conf_item_cmp_qsort(const void *va, const void *vb) { + const struct conf_item *item_a = va; + const struct conf_item *item_b = vb; + return strcmp(item_a->key, item_b->key); +} + pom_conf * parser_finish(struct parser *parser) { if (parser->out_of_memory || parser->errors.count) { @@ -667,6 +685,7 @@ parser_finish(struct parser *parser) { parser_out_of_memory(parser); return NULL; } + strcpy(filename, parser->filename); // we made room for the to_free header in pom_load. struct to_free *string_data = (struct to_free *)parser->string_data.array; // stop this from getting freed @@ -680,8 +699,14 @@ parser_finish(struct parser *parser) { conf_item->line = parser_item->line; conf_item->key = ((char*)string_data->data) + (parser_item->key - sizeof(struct to_free)); conf_item->value = ((char*)string_data->data) + (parser_item->value - sizeof(struct to_free)); +#if HAVE_ATOMICS + conf_item->read = ATOMIC_VAR_INIT(false); +#else + conf_item->read = false; +#endif conf_item->section = NULL; // TODO } + qsort(conf->items, conf->items_count, sizeof *conf->items, conf_item_cmp_qsort); pom_conf *root = conf_calloc(conf, 1, sizeof *root); root->items = conf->items; root->items_count = conf->items_count; @@ -825,7 +850,7 @@ pom_conf_free(pom_conf *conf) { } static void -check_conf(const pom_conf *conf, const char *func) { +check_conf_(const pom_conf *conf, const char *func) { if (!conf) fatal_error("NULL configuration passed to %s", func); if (conf->version_number != conf->main->version_number) @@ -833,7 +858,7 @@ check_conf(const pom_conf *conf, const char *func) { "(in %s) after pom_conf_merge was called.\n" "This is not allowed.", func); } -#define check_conf(conf) check_conf(conf, __func__) +#define check_conf(conf) check_conf_(conf, __func__) const pom_item * pom_conf_next_item(const pom_conf *conf, pom_item_iter **p_iter) { @@ -860,3 +885,81 @@ pom_conf_next_item(const pom_conf *conf, pom_item_iter **p_iter) { iter->conf_item++; return &iter->item; } + +static size_t +conf_binary_search(const pom_conf *conf, const char *key, char nxt_char, bool *found) { + size_t lo = 0; + size_t hi = conf->items_count; + size_t key_len = strlen(key); + while (lo < hi) { + size_t mid = (lo + hi) / 2; + const char *mid_key = conf->items[mid].key + conf->prefix_len; + int cmp = memcmp(key, mid_key, key_len); + if (cmp == 0) + cmp = nxt_char - mid_key[key_len]; + if (cmp < 0) { + hi = mid; + } else if (cmp > 0) { + lo = mid + 1; + } else { + if (found) *found = true; + return mid; + } + } + if (found) *found = false; + return lo; +} + +struct conf_item * +conf_get_item(const pom_conf *conf, const char *key, const char *func) { + check_conf_(conf, func); + if (!key) + fatal_error("%s called with key = NULL", func); + bool found; + size_t i = conf_binary_search(conf, key, 0, &found); + if (found) + return &conf->items[i]; + else + return NULL; +} +#define conf_get_item(conf, key) conf_get_item(conf, key, __func__) + +const char * +pom_conf_get(const pom_conf *conf, const char *key) { + struct conf_item *item = conf_get_item(conf, key); + if (item) { + #if HAVE_ATOMICS + atomic_store(&item->read, true); + #else + item->read = true; + #endif + return item->value; + } else { + return NULL; + } +} + +const char * +pom_conf_get_or_default(const pom_conf *conf, const char *key, const char *dflt) { + const char *value = pom_conf_get(conf, key); + return value ? value : dflt; +} + +bool +pom_conf_has(const pom_conf *conf, const char *key) { + return conf_get_item(conf, key) != NULL; +} + +bool +pom_conf_location(const pom_conf *conf, const char *key, const char **file, uint64_t *line) { + struct conf_item *item = conf_get_item(conf, key); + if (item) { + if (file) *file = item->file; + if (line) *line = item->line; + return true; + } else { + if (file) *file = NULL; + if (line) *line = 0; + return false; + } +} @@ -162,6 +162,8 @@ POM__MUST_USE_R; /// /// This will be a string such as `"Duplicate key: foo.bar"` /// +/// Error messages may change arbitrarily in future versions. +/// /// The returned pointer is valid until the error is freed. /// /// See also \ref pom_error_print and \ref pom_error_to_string, which @@ -357,6 +359,8 @@ pom_conf_section(const pom_conf *conf, const char *section); /// you should still call this function repeatedly until you get `NULL`; /// otherwise memory associated with the iterator may be leaked. /// +/// The iterator is invalidated if \ref pom_conf_merge is called. +/// /// The correct usage for this function is: /// /// ```C @@ -384,6 +388,8 @@ pom_conf_next_key(const pom_conf *conf, pom_key_iter **iter); /// you should still call this function repeatedly until you get `NULL`; /// otherwise memory associated with the iterator may be leaked. /// +/// The iterator is invalidated if \ref pom_conf_merge is called. +/// /// The returned pointer is only valid until the next call to \ref pom_conf_next_item. /// /// The correct usage for this function is: @@ -413,6 +419,9 @@ POM__MUST_USE_R; /// Merge keys from `other` into `conf`, preferring keys in `other`. This invalidates /// all sections made with \ref pom_conf_section. +/// +/// It also invalidates any iterators from \ref pom_conf_next_item, \ref pom_conf_next_unread_key, +/// \ref pom_conf_next_key. void pom_conf_merge(pom_conf *conf, const pom_conf *other); @@ -431,6 +440,8 @@ pom_conf_merge(pom_conf *conf, const pom_conf *other); /// you should still call this function repeatedly until you get `NULL`; /// otherwise memory associated with the iterator may be leaked. /// +/// The iterator is invalidated if \ref pom_conf_merge is called. +/// /// The correct usage for this function is: /// /// ```C diff --git a/pre-commit.sh b/pre-commit.sh index 6fd5ced..2c213bd 100755 --- a/pre-commit.sh +++ b/pre-commit.sh @@ -1,5 +1,6 @@ #!/bin/sh if sed --version | grep -q 'GNU sed'; then + # Remove trailing white space sed -i 's/\s\s*$//' pom.c pom.h fi git add -u |