libSystem/src/config.c

334 lines
6.2 KiB
C

/* $Id$ */
/* Copyright (c) 2007 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libSystem */
/* libSystem is not free software; you can redistribute it and/or modify it
* under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike
* 3.0 Unported as published by the Creative Commons organization.
*
* libSystem 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 Creative Commons Attribution-NonCommercial-
* ShareAlike 3.0 Unported license for more details.
*
* You should have received a copy of the Creative Commons Attribution-
* NonCommercial-ShareAlike 3.0 along with libSystem; if not, browse to
* http://creativecommons.org/licenses/by-nc-sa/3.0/ */
/* TODO:
* - use the error reporting framework */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "System.h"
/* Config */
/* private */
/* types */
/* FIXME should be an API to avoid this */
typedef struct _HashEntry
{
char * name;
void * data;
} HashEntry;
/* public */
/* functions */
/* config_new */
Config * config_new(void)
{
Config * config;
if((config = hash_new()) == NULL)
return NULL;
return config;
}
/* config_delete */
void config_delete(Config * config)
{
size_t i;
HashEntry * hi;
int j;
HashEntry * hj;
for(i = array_count(config); i > 0; i--)
{
hi = array_get(config, i - 1);
for(j = array_count(hi->data); j > 0; j--)
{
hj = array_get(hi->data, j - 1);
free(hj->data);
}
hash_delete(hi->data);
}
hash_delete(config);
}
/* accessors */
/* config_get */
char * config_get(Config * config, char const * section, char const * variable)
{
Hash * h;
char * value;
if((h = hash_get(config, section)) != NULL) /* found section */
{
if((value = hash_get(h, variable)) != NULL) /* found value */
return value;
if(section[0] == '\0')
error_set_code(1, "%s%s", variable, ": Not found in"
" default section");
else
error_set_code(1, "%s%s%s", variable, ": Not found in"
" section ", section);
return NULL;
}
if(section[0] == '\0')
error_set_code(1, "%s", "default section: Not found");
else
error_set_code(1, "%s%s%s", "section ", section, ": Not found");
return NULL;
}
/* config_set */
int config_set(Config * config, char const * section, char const * variable,
char const * value)
{
Hash * h;
char * p;
if((h = hash_get(config, section)) == NULL)
{
if((h = hash_new()) == NULL)
return 1;
if(hash_set(config, section, h) == 1)
{
hash_delete(h);
return 1;
}
}
if(value == NULL)
return hash_set(h, variable, NULL) == 0 ? 0 : 1;
if((p = string_new(value)) == NULL)
return 1;
if(hash_set(h, variable, p) == 0)
return 0;
free(p);
return 1;
}
/* useful */
/* config_load */
static char * _load_section(FILE * fp);
static char * _load_variable(FILE * fp, int c);
static char * _load_value(FILE * fp);
int config_load(Config * config, char const * filename)
{
FILE * fp;
char * section;
char * variable = NULL;
int c;
char * str;
int ret = 0;
if((section = string_new("")) == NULL
|| (fp = fopen(filename, "r")) == NULL)
{
free(section);
return error_set_code(1, "%s%s%s", filename, ": ",
strerror(errno));
}
while((c = fgetc(fp)) != EOF)
{
if(c == '#')
while((c = fgetc(fp)) != EOF && c != '\n');
else if(c == '[')
{
if((str = _load_section(fp)) == NULL)
break;
free(section);
section = str;
}
else if(isprint(c))
{
if((str = _load_variable(fp, c)) == NULL)
break;
free(variable);
variable = str;
if((str = _load_value(fp)) == NULL)
break;
config_set(config, section, variable, str);
free(str);
}
else if(c != '\n')
break;
}
free(section);
free(variable);
if(!feof(fp))
{
errno = EINVAL;
ret = 1;
}
fclose(fp);
return ret;
}
static char * _load_section(FILE * fp)
{
int c;
char * str = NULL;
size_t len = 0;
char * p;
while((c = fgetc(fp)) != EOF && c != ']' && isprint(c))
{
if((p = realloc(str, sizeof(char) * (len + 2))) == NULL)
{
free(str);
return NULL;
}
str = p;
str[len++] = c;
}
if(c != ']')
{
free(str);
return NULL;
}
if(str == NULL)
return strdup("");
str[len] = '\0';
return str;
}
static char * _load_variable(FILE * fp, int c)
{
char * str;
int len = 1;
char * p;
if((str = malloc(sizeof(char) * (len+1))) == NULL)
return NULL;
str[0] = c;
while((c = fgetc(fp)) != EOF && c != '=' && isprint(c))
{
if((p = realloc(str, sizeof(char) * (len+2))) == NULL)
{
free(str);
return NULL;
}
str = p;
str[len++] = c;
}
if(c != '=')
{
free(str);
return NULL;
}
str[len] = '\0';
return str;
}
static char * _load_value(FILE * fp)
{
int c;
char * str = NULL;
int len = 0;
char * p;
while((c = fgetc(fp)) != EOF && isprint(c))
{
if((p = realloc(str, sizeof(char) * (len+2))) == NULL)
{
free(str);
return NULL;
}
str = p;
str[len++] = c;
}
if(c != '\n')
{
free(str);
return NULL;
}
if(str == NULL)
return string_new("");
str[len] = '\0';
return str;
}
/* config_save */
static int _save_section(Hash * h, size_t i, FILE * fp);
static int _save_variables(Hash * h, FILE * fp);
int config_save(Config * config, char const * filename)
{
FILE * fp;
size_t i;
size_t j;
int ret = 0;
if((i = array_count(config)) == 0)
return 1;
if((fp = fopen(filename, "w")) == NULL)
{
fprintf(stderr, "%s", "libutils: ");
perror(filename);
return 1;
}
for(j = 0; j < i; j++)
if((ret = _save_section(config, j, fp)) != 0)
break;
fclose(fp);
return ret;
}
static int _save_section(Hash * h, size_t i, FILE * fp)
{
HashEntry * he;
he = array_get(h, i);
if(he->name[0] != '\0')
{
if(fprintf(fp, "[%s]\n", he->name) < 0)
return 1;
}
else if(i != 0)
if(fwrite("[]\n", sizeof(char), 3, fp) != 3)
return 1;
if(_save_variables(he->data, fp) != 0)
return 1;
return fputc('\n', fp) == '\n' ? 0 : 1;
}
static int _save_variables(Hash * h, FILE * fp)
{
size_t i;
size_t j;
HashEntry * he;
i = array_count(h);
for(j = 0; j < i; j++)
{
he = array_get(h, j);
if(he->name == NULL || he->data == NULL)
continue;
if(fprintf(fp, "%s=%s\n", he->name, (char*)he->data) < 0)
return 1;
}
return 0;
}