 /*
  * Khoros: $Id: configtb.c,v 1.2 1992/03/20 22:52:01 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: configtb.c,v 1.2 1992/03/20 22:52:01 dkhoros Exp $";
#endif

 /*
  * $Log: configtb.c,v $
 * Revision 1.2  1992/03/20  22:52:01  dkhoros
 * VirtualPatch5
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.

 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as to the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including, for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1991 by UNM */
#include "kraftsman.h"
#include "ghost.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: configtb.c                             <<<<
   >>>>                                                       <<<<
   >>>>   description:                                        <<<<
   >>>>                                                       <<<<
   >>>>      routines: 					      <<<<
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

/***********************************************************************
*
*  Routine Name: _getln()
*
*          Date: February 17, 1992
*
*       Purpose: Get the next line in the config file
*
*         Input: pointer to string
*
*        Output: pointer to result string.. NULL if no string available
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
char *_getln(ptr)
  char **ptr;
  {
    char *nl, *ret;
    if (*ptr == NULL)
      return(NULL);
    nl = strchr(*ptr,'\n');
    if (nl == NULL)
      {
	ret = VStrcpy(*ptr);
        *ptr = NULL;
      }
    else
      {
	ret = VStrncpy(*ptr, (int) (nl - *ptr));
	*ptr = nl +1;
      }
    return(ret);
  }

/***********************************************************************
*
*  Routine Name: _getstr()
*
*          Date: February 17, 1992
*
*       Purpose: Get a next string in the config file
*
*         Input: pointer to string
*
*        Output: pointer to result string.. NULL if no string available
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
char *_getstr(ptr)
  char **ptr;
  {
    char *sp, *ret;

    if (*ptr == NULL)
      return(NULL);
    sp = strchr(*ptr,' ');
    if (sp == NULL)
      {
	ret = VStrcpy(*ptr);
	*ptr = NULL;
      }
    else
      {
	ret = VStrncpy(*ptr,(sp - *ptr));
	*ptr = sp + 1;
      }
    return(ret);
  }

/***********************************************************************
*
*  Routine Name: config2list()
*
*          Date:
*
*       Purpose: To read data out of the config file, and put it in
*		 a list CFG_ENTRY data structures
*
*         Input: index		-- starting index in form.
*		 cfg_index	-- address to count of cfg list.
*
*        Output: the CFG_ENTRY list
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
CFG_ENTRY *config2list( cfg_index, indx )
  int indx, *cfg_index;
  {
    char **km_config;
    char *cfgfile, *nl = NULL, *tmp, *tmp1;
    char *line, *line1;
    char **keynames[2];
    FILE *cfile;
    CFG_ENTRY *list = NULL;

    *cfg_index = 0;
    if ((cfgfile = vfullpath(CFGFILE, NULL, NULL)) == NULL)
      {
	xvf_error_wait("config2list: Can't open config file",
		       "Kraftsman Error", "ok");
	return(NULL);
      }

    if ((cfile = fopen (cfgfile,"r")) == NULL)
      {
	xvf_error_wait("config2list: Can't open config file",
		       "Kraftsman Error", "ok");
	return(NULL);
      }

    kraftsman_init_config_keys(keynames);
    km_config = gw_read_kraft_config(cfile,keynames,MaxKraftConfig);
    if (km_config == NULL)
      {
	xvf_error_wait("config2list: Can't open config file",
		       "Kraftsman Error", "ok");
	return(NULL);
      }

    nl = km_config[VarDefs];
    while ((nl != NULL) && ((line = _getln(&nl)) != NULL) && VStrlen(line) > 0)
      {
	line1 = line;
	tmp = _getstr(&line);
	list = add_cfg_entry(list, cfg_index , tmp, indx );
	free (tmp);
	VARVAL(list[*cfg_index-1]) = _getstr(&line);
	if (VARVAL(list[*cfg_index-1])[0] == '#')
	  {
	    while ((tmp = _getstr(&line)) != NULL)
	      {
		tmp1 = _getstr(&line);
		add_var_entry(list[*cfg_index-1], tmp, tmp1);
		free(tmp);
		free(tmp1);
	      }
	  }
	free(line1);
      }

    return(list);
  }

/***********************************************************************
*
*  Routine Name: create_cfg_entry()
*
*          Date: February 16, 1992
*
*       Purpose: To create a CFG_ENTRY data structure
*
*         Input: None
*
*        Output: returns a pointer to an empty CFG_ENTRY data structure
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
CFG_ENTRY create_cfg_entry()
  {
    CFG_ENTRY ret;
    ret = (CFG_ENTRY) calloc(1, sizeof(struct cfg_entry));

    if (ret == NULL)
      _xv_perror_wait("create_cfg_entry","create_cfg_entry");

    return(ret);
  }

/***********************************************************************
*
*  Routine Name: free_cfg_list()
*
*          Date: February 16, 1992
*
*       Purpose: To free a list of CFG_ENTRY structures
*
*         Input: lsize		-- List Size
*		 listaddr	-- List Pointer
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void free_cfg_list(listaddr, lsize)
  CFG_ENTRY *listaddr;
  int lsize;
  {
    int i,j;

    for(i = 0 ; i < lsize; i++)
      {
	kfree(VARVAL(listaddr[i]));
	clear_var_vals(&ENTRYLST(listaddr[i]),&ENTRYCNT(listaddr[i]));
	for (j = 0; j < FILEVARINDX(listaddr[i]) ; j++)
	  {
	    free(IVARIABLE(listaddr[i],j));
	    free(ISUBSTR(listaddr[i],j));
	  }
	free(VARIABLE(listaddr[i]));
	free(SUBSTR(listaddr[i]));
      }

    kfree(listaddr);
  }

/***********************************************************************
*
*  Routine Name: clear_var_vals()
*
*          Date: February 16, 1992
*
*       Purpose: Free a list of VAR_ENTRY structures
*
*	  Input: count		-- # number of structures to free.
*         	 varlist	-- pointer to list of vars to free
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void clear_var_vals(varlist,count)
  int *count;
  char ***varlist;
  {
    int i;
    for (i = 0; i < *count; i++)
      free((*varlist)[i]);
    *count = 0;
    kfree(*varlist);
    *varlist = NULL;
  }

/***********************************************************************
*
*  Routine Name: add_cfg_entry()
*
*          Date: February 16, 1992
*
*       Purpose: Free a list of CFG_ENTRY structures
*
*	  Input: cfg_index	-- # number of structures in list
*         	 cfg_list	-- pointer to list of structures
*		 vval		-- corresponding imake def variable
*		 index		-- Form database index value
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
CFG_ENTRY *add_cfg_entry(cfg_list, cfg_index, vval, index)
  CFG_ENTRY *cfg_list;
  char *vval;
  int index, *cfg_index;
  {
    CFG_ENTRY *newlist;

    newlist = cfg_list;
    if (((*cfg_index) % ALLOCSIZE) == 0)
      newlist = (CFG_ENTRY *) krealloc(newlist,(((((*cfg_index) / ALLOCSIZE) +1)
					* ALLOCSIZE) * sizeof (CFG_ENTRY)));
    newlist[*cfg_index] = create_cfg_entry();
    FORMVAR(newlist[*cfg_index]) = VStrcpy(vval);
    VARINDX(newlist[*cfg_index]) = index;
    (*cfg_index)++;
    return(newlist);
  }

/***********************************************************************
*
*  Routine Name: add_var_entry()
*
*          Date: February 16, 1992
*
*       Purpose: Add an entry to a list of VAR_ENTRY structures
*
*	  Input: var_index	-- # number of structures in list
*         	 var_list	-- pointer to list of structures
*		 var		-- Variable to store
*		 substr		-- Substitute string
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void add_var_entry(var_list, var, substr)
  CFG_ENTRY var_list;
  char *var;
  char *substr;
  {
    if ((FILEVARINDX(var_list) % ALLOCSIZE) == 0)
      {
	VARIABLE(var_list) = (char **) krealloc(VARIABLE(var_list),
		((((FILEVARINDX(var_list) / ALLOCSIZE) +1) * ALLOCSIZE)
		* sizeof (char *)));
	SUBSTR(var_list) = (char **) krealloc(SUBSTR(var_list),
		((((FILEVARINDX(var_list) / ALLOCSIZE) +1) * ALLOCSIZE)
		* sizeof (char *)));
      }
    IVARIABLE(var_list,FILEVARINDX(var_list)) = VStrcpy(var);
    ISUBSTR(var_list,FILEVARINDX(var_list)) = VStrcpy(substr);
    (FILEVARINDX(var_list))++;
    return;
  }

/***********************************************************************
*
*  Routine Name: add_entry()
*
*          Date: February 16, 1992
*
*       Purpose: Add an entry to a list of VAR_ENTRY structures
*
*	  Input: entry		-- pointer to cfg entry
*		 var		-- Variable to store
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void add_entry(entry, var)
  CFG_ENTRY entry;
  char *var;
  {
    if (ENTRYCNT(entry) == 0)
      ENTRYLST(entry) = (char **) calloc(ALLOCSIZE, sizeof(char *));
    else if (ENTRYCNT(entry) % ALLOCSIZE == 0)
      ENTRYLST(entry) = (char **) krealloc(ENTRYLST(entry),
	      (((ENTRYCNT(entry) / ALLOCSIZE)+1) * ALLOCSIZE) * sizeof(char *));
    IENTRYLST(entry,ENTRYCNT(entry)) = VStrcpy(var);
    ENTRYCNT(entry)++;

    return;
  }

/***********************************************************************
*
*  Routine Name: cfg2output()
*
*          Date: February 16, 1992
*
*       Purpose: use the list of variables to create the toolbox.def file.
*
*	  Input:  varlist	-- pointer to list of structures
*		  var_index	-- # of elements in varlist
*		  filename	-- pathname to toolbox.def file
*		  filearray	-- parsed toolbox.def file
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void cfg2output(varlist, varcnt, filename, filearray)
  CFG_ENTRY *varlist;
  int varcnt;
  char *filename;
  char **filearray;
  {
    int i = 0, j, k, list_index, entry_index, *arry;
    char line[LENGTH], line1[LENGTH];
    FILE *imakedef;

    (void) vfullpath(filename, NULL, line);
    if (access(line, W_OK) == -1)
      {
	xvf_error_wait("cfg2output: Can't write to imake definition file",
		       "Kraftsman Error", "ok");
	return;
      }
    (void) vreplace_string(line, ".def", ".old", line1);
    if (rename(line,line1) == -1)
      {
	xvf_error_wait("cfg2output: Can't access imake definition file",
		       "Kraftsman Error", "ok");
	return;
      }
    if ((imakedef = fopen(line,"w")) == NULL)
      {
	xvf_error_wait("cfg2output: Can't access imake definition file",
		       "Kraftsman Error", "ok");
	return;
      }
    if ((arry = (int *) kcalloc( varcnt , sizeof (int))) == NULL)
      {
	fprintf(stderr,"Out of Memory!\n");
	exit(-1);
      }
    while (filearray[i] != NULL)
      {
	if (strncmp(filearray[i], "&&VAR_", 5) == 0)
	  {
	    sscanf(filearray[i],"&&VAR_%d_%d", &list_index, &entry_index);
	    arry[list_index] = 1;
	    if (VARVAL(varlist[list_index])[0] != '#')
	      fprintf(imakedef, "%s = ", VARVAL(varlist[list_index]));
	    else
	      fprintf(imakedef, "%s = ", IVARIABLE(varlist[list_index],
						  entry_index));
	    if (ENTRYCNT(varlist[list_index]) == 0)
	      fprintf(imakedef, "/**/\n");
	    else
	      for (j = 0; j < ENTRYCNT(varlist[list_index]); j++)
		{
		  if (VARVAL(varlist[list_index])[0] == '#')
		    (void) vreplace_string(ISUBSTR(varlist[list_index],
					   entry_index),
					   VARVAL(varlist[list_index]),
					   IENTRYLST(varlist[list_index],j),
					   line1);
		  else
		    (void) strcpy(line1, IENTRYLST(varlist[list_index],j));
		  if (j < ENTRYCNT(varlist[list_index]) -1 && j > 0)
		    fprintf(imakedef, "\t\t%s \\\n",line1);
		  else if (j < ENTRYCNT(varlist[list_index]) -1)
		    fprintf(imakedef, "%s \\\n",line1);
		  else if (j > 0)
		    fprintf(imakedef, "\t\t%s\n",line1);
		  else
		    fprintf(imakedef, "%s\n",line1);
		}
	  }
	else
	  fputs(filearray[i], imakedef);
	i++;
      }
    for (i = 0 ; i < varcnt; i++)
      if (arry[i] != 1)
	{
	  for (k = 0; (k < FILEVARINDX(varlist[i]) ||
		       VARVAL(varlist[i])[0] != '#'); k++)
	    {
	      if (VARVAL(varlist[i])[0] != '#')
		fprintf(imakedef,"%s = ", VARVAL(varlist[i]));
	      else
		fprintf(imakedef, "%s = ", IVARIABLE(varlist[i],k));
	      if (ENTRYCNT(varlist[i]) == 0)
		fprintf(imakedef, " /**/\n");
	      else
		for (j = 0; j < ENTRYCNT(varlist[i]); j++)
		  {
		    if (VARVAL(varlist[list_index])[0] == '#')
		      (void) vreplace_string(ISUBSTR(varlist[i],k),
					       VARVAL(varlist[i]),
					       IENTRYLST(varlist[i],j),line1);
		    else
		      (void) strcpy(line1, IENTRYLST(varlist[i],j));
		    if (j < ENTRYCNT(varlist[i]) -1 && j > 0)
		      fprintf(imakedef, "\t\t%s \\\n",line1);
		    else if (j < ENTRYCNT(varlist[i]) -1)
		      fprintf(imakedef, "%s \\\n",line1);
		    else if (j > 0)
		      fprintf(imakedef, "\t\t%s\n",line1);
		    else
		      fprintf(imakedef, "%s\n",line1);
		  }
	      if (k >= FILEVARINDX(varlist[i]))
		break;
	    }
	}
    free(arry);
    fclose(imakedef);
  }

/***********************************************************************
*
*  Routine Name: _getvar()
*
*          Date: February 23, 1992
*
*       Purpose: To take a line of data, and extract the variable off
*		 the first part of the line
*
*         Input: line		- Line to get variable from
*
*	 Output: string containing the variable name
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
char *_getvar(line)
  char *line;
  {
    char *t;
    if ((t = vstrpbrk(line," =\n")) == NULL)
      return(NULL);
    else
      return(VStrncpy(line, (int) (t - line)));
  }

/***********************************************************************
*
*  Routine Name: _parse_var()
*
*          Date: February 23, 1992
*
*       Purpose: To scan the line for specific values of the variable
*
*         Input: line 		- Current line to read data from
*		 imakedef	- file pointer of open toolbox def file
*		 entry		- pointer to the cfg_entry struct that
*				  will store the values
*		 subvarcnt	- A count of how many vars to go in
*				  on the variable list
*
*        Output: none
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
void _parse_var(line, entry, subvarcnt)
  char *line;
  CFG_ENTRY entry;
  int subvarcnt;
  {
    char *start, *space, line1[LENGTH], *cur, *old = NULL;
    char *var, *tmp;
    int length;

    line1[0] = '\0';
    start = strchr(line, '=') + 1;
    if (start == NULL)
      {
	fprintf(stderr,"_parse_var: Fatal error! Can't find equal");
	fprintf(stderr,"sign.  Don't know how to continue.  Exiting...");
	exit(-1);
      }

    while (*start != '\0' && (*start == ' ' || *start == '\t'))
      start++;
    if (*start == '\0')
      return;

    cur = VStrcpy(start);
    old = cur;
    while ((var = vstrtok(cur," \n")) != NULL)
      {
	if (strncmp(var,"/**/",2) == 0)
	  {
	    cur = NULL;
	    continue;
	  }
        if (VStrlen(var) == 0)
	  {
	    cur = NULL;
	    continue;
	  }
	if (VARVAL(entry)[0] == '#')
	  {
	    start = var;
	    space = vstrstr(ISUBSTR(entry,subvarcnt), VARVAL(entry));
	    length = space - ISUBSTR(entry,subvarcnt);
	    start += length;
	    space += VStrlen(VARVAL(entry));
	    length = VStrlen(space);
	    if (length > 0)
	      {
		tmp = vstrstr(start, space);
		var = VStrncpy(start, tmp-start);
	      }
	    else
	      var = VStrcpy(start);
	  }
        add_entry(entry,var);
	cur = NULL;
      }
    kfree(old);
  }

/***********************************************************************
*
*  Routine Name: _changable_var()
*
*          Date: February 25, 1992
*
*       Purpose: Determine if the variable detected is a changable
*		 variable (i.e. it was in the km.config file)
*
*         Input: var		- variable name to check
*		 var_index	- index of entry containing variable (returned)
*		 subvar_index	- index of sub entry in entry struct (returned)
*		 list		- list of configure entry structures to check
*		 list_cnt	- number of structures in the list.
*
*        Output: var_index and subvar_index are set.
*		 returns TRUE if var was found
*		 FALSE otherwise.
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
int _changable_var(var, var_index, subvar_index, list, list_cnt)
  char *var;
  int *var_index, *subvar_index;
  CFG_ENTRY *list;
  int list_cnt;
  {
    int i,j, done = FALSE;
    for (i = 0 ; i< list_cnt && done == FALSE; i++)
      {
	if (VARVAL(list[i])[0] != '#' && VStrcmp(var, VARVAL(list[i])) == 0)
	  break;
	else if (VARVAL(list[i])[0] != '#')
	  continue;
	for (j = 0 ; j < FILEVARINDX(list[i]); j++)
	  if(VStrcmp(var, IVARIABLE(list[i],j)) == 0)
	    {
	      done = TRUE;
	      break;
	    }
      }
    i = (done == TRUE)? i - 1 : i;
    if (i < list_cnt)
      {
	*var_index = i;
	*subvar_index = (VARVAL(list[i])[0] == '#') ? j : 0;
	return(TRUE);
      }
    *var_index = -1;
    *subvar_index = -1;
    return(FALSE);
  }

/***********************************************************************
*
*  Routine Name: parsefile()
*
*          Date: March 6, 1992
*
*       Purpose: read the complete line out of the def file (dealing
*		 with \'s as well)
*
*	  Input: line		- current line of data
*		 f		- current file to read from
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
char *_get_full_line(line, f)
  char *line;
  FILE *f;
  {
    char *bkslash, *current, *cur, defstr[LENGTH], tmp[LENGTH];

    if (line == NULL) return(NULL);

    current = VStrcpy(line);
    bkslash = strrchr(current, '\\');
    while (bkslash != NULL)
      {
	*bkslash = '\0';
	if (fgets(defstr,LENGTH,f) == NULL)
	  return(current);
	if (vcleanup_string(defstr,tmp) == NULL)
	  continue;
	cur = VStrcat(current, tmp);
	kfree(current);
	current = cur;
	bkslash = strrchr(current, '\\');
      }
    return(current);
  }
  

/***********************************************************************
*
*  Routine Name: parsefile()
*
*          Date: February 23, 1992
*
*       Purpose: read the current variable values out of the def file
*
*	  Input: list		- List of variables to look for
*		 
*		 
*
*        Output: None
*
*    Written By: Steven Jorgensen
*
* Modifications:
*
***********************************************************************/
CFG_ENTRY *parsefile(list, listcnt, filename, contents)
  CFG_ENTRY *list;
  int listcnt;
  char *filename;
  char ***contents;
  {
    int subvarcnt, indx = 0, varindex;
    char line[LENGTH], *line1, line2[LENGTH], *var;
    FILE *imakedef;

    (void) vfullpath(filename, NULL, line);

    if (access(line, W_OK) == -1)
      {
	xvf_error_wait("parsefile: Can't access imake definition file",
		       "Kraftsman Error", "ok");
	*contents = NULL;
	return(NULL);
      }
    if ((imakedef = fopen(line,"r")) == NULL)
      {
	xvf_error_wait("parsefile: Can't access imake definition file",
		       "Kraftsman Error", "ok");
	*contents = NULL;
	return(NULL);
      }
    *contents = (char **) calloc(LENGTH, sizeof(char *));
    
    while (fgets(line,LENGTH,imakedef) != NULL)
      {
	(void) vcleanup_string(line, line2);
	if (isupper(line2[0]) == 1)
	  {
	    var = _getvar(line2);
	    if (_changable_var(var, &varindex, &subvarcnt, list, listcnt)==TRUE)
	      {
		line1 = _get_full_line(line2, imakedef);
		if (subvarcnt <= 0)
		  _parse_var(line1, list[varindex], subvarcnt);
		sprintf(line,"&&VAR_%2.2d_%2.2d\n",varindex,subvarcnt);
		free(line1);
	      }
	    free(var);
	  }
	if (indx > 0 && indx % LENGTH == 0)
	  *contents = (char **) krealloc(*contents, LENGTH * ((indx / LENGTH)
					 + 1 ) * sizeof(char *));
	(*contents)[indx] = VStrcpy(line);
	indx++;
      }
    fclose(imakedef);
    return(list);
  }
