385 lines
9.2 KiB
C
385 lines
9.2 KiB
C
/*
|
|
configitem.c - generalized hierachy of configuration items
|
|
|
|
Copyright (C) Lumiera.org
|
|
2008, Christian Thaeter <ct@pipapo.org>
|
|
Simeon Voelkel <simeon_voelkel@arcor.de>
|
|
|
|
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 <ctype.h>
|
|
#include <stdint.h>
|
|
|
|
|
|
/**
|
|
* @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:
|
|
*/
|