some machinery for registering and retrieving defaults

* let config_setdefault() take a complete configline instead key:value pair
This commit is contained in:
Christian Thaeter 2008-08-19 22:32:54 +02:00
parent a0105eec42
commit c3e2941eb8
8 changed files with 261 additions and 100 deletions

View file

@ -32,6 +32,7 @@
//TODO: System includes//
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
/**
* @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 key<delegate syntax")
ENSURE (*item->delim == '=' || *item->delim == '<', "default must be a configentry with key=value or key<delegate syntax");
TRACE (config, "registering default: '%s'", item->line);
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)
{

View file

@ -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.

View file

@ -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;
}
/*

View file

@ -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);
/*

View file

@ -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();

View file

@ -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));
}

View file

@ -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);

View file

@ -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);