
/*
 * Copyright 1993, 1994, 1995 by the Regents of the University of California
 * see the file "Copyright" in the distribution for conditions of use.
 */

#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include "node.h"

#define is_white(ch)	((ch) == ' ' || (ch) == '\t' )
#define SKIP_WHITE(ptr)	while( is_white(*ptr) ) ptr++ ;

static char symbol[LAB_LEN+1];
static char *line_ptr;
#define MAX_LINE_LEN 200
static char line[MAX_LINE_LEN+2];

int
read_descrip( config_file )
FILE *config_file;
{
	/* read in and check global menu description file */

	read_nodes( config_file );
	check_nodes();
	return( find_node( "main" ));
}

static
read_nodes( config_file )
FILE *config_file;
{
	NODE temp_node;

	/* read and save menu description */

	/* make sure strchr() won't fail */
	line[MAX_LINE_LEN] = '\n';
	line[MAX_LINE_LEN+1] = '\0';

	/* read up to #End-menu - entries are commands or menus */
	for( n_nodes = 0; read_node( &temp_node, config_file ) != 0
				&& n_nodes < MAX_NODES;  ) {
		if( node[n_nodes] != NULL ) continue;
		node[n_nodes] = (NODE *)malloc( sizeof( NODE ) );
		if(node[n_nodes] == NULL ) desc_err("can't allocate space");
		/* check this node name doesn't duplicate earlier node */
		if( find_node( temp_node.nd_label ) != -1 ) {
			printf("*** Node name \"%s\" used to label two nodes\n",
						temp_node.nd_label); 
			printf("*** Second usage will be ignored\n\n");
			sleep(2);
		} else {
			*node[n_nodes] = temp_node;
			n_nodes++;
		}
	};
	if( n_nodes == MAX_NODES ) {
		printf("description file too long - truncated\n");
		sleep(2);
	}
	if( n_nodes == 0 ) {
		desc_err("no items in menu");
	}
}

static
read_node( node_in, config_file )
NODE *node_in;
FILE *config_file;
{
	char *ptr;
	char term_char;
	int i;

	/* read single node - menu or command */

read_line:
	/* first read line with label, type, title */
	if( fgets( line, MAX_LINE_LEN, config_file ) == NULL ) return(0);
	if( strncmp( line, "End-Menu", 8 ) == 0 ) return( 0 );
	*(strchr(line,'\n')) = '\0';
	line_ptr = line;

	/* ignore line starting with # */
	if( *line_ptr == '#' ) goto read_line;

	/* line starts with type of node, e.g. MENU, CMND, ...
	 * save node type.
	 */
	if( get_symbol() == 0 ) goto read_line;
	if( strcasecmp( symbol, "menu" ) == 0 ) {
		node_in->nd_type = TYPE_MENU;
		term_char = '/';
	} else if( strcasecmp( symbol, "cmnd" ) == 0 ) {
		node_in->nd_type = TYPE_COMMAND;
		term_char = '.';
	} else {
		desc_err("unrecognizable node type");
	}

	/* next save the node name */

	if( get_symbol() == 0 ) desc_err("missing name for node");
	strcpy( node_in->nd_label, symbol );

	/* rest of line is node title */

	SKIP_WHITE( line_ptr );
	ptr = strchr( line_ptr, '\0' );
	while( is_white(*(ptr-1)) && ptr > line_ptr ) ptr--;
	*ptr = '\0';
	/* check if it is too long - if so, truncate */
	if( ptr - line_ptr >= MAX_TITLE_LEN - 1 ) {
		ptr = line_ptr+MAX_TITLE_LEN - 2;
		*ptr = '\0';
		printf("title is too long, truncated to:\n%s\n", line_ptr );
		sleep(2);
	}
	if( *line_ptr == '\0' ) desc_err("No title for node");

	/* copy and save node title */
	/* first add termination character: '/' for menus, '.' for commands */
	*ptr = term_char;
	*(ptr+1) = '\0';
	strcpy( node_in->nd_title, line_ptr );



	/* read line with command or list of other nodes */
	if( fgets( line, MAX_LINE_LEN, config_file ) == NULL ) {
		desc_err("missing command or node list");
	}
	*(strchr(line,'\n')) = '\0';
	line_ptr = line;

	
	if( node_in->nd_type == TYPE_MENU ) {
		/* menu:  read in & save names of nodes in menu */
		for( i = 0; i < MAX_MENU_ENTRIES; i++ ) {
			SKIP_WHITE( line_ptr );
			if( get_symbol() == 0 ) break;
			strcpy( node_in->nd_labs[i], symbol );
		}
		node_in->nd_n = i;
	} else if( node_in->nd_type == TYPE_COMMAND ) {
		if( *line_ptr != '=' ) {
			desc_err("actual command for node is missing");
		}
		/* rest of line is actual command */
		ptr = strchr(line_ptr, '\0');
		ptr--;
		while( is_white(*ptr) && ptr > line_ptr ) ptr--;
		ptr++;
		*ptr = '\0';
		if( ptr - line_ptr >= MAX_CMND_LEN ) {
			desc_err("command is too long");
		}
		strcpy( node_in->nd_command, ++line_ptr );
		node_in->nd_n = 0;
	} else {
		desc_err("program bug");
	}

	node_in->nd_menu = NULL;
	return(1);
}

int
find_node( label )
char *label;
{
	int i;

	/*
	 *	find node[] index for node with specified label.
	 */

	for( i = 0; i < n_nodes; i++ ) {
		if( strcmp( label, &(*node[i]->nd_label) ) == 0 ) {
			return( i );
		}
	}
	return(-1);
}

static int
get_symbol()
{
	char *sym_ptr;
	int i;

	/*	
	 *	get next symbol from line[]; return it in symbol[],
	 *	truncate with warning if longer than LAB_LEN chars.
	 *
	 *	function returns: 0 if no symbol, 1 if have symbol
	 */

	/* skip blanks, tabs.  If nothing left, return 0 */
	SKIP_WHITE( line_ptr );
	if( *line_ptr == '\0' ) return(0);

	/* copy sumbol to variable 'symbol' */
	for( sym_ptr = symbol, i = 0 ;
			!isspace(*line_ptr) && *line_ptr != '\0' && i< LAB_LEN;
			i++, line_ptr++, sym_ptr++ ) {
		*sym_ptr = *line_ptr;
	}
	*sym_ptr = '\0';

	/* if symbol too long: truncate, issue warning & skip excess */
	if( !isspace(*line_ptr) && *line_ptr != '\0' ) {
		printf("symbol too long, truncated to: %s\n", symbol );
		while( !isspace(*line_ptr) && *line_ptr != '\0' ) *line_ptr++;
		sleep(2);
	}
	return(1);
}

desc_err(str)
char *str;
{
	/* inconsistency in global description file - fatal error */

	fprintf(stderr,"*** error: %s ***\n", str );
	fprintf(stderr,"*** input: %s ***\n", line );
	endit( 1 );
}
