/*	:ts=4
 *	envparm -- obtain the default value for the given parameter
 *
 *	All parameters are strings; all return values are character pointers
 *	to internally malloc()'d character arrays.
 *
 *	The Manx compiler will generate code for GetEnv() which looks for
 *	the ENV: variable; the Lattice compiler WILL NOT generate code for
 *	the Manx getenv() call [the getenv() included here just returns NULL].
 *
 *	$Id: envparm.c,v 1.5 90/12/15 12:46:12 crash Exp Locker: crash $
 *
 *	$Log:	envparm.c,v $
 * Revision 1.5  90/12/15  12:46:12  crash
 * moved some environment checking around a little
 * 
 * Revision 1.4  90/10/13  17:51:03  crash
 * boy, was GetEnv() screwed up!  Basically I changed the whole flow so there
 * wouldn't be alot of code re-executing over and over again...
 * 
 * Revision 1.3  90/07/05  21:24:22  crash
 * removed getenv() from AZTEC_C code
 * 
 * Revision 1.2  90/05/22  17:23:53  crash
 * Oops, I forgot to declare getenv()
 * 
 * Revision 1.1  90/05/22  17:22:09  crash
 * Initial revision
 * 
 */

/*
 *	Check ENV: and if not found, look for a variable called "CNEWS", which
 *	is the name of a file to check in addition to the environments.
 *
 *	Of course, from what Larry told me, this will a be moot as WB2.0
 *	gains acceptance, since the get/put routines for environment variables
 *	will be part of the OS (yea!), but there's always "backwards
 *	compatibility" (sigh) :-(.
 */

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include "news.h"
#include "fgetmfs.h"

extern char *GetEnv(char *var);

struct _env {
	struct _env *next;
	char	*word;
	char	*value;
} *head = 0;

static int parse(char *src, char **word, char **value);
static struct _env *lookup(register char *word);
static char *putparm(register char *word, register char *value);
char *mkfilename(register char *dest, register char *dir, char *name);

static char *CNews_Config = 0;
#define NEWSCTL	"NewsCtl:"

char *envparm(register char *var)
{
	register char *ptr;
	register struct _env *env;

	/*
	 *	First, we cache the CNews.Config file...
	 */
	if (!CNews_Config) {
		/*
		 *	Process the contents of the config file...
		 */
		FILE *fp;
		int count = 0;
		char *word, *value;

		if (CNews_Config = GetEnv("CNEWS"))
			;
		else {
			word = GetEnv("NEWSCTL");
			CNews_Config = mkfilename(NULL, word ? word : NEWSCTL, "Cnews.Config");
			if (word) free(word);
		}
		if ((fp = fopen(CNews_Config, "r")) == NULL)
			return( NULL );
		while (ptr = fgetms(fp)) {
			count++;
			if (word = strchr(ptr, '#'))	*word = '\0';
			while (*ptr && isspace(*ptr)) ptr++;
			if (!*ptr) continue;

			if (!parse(ptr, &word, &value) || !putparm(word, value))
				error("Couldn't store environment variable!\n", word);
		}
		fclose(fp);
	}
	/*
	 *	Is the CNews.Config cached?  If so, then the variable
	 *	should be found here...
	 */
	if (env = lookup(var))
		return( env->value );
	if (ptr = GetEnv(var))		/* If NULL, it really isn't out there */
		putparm(var, ptr);		/*   otherwise, store it for later    */
	return( ptr );				/*   and return the value. */
}

static int parse(char *src, char **word, char **value)
{
	while (*src && isspace(*src)) src++;
	*word = src;
	while (*src && *src != '=' && !isspace(*src)) src++;
	if (!*src)
		return( 0 );

	*src++ = '\0';
	while (*src && *src != '"') src++;
	if (!*src)
		return( 0 );

	*value = ++src;
	src = strchr(src, '"');
	if (!src)
		return( 0 );

	*src = '\0';
	return( 1 );
}

#ifdef AZTEC_C
char *GetEnv(register char *word)
{
	register FILE *fp;
	register char *fname, *value = NULL;

	fname = str3save("ENV:", "", word);
	if (fp = fopen(fname, "r")) {
		value = fgetms(fp);
		fclose(fp);
	}
	free(fname);
	return( value );
}
#endif /* AZTEC_C */

static char *putparm(register char *word, register char *value)
{
	register struct _env *next;
	register int len = strlen(word) + 1;

	if (next = lookup(word)) {
		if (next->value = (char *) realloc(next->value, strlen(value)+1))
			strcpy(next->value, value);
		return( next->value );
	} else if (next = (struct _env *) malloc(sizeof(*next)+len)) {
		next->next  = head;
		next->word  = (char *) &next[1];	/* First byte after `next' */
		if (next->value = (char *) malloc(strlen(value)+1)) {
			strcpy(next->word, word);
			strcpy(next->value, value);
			head = next;
			return( next->value );
		}
	}
	return( NULL );
}

static struct _env *lookup(register char *word)
{
	register struct _env *next;
	register int len = strlen(word)+1;

	next = head;
	while (next) {
		if (!cistrncmp(next->word, word, len))
			return( next );
		next = next->next;
	}
	return( NULL );
}
