/*
	KON - Kanji ON Linux Console -
	Copyright (C) 1992, 1993 Takashi MANABE (manabe@tut.ac.jp)

	KON 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.

	KON 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	"big5con.h"

#define BUF_SIZE	1024

#define MAX_CAPS	20

static struct capability {
	char *name;			 /* Name of capability label */
	initializer *func;		 /* Function to perform configuration */
	int initialized;		 /* 1 if initialized */
	char *arg;			 /* Command line argument for this capability. */
	char *def_value;		 /* Default value.  NULL means required entry. */
} cap[MAX_CAPS];

static struct capability	*FindCap(const char *name)
{
	int	i;
	struct capability	*cp;

	for (i = 0, cp = cap; i < MAX_CAPS; i++, cp++) {
		if ((cp->name != NULL) && (strcasecmp(name, cp->name) == 0)) {
			return cp;
		}
	}
	return NULL;
}

/* Define initializer function func for capability name.  If def_value is nil,
   then the entry of the name must exist in configuration file.  An error is
   flagged if no entry is found.  If def_value is non-nil and no entry is found
   in configuration file, then func is invoked with def_value. */

void	DefineCap(const char *name, initializer *func, const char *def_value)
{
	int	i;
	struct capability	*cp;

	/* Pass 1 -- try to replace same name entry if exists. */
	if ((cp = FindCap(name)) != NULL) {
#ifdef	DEBUG
		fprintf(stderr, "cap %s redefined (default %s)\r\n", name,
			def_value ? def_value : "None");
#endif
		cp->name = strdup(name);
		cp->func = func;
		if (def_value)
			cp->def_value = strdup(def_value);
		return;
	}
	/* Pass 2 -- fine empty slot and insert new entry. */
	for (i = 0, cp = cap; i < MAX_CAPS; i++, cp++) {
		if (cp->name == NULL) {
#ifdef	DEBUG
			fprintf(stderr, "cap %s defined (default %s)\r\n", name,
				def_value ? def_value : "None");
#endif
			cp->name = strdup(name);
			cp->func = func;
			if (def_value)
				cp->def_value = strdup(def_value);
			return;
		}
	}
	fprintf(stderr, "Fatal: internal error - can't find room for capability `%s'\r\r\n", name);
	abort();
}

/* Delete all initializer functions. */

void CapInit(void)
{
	struct capability	*cp;
	int	i;

	for (i = 0, cp = cap; i < MAX_CAPS; i++, cp++) {
#ifdef	DEBUG
		if (cp->name) 
			fprintf(stderr, "cap %s deleted\r\n", cp->name);
#endif
		cp->initialized = 0;
		if (cp->name)
			free(cp->name);
		if (cp->arg)
			free(cp->arg);
		if (cp->def_value)
			free(cp->def_value);
		cp->name = cp->arg = cp->def_value = NULL;
	}
}

static const char label_delim[] = ":,; \t\n";

/* Read configuration file named filename and invoke initializer function for each entry. */

int	ReadConfig(const char *filename)
{
	FILE	*capFp;
	char	line[MAX_COLS], *p;
	char	buf[BUF_SIZE];
	struct capability *c;
	int	i;
	int	errors = 0;		 /* number of errors during configuration */

	if ((capFp = fopen(filename, "r")) == NULL) {
		fprintf(stderr, "Error: can't open config file\r\r\n");
#if 0 /* by b5c: no need read config if not exist */
		perror(filename);
		return FAILURE;
#endif
	}

	while(capFp != NULL && fgets(line, MAX_COLS, capFp) != NULL) {
	nextLabel:
		if ((p = strchr(line, '#')) != NULL)
			*p = '\0';
		if (strchr(line, ':') == NULL) continue; /* not a lebel */
		for (p = strtok(line, label_delim); p != NULL; p = strtok(NULL, label_delim)) {
			/* Process one label line. */
			if ((c = FindCap(p)) != NULL) {
				/* Found matching capability.  Get body from file. */
				char *l = buf;
				while (fgets(line, MAX_COLS, capFp) != NULL
				       && line[0] == '\t') {
					char *l2 = line;
					while (*l2 != '\n' && *l2 != '#') {
						*l++ = *l2++;
					}
					*l++ = '\n';
				}
				*l = '\0';
				if (! c->initialized) {
					/* do initialize */
					if (c->arg) {
#ifdef	DEBUG
						fprintf(stderr, "Capability %s set to arg %s\r\n",
							c->name, c->arg);
#endif
						if (c->func(c->arg) < 0)
							errors++;
					} else {
#ifdef	DEBUG
						fprintf(stderr, "Capability %s set to %s",
							c->name, buf);
#endif
						if (c->func(buf) < 0)
							errors++;
					}
					c->initialized = 1;
				}
				goto nextLabel;	/* next line already read */
			}
		}
	}
	/* Default initialization for unspecified capability. */
	for (i = 0, c = cap; i < MAX_CAPS; i++, c++) {
		if ((c->name != NULL) && !c->initialized) {
			if (c->arg) {
#ifdef	DEBUG
				fprintf(stderr, "Capability %s defaults to arg %s\r\n", c->name, c->arg);
#endif
				if (c->func(c->arg) < 0)
					errors++;
			} else if (c->def_value) {
#ifdef	DEBUG
				fprintf(stderr, "Capability %s defaults to %s\r\n", c->name, c->def_value);
#endif
				if (c->func(c->def_value) < 0)
					errors++;
			} else {
				fprintf(stderr, "Error: entry for capability `%s' not found\r\r\n", c->name);
				errors++;
			}
		}
	}
	if(capFp != NULL)
		fclose(capFp);
#ifdef	DEBUG
	fprintf(stderr, "Finished reading config file\r\n");
#endif
	if (errors)
		return FAILURE;
	else
		return SUCCESS;
}

/* Set value for capability capName. */
int	SetCapArg(const char *capName, const char *value)
{
	struct capability *cp;
	if ((cp = FindCap(capName)) == NULL) {
		return FAILURE;
	}
	if (cp->def_value == NULL) {
		/* Protected capability. */
		return FAILURE;
	}
	cp->arg = strdup(value);
#ifdef	DEBUG
	fprintf(stderr, "Setting arg for %s to %s\r\n", capName, value);
#endif
	return SUCCESS;
}

/* Utility function that return 1 if confstr is "On" and 0 if "OFF". */

bool BoolConf(const char *confstr)
{
	char name[MAX_COLS];
	sscanf(confstr, "%s", name);
	if (strcasecmp(name, "On") == 0 ||
	    strcasecmp(name, "True") == 0) {
		return TRUE;
	} else if (strcasecmp(name, "Off") != 0 &&
		   strcasecmp(name, "False") != 0) {
		fprintf(stderr, "Warning: value `%s' unrecognized as boolean; assuming `Off'\r\r\n",
		     name);
	}
	return FALSE;
}
