/*
** libconfiguration
** $Id: configuration.c,v 1.1 2008/02/04 04:22:29 sella Exp $
** Copyright (c) 2006 James M. Sella. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static const char rcsid[] = "$Id: configuration.c,v 1.1 2008/02/04 04:22:29 sella Exp $";

#include "configuration.h"

#include <string.h>
#include <stdio.h>
#include <syslog.h>

#include <errno.h>
#include <assert.h>

extern int errno;

int read_conf_file(const char *config_file, struct config_node **node) {
	int ret_val = 1;
	FILE *fp;

	if ((fp = fopen(config_file, "r")) != NULL) {
		ret_val = parse_config(fp, node, NULL);

		fclose(fp);
	}

	return ret_val;
}

void free_config_nodes(struct config_node *node) {
	struct config_node *n;

	while (node != NULL) {
		n = node;
		node = node->next;

		if (n->var) free(n->var);
		if (n->val) free(n->val);
		if (n->sub) free_config_nodes(n->sub);

		free(n);
	}
}

void print_config_nodes(struct config_node *node, int depth) {
	struct config_node *n;
	char *tab;

	/* Setup spacing */
	tab = malloc(depth * sizeof(char) + 1);
	memset(tab, ' ', depth * sizeof(char));
	tab[depth] = '\0';

	if (depth == 0) {
		syslog(LOG_INFO, "[Configuration]");
	}

	while (node != NULL) {
		n = node;
		node = node->next;

		if (n->sub) {
			if (n->val) {
				syslog(LOG_INFO, " %s<%s %s>", tab, n->var, n->val);
			} else {
				syslog(LOG_INFO, " %s<%s>", tab, n->var);
			}
			print_config_nodes(n->sub, depth + 4);
			syslog(LOG_INFO, " %s</%s>", tab, n->var);
		} else if (n->val) {
			syslog(LOG_INFO, " %s%s  %s", tab, n->var, n->val);
		} else {
			syslog(LOG_INFO, " %s%s", tab, n->var);
		}
	}

	free(tab);
}

int parse_config(FILE *fp, struct config_node** node_h, const char* level) {
	int i;
	size_t buf_len;
	char buf[1024], *buf_ptr = NULL, *ptr = NULL;
	struct config_node *node;

	assert(fp != NULL);
	assert(node_h != NULL);

	while (feof(fp) == 0 && ferror(fp) == 0) {
		if (fgets(buf, sizeof(buf), fp) != NULL) {
			/* Remove comments */
			buf_len = strlen(buf);
			for (i = 0; i < buf_len; i++) {
				if (buf[i] == ';' || buf[i] == '#') {
					buf[i] = '\0';
					break;
				}
			}

			if ((ptr = strtok_r(buf, " \t\r\n<>\"", &buf_ptr)) != NULL) {
				if (strstr(buf, "</") != NULL) { /* Block end */
					return 0;
				}

				/* Initialize node */
				*node_h = malloc(sizeof(struct config_node));
				node = *node_h;
				memset(node, 0, sizeof(struct config_node));

				if (strchr(buf, '<') != NULL) { /* Block start */
					node->var = strdup(ptr); /* Set block name */

					if ((ptr = strtok_r(NULL, " \t\r\n<>\"", &buf_ptr)) != NULL) { 
						if (node->val == NULL) { /* Set value */
							node->val = strdup(ptr);
						} else { /* Add to value */
							buf_len = strlen(node->val) + strlen(ptr) + 2;
							node->val = (char*) realloc(node->val, buf_len);
							strncat(node->val, " ", 1); /* Add space */
							strncat(node->val, ptr, buf_len); /* Set value */
						}
					}

					parse_config(fp, &(node->sub), node->var); /* Recursive call for sub node */
				} else { /* Normal keyword */
					node->var = strdup(ptr); /* Set variable */

					while ((ptr = strtok_r(NULL, " \t\r\n\"", &buf_ptr)) != NULL) {
						if (node->val == NULL) { /* Set value */
							node->val = strdup(ptr);
						} else { /* Add to value */
							buf_len = strlen(node->val) + strlen(ptr) + 2;
							node->val = (char*) realloc(node->val, buf_len);
							strncat(node->val, " ", 1); /* Add space */
							strncat(node->val, ptr, buf_len); /* Set value */
						}
					}
				}

				/* Move node to next */
				node_h = &(node->next);
			}
		}
	}
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim: noet ts=3 sw=3
*/
