/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:environ.c 12.0$ */
/* $ACIS:environ.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/lib/tools/RCS/environ.c,v $ */

#ifndef lint
static char *rcsid = "$Header:environ.c 12.0$";
#endif

#include <stdio.h>
#include <ctype.h>
#include <utils.h>
#include <hash.h>
#include <varargs.h>
#include "environ.h"

/***===================================================================***/

int env_debug;

static environ *current_env;
static FILE *yyin;

#define LEN_FIELDNAME 100
#define LEN_ARGSTRING 100

static int  argint;
static char argstring[LEN_FIELDNAME];
static char fieldname[LEN_ARGSTRING];
static int env_fldknt;

/***===================================================================***/

#include "eparser.c"


/***===================================================================***/

static
yyerror()
{
    D_ENTRY(env_debug,"yyerror()\n");
    RETURN(TRUE);
}

/***===================================================================***/

static char *
ef_TypeName(fld)
register2 env_field *fld;
{
register1 int flags;

    D_ENTRY1(env_debug,"ef_TypeName(0x%x)\n",fld);
    flags= fld->ef_flags;
    if (flags&EF_INT)    RETURN("INT");
    if (flags&EF_STRING) RETURN("STRING");
    if (flags&EF_ENUM)	 RETURN("ENUM");
    if (flags&EF_SET)	 RETURN("SET");
    RETURN("UNKNOWN");
}

/***===================================================================***/

env_field *
env_Field(env,name)
register1 environ *env;
register2 char    *name;
{
    D_ENTRY2(env_debug,"env_Field(0x%x,%s)\n",env,name);
    RETURN((env_field *)ht_get(env->env_fields,name));
}

/***===================================================================***/

env_AddInt(env,name,val)
register2 environ *env;
register3 char    *name;
register4 int      val;
{
register1 env_field *fld;
register5 char *type;

    D_ENTRY3(env_debug,"env_AddInt(0x%x,%s,%d)\n",env,name,val);
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld) {
	if (!fld->ef_flags&EF_INT) {
	    type= ef_TypeName(fld);
	    error2("%s defined as INT and %s\n",name,type);
	    action1("%s definition ignored\n",type);
	}
	u_free(fld->ef_name);
    }
    else {
	fld= (env_field *)u_malloc(sizeof(env_field));
    }
    fld->ef_flags= EF_INT;
    fld->ef_name= u_malloc(strlen(name)+1);
    strcpy(fld->ef_name,name);
    fld->ef_val.ef_ival= val;
    ht_put(env->env_fields,name,fld);
    RETURN(val);
}

/***===================================================================***/

char *
env_AddString(env,name,str)
register1 environ *env;
register2 char    *name;
register3 char    *str;
{
register1 env_field *fld;
register5 char *type;

    D_ENTRY3(env_debug,"env_AddString(0x%x,%s,%s)\n",env,name,str);
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld) {
	if (fld->ef_flags&EF_STRING) {
	    if (StrMatch(str,fld->ef_val.ef_sval))
	       RETURN(fld->ef_val.ef_sval);
	}
	else {
	    type= ef_TypeName(fld);
	    error2("%s defined as STRING and %s\n",name,type);
	    action1("%s definition ignored\n",type);
	}
	u_free(fld->ef_name);
    }
    else {
	fld= (env_field *)u_malloc(sizeof(env_field));
    }
    fld->ef_flags= EF_STRING;
    fld->ef_name= u_malloc(strlen(name)+1);
    strcpy(fld->ef_name,name);
    if (str) {
	fld->ef_val.ef_sval= u_malloc(strlen(str)+1);
	strcpy(fld->ef_val.ef_sval,str);
    }
    else fld->ef_val.ef_sval= NULL;
    ht_put(env->env_fields,name,fld);
    RETURN(fld->ef_val.ef_sval);
}

/***===================================================================***/

env_AddEnum(env,name,id)
register2 environ *env;
register3 char    *name;
register4 char    *id;
{
register1 env_field *fld;
register5 char *type;

    D_ENTRY3(env_debug,"env_AddEnum(0x%x,%s,%s)\n",env,name,id);
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld) {
	if (fld->ef_flags&EF_ENUM) {
	    if (StrMatch(id,fld->ef_val.ef_sval))
	       RETURN(TRUE);
	}
	else {
	    type= ef_TypeName(fld);
	    error2("%s defined as ENUM and %s\n",name,type);
	    action1("%s definition ignored\n",type);
	}
	u_free(fld->ef_name);
    }
    else {
	fld= (env_field *)u_malloc(sizeof(env_field));
    }
    fld->ef_flags= EF_ENUM;
    fld->ef_name= u_malloc(strlen(name)+1);
    strcpy(fld->ef_name,name);
    fld->ef_val.ef_sval= u_malloc(strlen(id)+1);
    strcpy(fld->ef_val.ef_sval,id);
    ht_put(env->env_fields,name,fld);
    RETURN(TRUE);
}

/***===================================================================***/

env_AddSet(env,name)
register2 environ *env;
register3 char    *name;
{
register1 env_field *fld;
register4 char *type;

    D_ENTRY2(env_debug,"env_AddSet(0x%x,%s)\n",env,name);
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld) {
	if (fld->ef_flags&EF_SET)
	    RETURN(TRUE);
	else {
	    type= ef_TypeName(fld);
	    error2("%s defined as SET VALUE and %s\n",name,type);
	    action1("%s definition ignored\n",type);
	}
	u_free(fld->ef_name);
    }
    else {
	fld= (env_field *)u_malloc(sizeof(env_field));
    }
    fld->ef_flags= EF_SET;
    fld->ef_name= u_malloc(strlen(name)+1);
    strcpy(fld->ef_name,name);
    ht_put(env->env_fields,name,fld);
    RETURN(TRUE);
}

/***===================================================================***/

static
env_ReadString(env)
register3 environ *env;
{
register1 int ch;
register2 int knt;
register4 int errors= FALSE;

   knt= 0;
   while ((ch=getc(yyin))!=env_Char(env,ENV_STR_END)) {
	if (ch==env_Char(env,ENV_STR_QUOTE)) 
	    ch= getc(yyin);
	if (ch==EOF)
	    break;
	if (knt<LEN_ARGSTRING-1)
	    argstring[knt++]= ch;
	else errors++;
   }
   argstring[knt++]= '\0';
   if (errors) {
       warning("Argument string too long\n");
       action1("truncated. Returning \"%s\"\n",argstring);
       RETURN(FALSE);
   }
   RETURN(TRUE);
}

/***===================================================================***/

static
env_ReadIdent(env,ch)
register3 environ *env;
register1 int ch;
{
register2 int knt;
register4 int errors= 0;

   knt= 0;
   while ((!isspace(ch))&&(ch!=EOF)&&(env_Token(env,ch)==ENV_NO_TOKEN)) {
	if ((env->env_flags&ENV_FOLDDOWN)&&(isupper(ch))) 
	    ch= tolower(ch);
	else if ((env->env_flags&ENV_FOLDUP)&&(islower(ch)))
	    ch= toupper(ch);
	if (knt<LEN_ARGSTRING-1) 
	     argstring[knt++]= ch;
	else errors++;
	ch= getc(yyin);
   }
   argstring[knt++]= 0;
   if (errors) {
       warning("Fieldname too long.\n");
       action1("truncated. Returning \"%s\"\n",fieldname);
       RETURN(FALSE);
   }
   if (ch!=EOF) 
       ungetc(ch,yyin);
   RETURN(TRUE);
}

/***===================================================================***/

static
yylex()
{
register1 int ch;

    D_ENTRY(env_debug,"yylex()\n");
    do {
	ch= getc(yyin);
    } while (isspace(ch));
    if (ch==EOF)
        RETURN(EOF);
    else if (isdigit(ch)) {
	argint= 0;
	while (isdigit(ch)) {
	    argint*= 10;
	    argint+= ch-'0';
	    ch= getc(yyin);
	}
	if (ch!=EOF)
	   ungetc(ch,yyin);
	RETURN(INTEGER);
    }

    switch (env_Token(current_env,ch)) {
	case ENV_NO_TOKEN:	
		env_ReadIdent(current_env,ch); 
		RETURN(IDENT);
	case ENV_STR_START:	    
		env_ReadString(current_env);   
		RETURN(STRING);
	case ENV_FIELD_START:	
		RETURN(START_FIELDS);
	case ENV_FIELD_END:	
		RETURN(END_FIELDS);
	case ENV_FIELD_SEP:	
		RETURN(SEPERATOR);
	case ENV_ASSIGN:	
		RETURN(GETS);
    }
    RETURN(BOGUS);
}

/***===================================================================***/

env_Token(env,ch)
register4 environ *env;
register2 char ch;
{
register1 int knt;

    D_ENTRY2(env_debug,"env_Token(0x%x,%c)\n",env,ch);
    for (knt=0;knt<ENV_NO_TOKEN;knt++) {
	if (ch==env->env_tokens[knt])
	   RETURN(knt);
    }
    RETURN(ENV_NO_TOKEN);
}

/***===================================================================***/

static int
env_Found(fil,env)
register1 FILE    *fil;
register2 environ *env;
{
register3 int   ch;
register4 int   knt;
register5 int   len;
register6 char *name;

    D_ENTRY2(env_debug,"env_Found(0x%x,0x%x)\n",fil,env);
    knt=0;
    name= env->env_name;
    len= strlen(name);
    while (knt<len) {
	ch= getc(fil);
	if (ch==name[knt])
	    argstring[knt++]= ch;
	else {
	    ungetc(ch,fil);
	    argstring[knt++]= '\0';
	    RETURN(FALSE);
	}
    }
    RETURN(TRUE);
}

/***===================================================================***/

char *
env_Parse(infil,env)
register1 FILE *infil;
register2 environ *env;
{

    D_ENTRY2(env_debug,"env_Parse(0x%x,0x%x)\n",infil,env);

    if (env_Found(infil,env)) {
	yyin= infil;
	current_env= env;
        if (yyparse()) 
	    RETURN(NULL);
        else {
	    register3 int ch;

	    while ((ch=getc(infil))!=EOF) {
		if (ch==env_Char(env,ENV_FIELD_END))
		   break;
	    }
	    error1("syntax error in description of %s\n",env->env_name);
	    action("skipping enviroment description\n");
	    RETURN(NULL);
        }
    }
    else {
	if (argstring[0]=='\0')
	     RETURN(NULL);
	else RETURN(argstring);
    }
}

/***===================================================================***/

int
env_SetVal(env,vals,dflt)
register1 environ  *env;
register2 env_enum *vals;
register3 int       dflt;
{
register4 env_field *fld;
register5 int        knt;
register7 char      *name= NULL;
register8 int        val= dflt;
register6 char      *dflt_name= NULL;

    D_ENTRY3(env_debug,"env_SetVal(0x%x,0x%x,%d)\n",env,vals,dflt);
    if (!env) {
       RETURN(dflt);
    }
    knt=0;
    while (vals[knt].ef_ename) {
	fld= (env_field *)ht_get(env->env_fields,vals[knt].ef_ename);
	if (fld) {
	    if (name) {
		error2("Set field multiply defined (%s and %s)\n",name,
							vals[knt].ef_ename);
		action1("ignoring %s\n",name);
	    }
            name= vals[knt].ef_ename;
	    val=  vals[knt].ef_eval;
	}
	if (vals[knt].ef_eval==dflt)
	   dflt_name= vals[knt].ef_ename;
	knt++;
    }
    if (dflt_name) {
	 env_AddSet(env,dflt_name);
	 fld= (env_field *)ht_get(env->env_fields,dflt_name);
	 fld->ef_flags|= EF_DEFAULT;
    }
    RETURN(val);
}

/***===================================================================***/

int
env_Enum(env,name,vals,dflt)
register1 environ  *env;
register2 char     *name;
register3 env_enum *vals;
register3 int       dflt;
{
register4 env_field *fld;
register5 int        knt= 0;
register6 char      *dflt_name;

    D_ENTRY4(env_debug,"env_Enum(0x%x,%s,0x%x,%d)\n",env,name,vals,dflt);
    if (!env) {
	RETURN(dflt);
    }
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld&&(fld->ef_flags&EF_ENUM)) {
	while (vals[knt].ef_ename) {
	    if (StrMatch(vals[knt].ef_ename,fld->ef_val.ef_sval)) {
		RETURN(vals[knt].ef_eval);
	    }
	    if (vals[knt].ef_eval==dflt)
	       dflt_name= vals[knt].ef_ename;
	    knt++;
	}
    }
    if (dflt_name) {
	env_AddEnum(env,name,dflt_name);
	fld= (env_field *)ht_get(env->env_fields,name);
	fld->ef_flags|= EF_DEFAULT;
    }
    RETURN(dflt);
}

/***===================================================================***/

int
env_Int(env,name,dflt)
register1 environ *env;
register2 char *name;
register3 int   dflt;
{
register4 env_field *fld;

    D_ENTRY3(env_debug,"env_Int(0x%x,%s,%d)\n",env,name,dflt);
    if (!env) {
       RETURN(dflt);
    }
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld&&(fld->ef_flags&EF_INT)) {
	 RETURN(fld->ef_val.ef_ival);
    }
    env_AddInt(env,name,dflt);
    fld= (env_field *)ht_get(env->env_fields,name);
    fld->ef_flags|= EF_DEFAULT;
    RETURN(dflt);
}

/***===================================================================***/

char *
env_String(env,name,dflt)
register1 environ *env;
register2 char *name;
register3 char *dflt;
{
register4 env_field *fld;

    D_ENTRY3(env_debug,"env_String(0x%x,%s,%s)\n",env,name,dflt);
    if (!env)
       RETURN(dflt);
    fld= (env_field *)ht_get(env->env_fields,name);
    if (fld&&(fld->ef_flags&EF_STRING)) {
	RETURN(fld->ef_val.ef_sval);
    }
    env_AddString(env,name,dflt);
    fld= (env_field *)ht_get(env->env_fields,name);
    fld->ef_flags|= EF_DEFAULT;
    RETURN(fld->ef_val.ef_sval);
}

/***===================================================================***/

env_IsDefault(env,name)
register2 environ *env;
register3 char	  *name;
{
register1 env_field *fld;

    D_ENTRY2(env_debug,"env_IsDefault(0x%x,%s)\n",env,name);
    if (!env)
       RETURN(FALSE);
    fld= (env_field *)ht_get(env->env_fields,name);
    RETURN((fld->ef_flags&EF_DEFAULT)!=0);
}

/***===================================================================***/

environ *
env_New(name,tokens,flags)
register2 char      *name;
register3 char      *tokens;
register4 int        flags;
{
register1 environ *etmp= (environ *)u_malloc(sizeof(environ));

    D_ENTRY3(env_debug,"env_New(%s,%s,%d,0x%x)\n",name,tokens,flags);
    etmp->env_name=   name;
    etmp->env_tokens= tokens;
    etmp->env_flags=  flags;
    etmp->env_fields= ht_new(23);
    RETURN(etmp);
}
    
/***===================================================================***/

env_HdrPrint(fil,name,tokens)
register1 FILE *fil;
register2 char *name;
register3 char *tokens;
{
    D_ENTRY3(env_debug,"env_HdrPrint(0x%x,%s,%s)\n",fil,name,tokens);
    fprintf(fil,"%s%c",name,tokens[ENV_FIELD_START]);
    env_fldknt=0;
    RETURN(TRUE);
}

/***===================================================================***/

env_StrPrint(fil,field,str,tokens)
register2  FILE *fil;
register4  char *field;
register1  char *str;
register3  char *tokens;
{

    D_ENTRY4(env_debug,"env_StrPrint(0x%x,%s,%s,%s)\n",fil,field,str,tokens);
    if (env_fldknt++)
       putc(tokens[ENV_FIELD_SEP],fil);
    fprintf(fil,"%s%c%c",field,tokens[ENV_ASSIGN],tokens[ENV_STR_START]);
    while (*str) {
	if (*str==tokens[ENV_STR_START])
	   putc(tokens[ENV_STR_QUOTE],fil);
	putc(*str,fil);
	str++;
    }
    putc(tokens[ENV_STR_END],fil);
    RETURN(TRUE);
}

/***===================================================================***/

env_IntPrint(fil,field,val,tokens)
register1  FILE *fil;
register2  char *field;
register3  int   val;
register4  char *tokens;
{
    D_ENTRY4(env_debug,"env_IntPrint(0x%x,%s,%d,%s)\n",fil,field,val,tokens);
    if (env_fldknt++)
       putc(tokens[ENV_FIELD_SEP],fil);
    fprintf(fil,"%s%c%d",field,tokens[ENV_ASSIGN],val);
    RETURN(TRUE);
}

/***===================================================================***/

env_EnumPrint(fil,field,val,tokens)
register1  FILE *fil;
register2  char *field;
register3  char *val;
register4  char *tokens;
{
    D_ENTRY4(env_debug,"env_EnumPrint(0x%x,%s,%s,%s)\n",fil,field,val,tokens);
    if (env_fldknt++)
       putc(tokens[ENV_FIELD_SEP],fil);
    fprintf(fil,"%s%c%s",field,tokens[ENV_ASSIGN],val);
    RETURN(TRUE);
}

/***===================================================================***/

env_SetPrint(fil,field,tokens)
register1  FILE *fil;
register2  char *field;
register3  char *tokens;
{
    D_ENTRY3(env_debug,"env_IntPrint(0x%x,%s,%s)\n",fil,field,tokens);
    if (env_fldknt++)
       putc(tokens[ENV_FIELD_SEP],fil);
    fprintf(fil,"%s",field);
    RETURN(TRUE);
}

/***===================================================================***/

env_EndPrint(fil,tokens)
register1  FILE *fil;
register4  char *tokens;
{
    D_ENTRY2(env_debug,"env_IntPrint(0x%x,%s)\n",fil,tokens);
    putc(tokens[ENV_FIELD_END],fil);
    putc('\n',fil);
    RETURN(TRUE);
}

