From c3e2941eb87a02cd1b4e096ad4812d19118ddf04 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 19 Aug 2008 22:32:54 +0200 Subject: [PATCH] some machinery for registering and retrieving defaults * let config_setdefault() take a complete configline instead key:value pair --- src/backend/config.c | 116 +++++++++++++++++++++++++++++++++--- src/backend/config.h | 38 ++++++++++-- src/backend/config_lookup.c | 40 +++++++++++++ src/backend/config_lookup.h | 25 ++++++++ src/backend/config_typed.c | 104 ++++++++++---------------------- src/backend/configitem.c | 14 +++-- src/backend/configitem.h | 5 +- tests/backend/test-config.c | 19 +++--- 8 files changed, 261 insertions(+), 100 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index b68d30168..9cb532780 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -32,6 +32,7 @@ //TODO: System includes// #include #include +#include /** * @file @@ -74,8 +75,14 @@ lumiera_config_init (const char* path) lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); lumiera_config_lookup_init (&lumiera_global_config->keys); + lumiera_configitem_init (&lumiera_global_config->defaults); + lumiera_configitem_init (&lumiera_global_config->files); + lumiera_configitem_init (&lumiera_global_config->TODO_unknown); + lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config)); + TODO ("register path as config.path itself"); + return 0; } @@ -87,6 +94,9 @@ lumiera_config_destroy () if (lumiera_global_config) { lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config)); + lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys); + lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys); + lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys); lumiera_config_lookup_destroy (&lumiera_global_config->keys); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); @@ -140,11 +150,8 @@ lumiera_config_get (const char* key, const char** value) LUMIERA_CONFIG_KEY_CHARS, LUMIERA_CONFIG_ENV_CHARS, NULL); - if (!tr_key) - { - LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY); - } - else + + if (tr_key) { char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key); @@ -156,24 +163,117 @@ lumiera_config_get (const char* key, const char** value) } else { - TODO ("lookup key"); - ret = 0; /* assume that the lockup worked for now, value is still NULL, just no error set */ + TODO ("follow '<' delegates?"); + LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key); + + if (item) + { + *value = item->delim+1; + ret = 0; + } + else + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } } + else + { + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY); + } return ret; } int -lumiera_config_set (const char* key, const char* value) +lumiera_config_get_default (const char* key, const char** value) { TRACE (config); + REQUIRE (key); + REQUIRE (value); + + int ret = -1; + + TODO ("follow '<' delegates?"); + TODO ("refactor _get and get_default to iterator access"); + LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key); + + if (item && item->parent == &lumiera_global_config->defaults) + { + *value = item->delim+1; + ret = 0; + } + + return ret; +} + + +int +lumiera_config_set (const char* key, const char* delim_value) +{ + TRACE (config); + + TODO ("if does this item already exist in a user writeable file?"); + TODO (" replace delim_value"); + + TODO ("else"); + TODO (" find matching prefix"); + TODO (" find matching suffix"); + TODO (" find proper prefix indentation, else use config.indent"); + TODO (" create configitem with prefix/suffix removed"); + + + +// * set a value by key +// * handles internally everything as string:string key:value pair. +// * lowlevel function +// * tag file as dirty +// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. + + + UNIMPLEMENTED(); return -1; } +LumieraConfigitem +lumiera_config_setdefault (const char* line) +{ + TRACE (config); + REQUIRE (line); + + LumieraConfigitem item = NULL; + + LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock) + { + const char* key = line; + while (*key && isspace (*key)) + key++; + + key = lumiera_tmpbuf_strndup (line, strspn (line, LUMIERA_CONFIG_KEY_CHARS)); + + if (!(item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key)) || item->parent != &lumiera_global_config->defaults) + { + item = lumiera_configitem_new (line); + + if (item) + { + ENSURE (item->delim, "default must be a configentry with key=value or keydelim == '=' || *item->delim == '<', "default must be a configentry with key=value or keyline); + + llist_insert_head (&lumiera_global_config->defaults.childs, &item->link); + item->parent = &lumiera_global_config->defaults; + + lumiera_config_lookup_insert_default (&lumiera_global_config->keys, item); + } + } + } + + return item; +} + + int lumiera_config_reset (const char* key) { diff --git a/src/backend/config.h b/src/backend/config.h index 80a3f787f..e5363796d 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -59,7 +59,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); /** * @file - * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader + * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader */ #define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_." @@ -69,8 +69,12 @@ struct lumiera_config_struct { lumiera_config_lookup keys; - // configfile list + lumiera_configitem defaults; /* registered default values */ + lumiera_configitem files; /* all loaded files */ + lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */ + char* path; + /* all access is protected with rwlock's. We use rwlocks here since concurrent reads are likely common. @@ -89,6 +93,7 @@ typedef lumiera_config* LumieraConfig; */ /* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */ #define LUMIERA_CONFIG_TYPES \ + LUMIERA_CONFIG_TYPE(link, char*) \ LUMIERA_CONFIG_TYPE(number, signed long long) \ LUMIERA_CONFIG_TYPE(real, long double) \ LUMIERA_CONFIG_TYPE(string, char*) \ @@ -160,17 +165,38 @@ int lumiera_config_get (const char* key, const char** value); +int +lumiera_config_get_default (const char* key, const char** value); + + // * {{{ lumiera_config_set(...) }}} // * set a value by key // * handles internally everything as string:string key:value pair. // * lowlevel function // * tag file as dirty // * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. + /** + * + * + * @param key + * @param delim_value delimiter (= or <) followed by the value to be set * */ int -lumiera_config_set (const char* key, const char* value); +lumiera_config_set (const char* key, const char* delim_value); + + +/** + * Installs a default value for a config key. + * Any key might have an associated default value which is used when + * no other configuration is available, this can be set once. + * Any subsequent call will be a no-op. + * @param line line with key, delimiter and value to store as default value + * @return NULL in case of an error, else a pointer to the default configitem + */ +LumieraConfigitem +lumiera_config_setdefault (const char* line); @@ -187,7 +213,7 @@ lumiera_config_set (const char* key, const char* value); */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ - lumiera_config_##name##_get (const char* key, type* value, const char* def); + lumiera_config_##name##_get (const char* key, type* value); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -200,7 +226,7 @@ LUMIERA_CONFIG_TYPES */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ - lumiera_config_##name##_set (const char* key, type* value, const char* fmt); + lumiera_config_##name##_set (const char* key, type* value); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -211,7 +237,7 @@ LUMIERA_CONFIG_TYPES * */ int -lumiera_config_reset(const char* key); +lumiera_config_reset (const char* key); // * Find exact place of a setting. diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index fc124d636..88fd8b102 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -102,6 +102,32 @@ lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) } +LumieraConfigLookupentry +lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item) +{ + TRACE (config_lookup); + REQUIRE (self); + REQUIRE (item); + REQUIRE (item->key); + REQUIRE (item->key_size); + + lumiera_config_lookupentry tmp; + lumiera_config_lookupentry_init (&tmp, lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key)); + + LumieraConfigLookupentry entry = cuckoo_find (self->hash, &tmp); + + if (!entry) + entry = cuckoo_insert (self->hash, &tmp); + + if (entry) + llist_insert_tail (&entry->configitems, &item->lookup); + else + LUMIERA_DIE (CONFIG_LOOKUP); + + return entry; +} + + LumieraConfigitem lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) { @@ -151,6 +177,20 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) return NULL; } +LumieraConfigitem +lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) +{ + TRACE (config_lookup); + + LumieraConfigLookupentry entry = + lumiera_config_lookup_find (self, key); + + if (entry && !llist_is_empty (&entry->configitems)) + return LLIST_TO_STRUCTP (llist_tail (&entry->configitems), lumiera_configitem, lookup); + + return NULL; +} + /* diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h index af22b2335..42c06842e 100644 --- a/src/backend/config_lookup.h +++ b/src/backend/config_lookup.h @@ -85,6 +85,21 @@ lumiera_config_lookup_destroy (LumieraConfigLookup self); LumieraConfigLookupentry lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item); + +/** + * Add a default config item to a lookup structure. + * @internal + * This function is used internal. + * The item must contain a full key and not part of any 'section' + * and is inserted as tail of the lookup list. + * @param self lookup structure where the item shall be added + * @param item config item to add to the lookup structure + * @return opaque pointer to a hashtable entry + */ +LumieraConfigLookupentry +lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item); + + /** * Remove a config item from a lookup structure. * Config must be removed from the lookup when they are not used anymore. @@ -116,6 +131,16 @@ lumiera_config_lookup_find (LumieraConfigLookup self, const char* key); LumieraConfigitem lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key); +/** + * Find a the bottommost config item stored to a given key. + * defaults sits at the bottom if exists + * @param self lookup structure where the key shall be searched + * @param key string to be looked up + * @return TODO + */ +LumieraConfigitem +lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key); + /* diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 78f2e8cd7..02e75d0db 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -38,12 +38,29 @@ extern LumieraConfig lumiera_global_config; * Here are the high level typed configuration interfaces defined. */ +int +lumiera_config_link_get (const char* key, char** value) +{ + TRACE (config_typed); + UNIMPLEMENTED(); + return 0; +} + +int +lumiera_config_link_set (const char* key, char** value) +{ + TRACE (config_typed); + UNIMPLEMENTED(); + return 0; +} + + /** * Number * signed integer numbers, in different formats (decimal, hex, oct, binary(for masks)) */ int -lumiera_config_number_get (const char* key, long long* value, const char* def) +lumiera_config_number_get (const char* key, long long* value) { TRACE (config_typed); @@ -63,31 +80,12 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) else { LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE); - if (def) - /* even when we return an error code we still try to initialize value with our default while in error state */ - goto try_default; - } - } - else if (def) - { - /* not found, fall back to default */ - ret = 0; /* we presume that the default is ok */ - try_default: - - if (sscanf (def, "%Li", value) == 1) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - /* default value is broken!! */ - /* note that this error gets ignored by the application when we had a type error above, but will still be logged with nobug */ - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + /* try default instead */ + if (!lumiera_config_get_default (key, &raw_value)) + sscanf (raw_value, "%Li", value); } } else - /* finally, no config, no default, give up */ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } } @@ -96,7 +94,7 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) } int -lumiera_config_number_set (const char* key, long long* value, const char* fmt) +lumiera_config_number_set (const char* key, long long* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -109,7 +107,7 @@ lumiera_config_number_set (const char* key, long long* value, const char* fmt) * floating point number in standard formats (see printf/scanf) */ int -lumiera_config_real_get (const char* key, long double* value, const char* def) +lumiera_config_real_get (const char* key, long double* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -117,7 +115,7 @@ lumiera_config_real_get (const char* key, long double* value, const char* def) } int -lumiera_config_real_set (const char* key, long double* value, const char* fmt) +lumiera_config_real_set (const char* key, long double* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -189,7 +187,7 @@ scan_string (const char* in) } int -lumiera_config_string_get (const char* key, char** value, const char* def) +lumiera_config_string_get (const char* key, char** value) { TRACE (config_typed); @@ -204,27 +202,9 @@ lumiera_config_string_get (const char* key, char** value, const char* def) if (raw_value) { *value = scan_string (raw_value); - if (*value) ret = 0; /* all ok */ - else if (def) - goto try_default; - } - else if (def) - { - ret = 0; - try_default: - - *value = scan_string (def); - if (*value) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); - } + /* else error was raised by scan_string */ } else LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); @@ -235,7 +215,7 @@ lumiera_config_string_get (const char* key, char** value, const char* def) } int -lumiera_config_string_set (const char* key, char** value, const char* fmt) +lumiera_config_string_set (const char* key, char** value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -271,7 +251,7 @@ scan_word (const char* in) } int -lumiera_config_word_get (const char* key, char** value, const char* def) +lumiera_config_word_get (const char* key, char** value) { TRACE (config_typed, "KEY %s", key); @@ -286,30 +266,8 @@ lumiera_config_word_get (const char* key, char** value, const char* def) if (raw_value) { *value = scan_word (raw_value); - - TRACE (config_typed, "RAW_VALUE %s, scanned .%s.", raw_value, *value); - if (*value) ret = 0; /* all ok */ - else if (def) - goto try_default; - } - else if (def) - { - ret = 0; - try_default: - - *value = scan_word (def); - TRACE (config_typed, "DEFAULT %s, scanned .%s.", def, *value); - if (*value) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); - } } else LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); @@ -320,7 +278,7 @@ lumiera_config_word_get (const char* key, char** value, const char* def) } int -lumiera_config_word_set (const char* key, char** value, const char* fmt) +lumiera_config_word_set (const char* key, char** value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -333,7 +291,7 @@ lumiera_config_word_set (const char* key, char** value, const char* fmt) * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear) */ int -lumiera_config_bool_get (const char* key, int* value, const char* def) +lumiera_config_bool_get (const char* key, int* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -341,7 +299,7 @@ lumiera_config_bool_get (const char* key, int* value, const char* def) } int -lumiera_config_bool_set (const char* key, int* value, const char* fmt) +lumiera_config_bool_set (const char* key, int* value) { TRACE (config_typed); UNIMPLEMENTED(); diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a49694280..0d7830b87 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -68,7 +68,7 @@ lumiera_configitem_init (LumieraConfigitem self) } LumieraConfigitem -lumiera_configitem_destroy (LumieraConfigitem self) +lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (config_item); @@ -77,7 +77,12 @@ lumiera_configitem_destroy (LumieraConfigitem self) if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); - ENSURE (llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + if (!llist_is_empty (&self->lookup)) + lumiera_config_lookup_remove (lookup, self); + + LLIST_WHILE_HEAD (&self->childs, node) + lumiera_configitem_delete ((LumieraConfigitem) node, lookup); + ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); llist_unlink (&self->link); @@ -102,15 +107,16 @@ lumiera_configitem_new (const char* line) ? tmp.vtable->new (&tmp) : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp); + TRACE (config_item, "key size of %s is %d", tmp.key, tmp.key_size); return self; } void -lumiera_configitem_delete (LumieraConfigitem self) +lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (config_item); - lumiera_free (lumiera_configitem_destroy (self)); + lumiera_free (lumiera_configitem_destroy (self, lookup)); } diff --git a/src/backend/configitem.h b/src/backend/configitem.h index c2b0bea92..c2395b6dc 100644 --- a/src/backend/configitem.h +++ b/src/backend/configitem.h @@ -33,6 +33,7 @@ typedef lumiera_configitem* LumieraConfigitem; struct lumiera_configitem_vtable; //TODO: Lumiera header includes// +#include "backend/config_lookup.h" //TODO: System includes// @@ -112,13 +113,13 @@ LumieraConfigitem lumiera_configitem_init (LumieraConfigitem self); LumieraConfigitem -lumiera_configitem_destroy (LumieraConfigitem self); +lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup); LumieraConfigitem lumiera_configitem_new (const char* line); void -lumiera_configitem_delete (LumieraConfigitem self); +lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup); LumieraConfigitem lumiera_configitem_parse (LumieraConfigitem self, const char* line); diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index f6f49e099..8fed601f8 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -56,7 +56,7 @@ TEST ("configitem_simple") printf ("value = '%s'\n", item->delim+1); } - lumiera_configitem_delete (item); + lumiera_configitem_delete (item, NULL); lumiera_config_destroy (); } @@ -92,7 +92,9 @@ TEST ("number_get") long long number = 0; - if (!lumiera_config_number_get (argv[2], &number, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_number_get (argv[2], &number)) printf ("%lld\n", number); else printf ("%s, %lld\n", lumiera_error (), number); @@ -109,7 +111,7 @@ TEST ("number_get_nodefault") long long number = 0; - if (!lumiera_config_number_get (argv[2], &number, NULL)) + if (!lumiera_config_number_get (argv[2], &number)) printf ("%lld\n", number); else printf ("%s\n", lumiera_error ()); @@ -127,7 +129,9 @@ TEST ("string_get") char* string; - if (!lumiera_config_string_get (argv[2], &string, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_string_get (argv[2], &string)) printf ("'%s'\n", string); else printf ("%s, '%s'\n", lumiera_error (), string); @@ -139,11 +143,10 @@ TEST ("string_get") TEST ("string_set") { REQUIRE (argv[2]); - REQUIRE (argv[3]); lumiera_config_init ("./"); - lumiera_config_string_set (argv[2], &argv[3], NULL); + lumiera_config_string_set (argv[2], &argv[3]); FIXME ("handle error"); const char* string; @@ -165,7 +168,9 @@ TEST ("word_get") char* word; - if (!lumiera_config_word_get (argv[2], &word, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_word_get (argv[2], &word)) printf ("'%s'\n", word); else printf ("%s, '%s'\n", lumiera_error (), word);