
/**************************************************************************
 *                                                                        *
 * Copyright (c) 1996 Michael Richmond and Richard Treffers               *
 *                                                                        *
 *                    This software may be copied and distributed for     *
 *                    educational, research and not for profit services   *
 *                    provided that this copyright and statement are      *
 *                    included in all such copies.                        *
 *                                                                        *
 **************************************************************************/

#ifndef DEBUG
#undef DEBUG
#endif

/*	
	returns pointer to card image starting with instring
	symbol table name SYM_TABLE must be set in environment 
	strings of form
		xxx=yyy
	instring==xxx
	returns yyy or NULL if match is not found

	Author: R.R. Treffers

	Modified so that strings no longer translated into lower case when 
	put into the symbol table.  MWR 9/10/91.

	9/23/92 -remove get_float,put_float, and dead wood -rrt
	4/22/94 - cast strlen() 
	7/7/94 - add stdinclude for prototypes -rrt

	2/11/01 - re-wrote "putsym" entirely to avoid opening same file
	              twice, once for reading and once for writing.
		      Was causing seg faults in some circumstances.
		      Now hold all contents in memory briefly.
		      MWR

*/

#include "pcvista.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>

#define LF		10
#define CR		13

static void chomp(char *string);



char *
getsym(instring)		/* returns pointer to card image starting */
char *instring;				/* with instring */
{
	FILE *fp;
	int last;
	static char buf[NBUF], *rval;
	char *eq_loc,  *table;

	if ((table = getenv("SYM_TABLE")) == NULL)
		error(-1, "SYM_TABLE not set in environment");

	if ((fp = fopen(table, "r")) == NULL)
		return(NULL);

	rval = NULL;
	while (fgets(buf, NBUF, fp) != NULL) {
		eq_loc = strchr(buf, '=');			/* find location of equal sign */
		if (eq_loc != NULL){		
			*eq_loc = '\0';				/* convert buf to first string */
			if (!strcmp(buf, instring)) {
				rval = eq_loc + 1;			/* skip over = */
				break;
			}
		}	
	}
	if (rval != NULL) {
		last = strlen(rval) - 1;
		if (rval[last] == LF)	/* kill off dangling line feeds */
			rval[last] = 0;
	}
	fclose(fp);			
	return(rval);
}
	
/*	
	installs string in symbol table
	if second string is null, the symbol is removed
	calls error if failure
*/

void 
putsym(string)
char *string;
{
	FILE *fin, *fout;
	int nc, num_lines, i;
	int remove_flag = 0;
	int already_flag = 0;
	char **symbol_array;
	char buf[NBUF + 1], *table;
	char string_copy[NBUF + 1];

	/* 
	 * Truncate the input string at length "NBUF - 2", if necessary. 
	 * We need to leave room for a newline and a '\0' character
	 * at the end.
	 */
	strncpy(string_copy, string, NBUF - 2);
	string_copy[NBUF-1] = '\0';
	chomp(string_copy);

	/* 
	 * Set 'nc' to position of the equals sign in the string.
	 * A value like this:
	 *             foobar=
	 * means that the symbol will be removed from the table.
	 */
	for (nc = 0; nc < (int)strlen(string_copy); nc++) {
		if (string_copy[nc] == '=') {
			break;
		}
	}
	if (nc == strlen(string_copy) - 1) {
		remove_flag = 1;
	}

	if ((table = getenv("SYM_TABLE")) == NULL) {
		error(-1, "putsym: SYM_TABLE not set in environment");
	}

	/* 
	 * Check to see if the file exists.  If not, we just write the
	 *   desired information into it and quit.
	 */
	fin = fopen(table, "r");
	if (fin == NULL) {
		if ((fout = fopen(table, "w")) == NULL) {
			error(-1, "putsym: can't create symbol table");
		}
		fprintf(fout, "%s\n", string_copy);
		fclose(fout);
		return;
	}


	/* 
	 * Okay, so the file already exists.  We're going to read it
	 *   all into memory.
	 * 
	 * Step 1: Count the lines in the file, each of which has
	 *         at most NBUF characters.
	 */
	num_lines = 0;
	while (fgets(buf, NBUF, fin) != NULL) {
		num_lines++;
	}

	/*
	 * Step 2: Allocate space for the symbols in memory.
	 */
	if ((symbol_array = (char **) malloc(num_lines*sizeof(char *))) == 
			                    NULL) {
		error(-1, "putsym: can't malloc for copy of symbol table");
	}
	for (i = 0; i < num_lines; i++) {
		if ((symbol_array[i] = (char *) malloc(NBUF*sizeof(char))) == 
				            NULL) {
			error(-1, "putsym: can't malloc for contents of symbol table");
		}
	}

	/* 
	 * Step 3: Read contents of symbol table into memory 
	 */
	rewind(fin);
	for (i = 0; i < num_lines; i++) {
		if (fgets(symbol_array[i], NBUF, fin) == NULL) {
			error(-1, "putsym: error reading symbol table into memory");
		}
		chomp(symbol_array[i]);
	}
	fclose(fin);

	/* 
	 * Step 4: Check to see if the symbol given in "string_copy" is present
	 *         in the file already.  If so, we 
	 *
	 *           a. replace its entry in the "symbol_array" with the 
	 *                 value from "string_copy".
	 *       or
	 *           b. prepare to ignore it, if the "remove_flag" is set
	 */
	already_flag = 0;
	for (i = 0; i < num_lines; i++) {
		if (strncmp(symbol_array[i], string_copy, nc) == 0) {
			if (remove_flag == 1) {
				/* don't do anything ... */
#ifdef DEBUG
				printf("putsym: will remove entry: ..%s..\n",
						 symbol_array[i]);
#endif
			}
			else {
				/* replace contents with "string_copy" */
#ifdef DEBUG
				printf("putsym: will replace entry: ..%s..\n",
						 symbol_array[i]);
				printf("        with new entry:     ..%s..\n",
						 string_copy);
#endif
				strncpy(symbol_array[i], string_copy, NBUF);
			}
			already_flag = 1;
			break;
		}
	}
#ifdef DEBUG
	if (already_flag == 0) {
		printf("putsym: symbol ..%s.. not yet in table -- will add \n",
				string_copy);
	} else {
		printf("putsym: symbol ..%s.. already in table \n",
				string_copy);
	}
#endif

	/* 
	 * Step 5: Now, write the contents of the table back from 
	 *         memory into the file.
	 */
	if ((fout = fopen(table, "w")) == NULL) {
		error(-1, "putsym: can't re-write symbol table");
	}
	for (i = 0; i < num_lines; i++) {
		if (strncmp(symbol_array[i], string_copy, nc) == 0) {
			if (remove_flag == 1) {
				/* don't do anything ... */
			}
			else {
				fprintf(fout, "%s\n", symbol_array[i]);
			}
		} else {
			fprintf(fout, "%s\n", symbol_array[i]);
		}
	}
	/* if necessary, add a new line with this symbol to end of table */
	if (already_flag == 0) {
		fprintf(fout, "%s\n", string_copy);
	}
	fclose(fout);

	/* de-allocate memory */
	for (i = 0; i < num_lines; i++) {
		free(symbol_array[i]);
	}
	free(symbol_array);

}



/****************************************************************************
 * PROCEDURE: chomp
 *
 * DESCRIPTION: Given a string, walk through it from start to end.
 *              If a newline is encountered, replace the newline
 *              with a '\0' character, effectively ending the string
 *              at that point.
 *
 * RETURNS:
 *    nothing
 */

static void
chomp
	(
	char *string              /* I/O: replace newline with '\0' */
	)
{
	int i;

	for (i = 0; string[i] != '\0'; i++) {
		if (string[i] == '\n') {
			string[i] = '\0';
			break;
		}
	}
}
