/* vi: set sw=4 ts=4: */
/*
 * KON2 - Kanji ON Console -
 * Copyright (C) 1992-1996 Takashi MANABE (manabe@papilio.tutics.tut.ac.jp)
 *
 * CCE - Console Chinese Environment -
 * Copyright (C) 1998-2003 Rui He (rhe@3eti.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 */

#include	<stdio.h>
#include	<string.h>
#include	<unistd.h>
#include	<stdlib.h>

#include	<getcap.h>

#undef DEBUG  /* Rui He, we are not debugging CAP */

#define BUF_SIZE	2048
#define MAX_CAPS	30

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;
}

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

	if ((cp = FindCap(name)) != NULL) 
	{
#ifdef	DEBUG
		fprintf(stderr, "cap %s redefined (default %s)\r\n", name,
			def_value ? def_value : "None");
#endif
		if (cp->name) free(cp->name);  /* Added by security patch */
		cp->name = strdup(name);
		cp->func = func;
		if (cp->def_value) free(cp->def_value);  /* Added by security patch */
		if (def_value)
			cp->def_value = strdup(def_value);
		return;
	}

	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();
}

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";

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");
		perror(filename);
		return FAILURE;
	}

	while(fgets(line, MAX_COLS, capFp) != NULL) 
	{
	nextLabel:
		if ((p = strchr(line, '#')) != NULL)
			*p = '\0';
		if (strchr(line, ':') == NULL) continue; /* not a label */
		for (p = strtok(line, label_delim); p != NULL; 
				p = strtok(NULL, label_delim)) 
		{

			if ((c = FindCap(p)) != NULL) 
            {

				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) 
				{

					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 */
			}
		}
	}

	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++;
			}
		}
	}

	fclose(capFp);
#ifdef	DEBUG
	fprintf(stderr, "Finished reading config file\r\n");
#endif
	if (errors)
		return FAILURE;
	else
		return SUCCESS;
}

int	SetCapArg(const char *capName, const char *value)
{
	struct capability *cp;
	if ((cp = FindCap(capName)) == NULL) {
		return FAILURE;
	}
	if (cp->def_value == NULL) {

		return FAILURE;
	}

    if (cp->arg)
        free(cp->arg);

	cp->arg = strdup(value);
#ifdef	DEBUG
	fprintf(stderr, "Setting arg for %s to %s\r\n", capName, value);
#endif
	return SUCCESS;
}

bool BoolConf(const char *confstr)
{
	char name[MAX_COLS];

	sscanf(confstr, "%255s", 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;
}

char *skip_space(char *p)
{
	while (*p == ' ' || *p == '\t') p++;
	return p;
}

char *to_space(char *p)
{
	while(*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' && *p != '#') 
		p++; /* skip to the next space */
	return p;
}
