static char *SccsId = "@(#)param.c 4.6 (TU-Delft) 03/03/93";
/**********************************************************

Name/Version      : aux/4.6

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Authors           : A.J. van Genderen
                  : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1988. All rights reserved.
**********************************************************/
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include "bool.h"
#include "aux.h"

extern double strtod ();
extern long   strol ();

static int verboseLevel = 0;

/* VARARGS2 */

/*
 * Report error for parameter <param>
 */
void paramError (param, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
char * param;
char * s;
{
    int l = strlen (s);
    char * n = NEW (char, l+2);
    strcpy (n, "\t");
    strcat (n, s);
    say ("error for parameter '%s'", param);
    say (n, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
    DISPOSE (n);
}

void paramSetVerbose (level)
int level;
{
    verboseLevel = level;
}

/*
 * read <paramfile>
 */
void paramReadFile (paramfile) 
char * paramfile;
{
    int    line;
    FILE * fp;
    char * key;
    char * val;
    char linebuf[200];

    fp = cfopen (paramfile, "r");

    line = 0;

    while (fgets (linebuf, sizeof (linebuf) - 1, fp)) {
	line++;
	linebuf[strlen(linebuf)-1] = '\0';      /* strip '\n' */
	key = strtok (linebuf, " \t");
	if (key == NULL || *key == '#') continue;

	/* since the string does not contain \n's,
	 * this delivers the rest of the string.
	 */
	val = strtok (NULL, "\n");
	if (val == NULL) val = "";

	Debug (fprintf (stderr,
	    "line %d: key <%s> val <%s>\n", line, key, val));

	paramSet (key, val);
    }
    fclose (fp);
}


static char * keys[100], *values[100];
static int paramIndex = 0;
static char * okeys[100], *ovalues[100];
static int optionIndex = 0;

/*
 * Set parameter <key> to <value>
 */
void paramSet (key, value)
char * key;
char * value;
{
    int i, l;
    char * v;
    if (value == NULL)
	value = "true";

    if (*value == '\0')
	value = "true";

    /* chop comment */
    l = strlen (value);	/* help the optimizer */
    for (i = 0; i < l; i++) {
	if (value[i] == '#') {
	    value[i] = '\0';
	    break;
	}
    }

    /* strip initial and trailing white space. */
    while (isspace (*value)) value++;

    v = value + strlen (value) - 1;
    while (isspace (*v)) v--;
    *(v + 1) = '\0';

    keys[paramIndex] = strsave (key);
    values[paramIndex] = strsave (value);
    paramIndex++;
}

void paramSetOption (option)
char * option;
{
    char * key;
    char * value;
    char * v;
    char buf[200];

    strcpy (buf, option);
    key = strtok (buf, "=");
    value = strtok (NULL, "\n");

    if (value == NULL)
	value = "true";

    if (*value == '\0')
	value = "true";

    /* strip initial and trailing white space. */
    while (isspace (*value)) value++;

    v = value + strlen (value) - 1;
    while (isspace (*v)) v--;
    *(v + 1) = '\0';

    okeys[optionIndex] = strsave (key);
    ovalues[optionIndex] = strsave (value);
    optionIndex++;
}

/*
 * Clear all parameters that were read with paramReadFile ()
 * or set with paramSet ().
 */
void paramFree ()
{
    int i;

    for (i = 0; i < paramIndex; i++) {
        DISPOSE (keys[i]);
        DISPOSE (values[i]);
    }

    paramIndex = 0;
}


/*
 * Lookup string value of <key>, but return <dflt> if <key> not found.
 */
char * paramLookupS (key, dflt)
char * key;
char * dflt;
{
    int i;

    /* search the tables backwards, so that last setting
     * in file overrules earlier settings.
     */
    for (i = optionIndex - 1; i >= 0; i--) {
	if (strsame (key, okeys[i])) {
	    if (verboseLevel)
		message ("parameter '%s' = '%s'", key, ovalues[i]);
	    return (ovalues[i]);
	}
    }

    for (i = paramIndex - 1; i >= 0; i--) {
	if (strsame (key, keys[i])) {
	    if (verboseLevel)
		message ("parameter '%s' = '%s'", key, values[i]);
	    return (values[i]);
	}
    }

    if (verboseLevel) {
	if (dflt)
	    message ("parameter '%s' not set, default '%s'", key, dflt);
	else
	    message ("parameter '%s' not set, no default", key);
    }

    return (dflt);
}

/*
 * Lookup <key> as a double value, and return <dflt> as double if not found.
 */
double paramLookupD (key, dflt)
char * key;
char * dflt;
{
    char * s = paramLookupS (key, dflt);
    char * p;
    double d;

    if (strsame (s, "inf") || strsame (s, "infinity")) {
	return (HUGE_VAL);
    }

    d = strtod (s, &p);

    if (p == s) {
	paramError (key,
"value '%s' is not a real number or 'inf'\n\
\tsubstituting default '%s'", s, dflt);
	if (strsame (dflt, "inf") || strsame (dflt, "infinity"))
	    d = HUGE_VAL;
	else
	    d = atof (dflt);
    }

    return (d);
}

int paramLookupI (key, dflt)
char * key;
char * dflt;
{
    char * s = paramLookupS (key, dflt);
    char * p;
    int i;

    if (strsame (s, "inf") || strsame (s, "infinity")) {
	return (MAXINT);
    }

    i = (int) strtol (s, &p, 10);

    if (p == s) {
	paramError (key,
"value '%s' is not an integer number or 'inf'\n\
\tsubstituting default '%s'", s, dflt);
	if (strsame (dflt, "inf") || strsame (dflt, "infinity"))
	    i = MAXINT;
	else
	    i = atoi (dflt);
    }

    return (i);
}

bool_t paramLookupB (key, dflt)
char * key;
char * dflt;
{
    char * v = paramLookupS (key, dflt);

    if (strcmp (v, "on") == 0) return (TRUE);
    if (strcmp (v, "off") == 0) return (FALSE);

    paramError (key,
	"value '%s' is not a toggle value, substituting default '%s'",
	v, dflt);

    v = dflt;

    if (strcmp (v, "on") == 0) return (TRUE);
    if (strcmp (v, "off") == 0) return (FALSE);

    /* internal error */
    ASSERT (0);

    return (FALSE);
}

# ifdef DRIVER
main (argc, argv)
int argc;
char * argv[];
{
    extern int optind;
    extern char *optarg;
    int i;
    int c;
    while ((c = getopt (argc, argv, "S:")) != EOF) {
	switch (c) {
	    case 'S': paramSetOption (optarg); break;
	    case '?': fprintf (stderr, "bad option %c\n", c);
	}
    }
    paramReadFile ("paramtest.p");

    for (i = optind; i < argc; i++) {
	fprintf (stderr, "param: <%s> value: <%s>\n", 
	    argv[i], paramLookupS (argv[i], NULL));
    }
}
# endif /* DRIVER */
/* EOF */
