/* configitem.c - generalized hierachy of configuration items Copyright (C) Lumiera.org 2008, Christian Thaeter Simeon Voelkel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "include/logging.h" #include "lib/llist.h" #include "lib/safeclib.h" //TODO: Lumiera header includes// #include "common/config.h" #include "common/configitem.h" #include "common/configentry.h" static LumieraConfigitem parse_directive (LumieraConfigitem self, char* itr); static LumieraConfigitem parse_section (LumieraConfigitem self, char* itr); static LumieraConfigitem parse_configentry (LumieraConfigitem self, char* itr); #include #include /** * @file * create a configitem out of a single line. * */ LumieraConfigitem lumiera_configitem_init (LumieraConfigitem self) { TRACE (configitem_dbg); REQUIRE (self); llist_init (&self->link); self->parent = NULL; llist_init (&self->childs); llist_init (&self->lookup); self->line = NULL; self->key = NULL; self->key_size = 0; self->delim = NULL; self->vtable = NULL; return self; } LumieraConfigitem lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (configitem_dbg); if (self) { LLIST_WHILE_HEAD (&self->childs, node) lumiera_configitem_delete ((LumieraConfigitem) node, lookup); ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); if (!llist_is_empty (&self->lookup)) lumiera_config_lookup_remove (lookup, self); llist_unlink (&self->link); lumiera_free (self->line); } return self; } LumieraConfigitem lumiera_configitem_new (const char* line) { TRACE (configitem_dbg, "%s", line); lumiera_configitem tmp; lumiera_configitem_init (&tmp); lumiera_configitem_parse (&tmp, line); LumieraConfigitem self = tmp.vtable && tmp.vtable->new ? tmp.vtable->new (&tmp) : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp); return self; } void lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (configitem_dbg); lumiera_free (lumiera_configitem_destroy (self, lookup)); } LumieraConfigitem lumiera_configitem_set_value (LumieraConfigitem self, const char* delim_value) { REQUIRE (self->key); REQUIRE (self->delim); char* line = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s", self->delim - self->line, self->line, delim_value); lumiera_configitem_parse (self, line); return self; } LumieraConfigitem lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) { TRACE (configitem_dbg); REQUIRE (self); REQUIRE (source); llist_init (&self->link); llist_insertlist_next (&self->link, &source->link); self->parent = source->parent; llist_init (&self->childs); llist_insertlist_next (&self->childs, &source->childs); llist_init (&self->lookup); llist_insertlist_next (&self->lookup, &source->lookup); self->line = source->line; source->line = NULL; self->key = source->key; self->key_size = source->key_size; self->delim = source->delim; self->vtable = source->vtable; return self; } LumieraConfigitem lumiera_configitem_parse (LumieraConfigitem self, const char* line) { TRACE (configitem_dbg); lumiera_free (self->line); self->line = lumiera_strndup (line, SIZE_MAX); FIXME ("MOCKUP START"); char* itr = self->line; /* skip leading whitespaces */ while (*itr && isspace (*itr)) itr++; /* decide what this line represents */ if (!*itr || *itr == '#' ) { /* this is an empty line or a a comment */ } else if (*itr == '@' ) { /* this is a directive */ self = parse_directive (self, itr); } else if (*itr == '[' ) { /* this is a section */ self = parse_section (self, itr); } else { /* this is probably a configentry */ self = parse_configentry (self, itr); } return self; } static LumieraConfigitem parse_directive (LumieraConfigitem self, char* itr) { /* itr points now to @ */ self->key = itr; /* check whether there are illegal whitespaces after @ */ itr++; if (*itr && !isspace(*itr)) { /* now look for the end of the directive and set the keysize */ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); itr += self->key_size; /* we need a key with a length greather than zero and */ /* either end of line or whitespace after key */ if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) )) { /* look for given arguments */ /* skip blanks */ while (*itr && isspace (*itr)) itr++; if (*itr) { /* there are arguments given, thus set delim */ self->delim = itr - 1; } else { /* no arguments were given */ self->delim = NULL; } } else { /* malformed lines shall be treated like if they were comments */ self->key = NULL; self->key_size = 0; LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } } else { /* there occurred already an error right after the @! */ /* malformed lines shall be treated like if they were comments */ self->key = NULL; self->key_size = 0; LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; } static LumieraConfigitem parse_section (LumieraConfigitem self, char* itr) { /* skip blanks before prefix */ itr++; while (*itr && isspace(*itr)) itr++; /* itr points now to the begin of the key */ self->key = itr; /* now look for the end of the key and set the keysize */ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); itr += self->key_size; /* if the line ends ends with prefix] delim points to ] */ /* and not the last (blank) character before the final square bracket */ if (self->key_size && *itr && *itr == ']') { self->delim = itr; TODO("self->vtable = &lumiera_configsection_funcs;"); } else if (self->key_size && *itr && isspace(*itr)) { /* skip blanks until we reach the suffix or the final square bracket */ while (*itr && isspace(*itr)) itr++; if (*itr && *itr == ']') { /* final square bracket reached, so place delim one char before the */ /* actual position which must be a whitespace: no extra check necessary */ self->delim = itr - 1; TODO("self->vtable = &lumiera_configsection_funcs;"); } else if (*itr) { TODO("check wheter suffix is made of legal characters"); /* delim points to the last whitespace before the actual position; */ /* no extra check needed */ self->delim = itr - 1; TODO("self->vtable = &lumiera_configsection_funcs;"); } else { /* malformed section line, treat this line like a comment */ self->key = NULL; self->key_size = 0; LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } } else { /* error: either *itr is false, points neither to a blank nor to a closed square */ /* bracket or the key_size is zero */ /* treat this line like a comment */ self->key = NULL; self->key_size = 0; LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; } static LumieraConfigitem parse_configentry (LumieraConfigitem self, char* itr) { /* itr points now to the first not-whitespace-character */ self->key = itr; /* now look for the end of the key and set the keysize */ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); /* skip blanks */ itr += self->key_size; while (*itr && isspace (*itr)) itr++; if (self->key_size && *itr == '=') { /* this configentry assigns a value to a key */ self->delim = itr; self->vtable = &lumiera_configentry_funcs; } else if (self->key_size && *itr == '<') { /* this configentry is a redirect */ self->delim = itr; self->vtable = &lumiera_configentry_funcs; } else { /* this is not a valid configentry; treat this line like a comment */ self->key = NULL; self->key_size = 0; LUMIERA_ERROR_SET (config, CONFIG_SYNTAX, self->line); } return self; } /* // Local Variables: // mode: C // c-file-style: "gnu" // indent-tabs-mode: nil // End: */