summaryrefslogtreecommitdiff
path: root/pom.c
diff options
context:
space:
mode:
Diffstat (limited to 'pom.c')
-rw-r--r--pom.c109
1 files changed, 106 insertions, 3 deletions
diff --git a/pom.c b/pom.c
index 9d4b0e4..b795f3b 100644
--- a/pom.c
+++ b/pom.c
@@ -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;
+ }
+}