/***************************************************************************
    begin                : Fri Feb 11 2005
    copyright            : (C) 2005 - 2009 by Alper Akcan
    email                : alper.akcan@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License as        *
 *   published by the Free Software Foundation; either version 2.1 of the  *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 ***************************************************************************/

#include "xynth_.h"

char * s_config_strip (char *buf)
{
	char *start;

	/* Strip off trailing whitespace, returns, etc */
	while ((*buf != '\0') && (buf[strlen(buf) - 1] < 33)) {
		buf[strlen(buf) - 1] = '\0';
	}
	start = buf;

	/* Strip off leading whitespace, returns, etc */
	while (*start && (*start < 33)) {
		start++;
	}
	
	return start;
}

int s_config_parse (s_config_t *cfg, char *name)
{
        FILE *fp;
        char *buf;
        s_config_cat_t *category;
        s_config_var_t *variable;

	buf = (char *) s_malloc(sizeof(char) * (8192 + 1));
	
        fp = fopen(name, "r");
        if (fp == NULL) {
		debugf(DSYS, "Unable to open file : %s", name);
		goto err0;
	}

	while (!feof(fp)) {
		if (fgets(buf, 8192, fp)) {
			char *c;
			char *cur;

			/* strip comments */
			c = strchr(buf, ';');
			while (c) {
				if ((c == buf) || (*(c - 1) != '\\')) {
					*c = '\0';
				} else {
					*(c - 1) = ';';
					memmove(c, c + 1, strlen(c + 1));
				}
				c = strchr(c + 1, ';');
			}

			cur = s_config_strip(buf);
			if (*buf != '\0') {
				if (cur[0] == '[') {
					/* A category header */
					c = strchr(cur, ']');
					if (c) {
						*c = 0;
						if (!s_config_category_init(&category, cur + 1)) {
							s_list_add(cfg->category, category, -1);
						}
					} else {
						debugf(0, "parse error: no closing ']' for category %s of %s", cur + 1, name);
						goto err1;
					}
				} else if (cur[0] == '#') {
					/* A directive */
				} else {
					/* variable = value */
					category = (s_config_cat_t *) s_list_get(cfg->category, cfg->category->nb_elt - 1);
					if (category == NULL) {
						debugf(0, "parse error: There is no category context for %s", name);
						goto err1;
					}
					c = strchr(cur, '=');
					if (c) {
						*c = 0;
						c++;
						if (!s_config_variable_init(&variable, s_config_strip(cur), s_config_strip(c))) {
							s_list_add(category->variable, variable, -1);
						}
					} else {
						debugf(0, "parse error: No '=' (equal sign) in %s of %s", cur, name);
						goto err1;
					}
				}
			} else {
			}
		}
	}
	
	s_free(buf);
	fclose(fp);
	return 0;

err1:	fclose(fp);
err0:	s_free(buf);
	return -1;
}

int s_config_init (s_config_t **cfg)
{
	(*cfg) = (s_config_t *) s_malloc(sizeof(s_config_t));
	if (s_list_init(&((*cfg)->category))) {
		goto err0;
	}
	return 0;
err0:	s_free(*cfg);
	return -1;
}

int s_config_category_init (s_config_cat_t **cat, char *name)
{
	(*cat) = (s_config_cat_t *) s_malloc(sizeof(s_config_cat_t));
	(*cat)->name = strdup(name);
	if (s_list_init(&((*cat)->variable))) {
		goto err0;
	}
	return 0;
err0:	s_free((*cat)->name);
	s_free(*cat);
	return -1;
}

int s_config_variable_init (s_config_var_t **var, char *name, char *value)
{
	(*var) = (s_config_var_t *) s_malloc(sizeof(s_config_var_t));
	(*var)->name = strdup(name);
	(*var)->value = strdup(value);
	return 0;
}

int s_config_variable_uninit (s_config_var_t *var)
{
	s_free(var->name);
	s_free(var->value);
	s_free(var);
	return 0;
}

int s_config_category_uninit (s_config_cat_t *cat)
{
        while (!s_list_eol(cat->variable, 0)) {
		s_config_var_t *var = (s_config_var_t *) s_list_get(cat->variable, 0);
		s_list_remove(cat->variable, 0);
		s_config_variable_uninit(var);
	}
        s_list_uninit(cat->variable);
        s_free(cat->name);
	s_free(cat);
	return 0;
}

int s_config_uninit (s_config_t *cfg)
{
        while (!s_list_eol(cfg->category, 0)) {
		s_config_cat_t *cat = (s_config_cat_t *) s_list_get(cfg->category, 0);
		s_list_remove(cfg->category, 0);
		s_config_category_uninit(cat);
	}
        s_list_uninit(cfg->category);
	s_free(cfg);
	return 0;
}
