merged the modularization branch (credentials) back to trunk
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
|
||||
typedef struct private_settings_t private_settings_t;
|
||||
typedef struct section_t section_t;
|
||||
typedef struct kv_t kv_t;
|
||||
|
||||
/**
|
||||
* private data of settings
|
||||
*/
|
||||
struct private_settings_t {
|
||||
|
||||
/**
|
||||
* public functions
|
||||
*/
|
||||
settings_t public;
|
||||
|
||||
/**
|
||||
* top level section
|
||||
*/
|
||||
section_t *top;
|
||||
|
||||
/**
|
||||
* allocated file text
|
||||
*/
|
||||
char *text;
|
||||
};
|
||||
|
||||
/**
|
||||
* section containing subsections and key value pairs
|
||||
*/
|
||||
struct section_t {
|
||||
|
||||
/**
|
||||
* name of the section
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* subsections, as section_t
|
||||
*/
|
||||
linked_list_t *sections;
|
||||
|
||||
/**
|
||||
* key value pairs, as kv_t
|
||||
*/
|
||||
linked_list_t *kv;
|
||||
};
|
||||
|
||||
/**
|
||||
* Key value pair
|
||||
*/
|
||||
struct kv_t {
|
||||
|
||||
/**
|
||||
* key string, relative
|
||||
*/
|
||||
char *key;
|
||||
|
||||
/**
|
||||
* value as string
|
||||
*/
|
||||
char *value;
|
||||
};
|
||||
|
||||
static char *find(section_t *section, char *key)
|
||||
{
|
||||
char *name, *pos, *value = NULL;
|
||||
enumerator_t *enumerator;
|
||||
kv_t *kv;
|
||||
section_t *current, *found = NULL;
|
||||
|
||||
if (section == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = strdupa(key);
|
||||
|
||||
pos = strchr(name, '.');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
enumerator = section->sections->create_enumerator(section->sections);
|
||||
while (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
if (streq(current->name, name))
|
||||
{
|
||||
found = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
if (found)
|
||||
{
|
||||
return find(found, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enumerator = section->kv->create_enumerator(section->kv);
|
||||
while (enumerator->enumerate(enumerator, &kv))
|
||||
{
|
||||
if (streq(kv->key, name))
|
||||
{
|
||||
value = kv->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of settings_t.get.
|
||||
*/
|
||||
static char* get_str(private_settings_t *this, char *key, char *def)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = find(this->top, key);
|
||||
if (value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of settings_t.get_bool.
|
||||
*/
|
||||
static bool get_bool(private_settings_t *this, char *key, bool def)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = find(this->top, key);
|
||||
if (value)
|
||||
{
|
||||
if (strcasecmp(value, "true") == 0 ||
|
||||
strcasecmp(value, "enables") == 0 ||
|
||||
strcasecmp(value, "yes") == 0 ||
|
||||
strcasecmp(value, "1") == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcasecmp(value, "false") == 0 ||
|
||||
strcasecmp(value, "disabled") == 0 ||
|
||||
strcasecmp(value, "no") == 0 ||
|
||||
strcasecmp(value, "0") == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of settings_t.get_int.
|
||||
*/
|
||||
static int get_int(private_settings_t *this, char *key, int def)
|
||||
{
|
||||
char *value;
|
||||
int intval;
|
||||
|
||||
value = find(this->top, key);
|
||||
if (value)
|
||||
{
|
||||
errno = 0;
|
||||
intval = strtol(value, NULL, 10);
|
||||
if (errno == 0)
|
||||
{
|
||||
return intval;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* destry a section
|
||||
*/
|
||||
static void section_destroy(section_t *this)
|
||||
{
|
||||
this->kv->destroy_function(this->kv, free);
|
||||
this->sections->destroy_function(this->sections, (void*)section_destroy);
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse text, truncate "skip" chars, delimited by term respecting brackets.
|
||||
*
|
||||
* Chars in "skip" are truncated at the beginning and the end of the resulting
|
||||
* token. "term" contains a list of characters to read up to (first match),
|
||||
* while "br" contains bracket counterparts found in "term" to skip.
|
||||
*/
|
||||
static char parse(char **text, char *skip, char *term, char *br, char **token)
|
||||
{
|
||||
char *best = NULL;
|
||||
char best_term = '\0';
|
||||
|
||||
/* skip leading chars */
|
||||
while (strchr(skip, **text))
|
||||
{
|
||||
(*text)++;
|
||||
if (!**text)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* mark begin of subtext */
|
||||
*token = *text;
|
||||
while (*term)
|
||||
{
|
||||
char *pos = *text;
|
||||
int level = 1;
|
||||
|
||||
/* find terminator */
|
||||
while (*pos)
|
||||
{
|
||||
if (*pos == *term)
|
||||
{
|
||||
level--;
|
||||
}
|
||||
else if (br && *pos == *br)
|
||||
{
|
||||
level++;
|
||||
}
|
||||
if (level == 0)
|
||||
{
|
||||
if (best == NULL || best > pos)
|
||||
{
|
||||
best = pos;
|
||||
best_term = *term;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
/* try next terminator */
|
||||
term++;
|
||||
if (br)
|
||||
{
|
||||
br++;
|
||||
}
|
||||
}
|
||||
if (best)
|
||||
{
|
||||
/* update input */
|
||||
*text = best;
|
||||
/* null trailing bytes */
|
||||
do
|
||||
{
|
||||
*best = '\0';
|
||||
best--;
|
||||
}
|
||||
while (best >= *token && strchr(skip, *best));
|
||||
/* return found terminator */
|
||||
return best_term;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a section
|
||||
*/
|
||||
static section_t* parse_section(char **text, char *name)
|
||||
{
|
||||
section_t *sub, *section;
|
||||
bool finished = FALSE;
|
||||
char *key, *value, *inner;
|
||||
|
||||
static int lev = 0;
|
||||
lev++;
|
||||
|
||||
section = malloc_thing(section_t);
|
||||
section->name = name;
|
||||
section->sections = linked_list_create();
|
||||
section->kv = linked_list_create();
|
||||
|
||||
while (!finished)
|
||||
{
|
||||
switch (parse(text, "\t\n ", "{=#", NULL, &key))
|
||||
{
|
||||
case '{':
|
||||
if (parse(text, "\t ", "}", "{", &inner))
|
||||
{
|
||||
sub = parse_section(&inner, key);
|
||||
if (sub)
|
||||
{
|
||||
section->sections->insert_last(section->sections, sub);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
if (parse(text, "\t ", "\n", NULL, &value))
|
||||
{
|
||||
kv_t *kv = malloc_thing(kv_t);
|
||||
kv->key = key;
|
||||
kv->value = value;
|
||||
section->kv->insert_last(section->kv, kv);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
parse(text, "", "\n", NULL, &value);
|
||||
continue;
|
||||
default:
|
||||
finished = TRUE;
|
||||
continue;
|
||||
}
|
||||
section_destroy(section);
|
||||
return NULL;
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of settings_t.destroy
|
||||
*/
|
||||
static void destroy(private_settings_t *this)
|
||||
{
|
||||
if (this->top)
|
||||
{
|
||||
section_destroy(this->top);
|
||||
}
|
||||
free(this->text);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* see header file
|
||||
*/
|
||||
settings_t *settings_create(char *file)
|
||||
{
|
||||
private_settings_t *this = malloc_thing(private_settings_t);
|
||||
|
||||
this->public.get_str = (char*(*)(settings_t*, char *key, char* def))get_str;
|
||||
this->public.get_int = (int(*)(settings_t*, char *key, bool def))get_int;
|
||||
this->public.get_bool = (bool(*)(settings_t*, char *key, bool def))get_bool;
|
||||
this->public.destroy = (void(*)(settings_t*))destroy;
|
||||
|
||||
this->top = NULL;
|
||||
this->text = NULL;
|
||||
|
||||
if (file)
|
||||
{
|
||||
FILE *fd;
|
||||
int len;
|
||||
char *pos;
|
||||
|
||||
fd = fopen(file, "r");
|
||||
if (fd == NULL)
|
||||
{
|
||||
return &this->public;
|
||||
}
|
||||
fseek(fd, 0, SEEK_END);
|
||||
len = ftell(fd);
|
||||
rewind(fd);
|
||||
this->text = malloc(len + 1);
|
||||
this->text[len] = '\0';
|
||||
if (fread(this->text, 1, len, fd) != len)
|
||||
{
|
||||
free(this->text);
|
||||
this->text = NULL;
|
||||
return &this->public;
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
pos = this->text;
|
||||
this->top = parse_section(&pos, NULL);
|
||||
if (this->top == NULL)
|
||||
{
|
||||
free(this->text);
|
||||
this->text = NULL;
|
||||
return &this->public;
|
||||
}
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user