/*
 * Copyright (1987) Jeff Elman.  University of California, San Diego
 * This software may be redistributed without charge; this notice
 * should be preserved.
 */

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <sys/types.h>
#include "defs.h"
#include "shell.h"
#ifndef ims
#include <setjmp.h>
#endif

/*
 * run_cmd.c
 *
 * perform interactive commands
 *
 */

#define	ARG_NONE	0
#define	ARG_STRING	1
#define	ARG_VEC		2

#ifdef notdef
extern	int doalias();
extern	int dounalias();
extern	int dounset();
#endif

extern	int do_cycle();
extern	int do_fileroot();
extern	int do_reset();
extern	int do_set();
extern	int do_test();
extern	int do_help();
extern	int do_quit();
extern	int do_saveweights();
extern	int do_loadweights();

#ifdef X
extern	int box_cmd();
extern	int plot2_cmd();
extern	int plot3_cmd();
#endif

struct cmd cmds[] = {
#ifdef notdef
	"alias", doalias, ARG_VEC,  
#endif
	"cycle", do_cycle, ARG_VEC, 
	"fileroot", do_fileroot, ARG_VEC,
	"loadweights", do_loadweights, ARG_VEC,
#ifdef X
	"plot2", plot2_cmd, ARG_VEC,
	"plot3", plot3_cmd, ARG_VEC,
	"plota", box_cmd, ARG_VEC,
#endif
	"quit", do_quit, ARG_NONE,
	"reset", do_reset, ARG_NONE,
	"set", do_set, ARG_VEC,  
	"saveweights", do_saveweights, ARG_NONE,
	"test", do_test, ARG_VEC,
#ifdef notdef
	"unalias", dounalias, ARG_VEC,  
	"unset", dounset, ARG_VEC,  
#endif
	"help", do_help, ARG_NONE,
	"?", do_help, ARG_NONE,
	0, 0, 0,
};

run_cmd()
{
	extern	char *main_select();
	extern	int val;
	extern	long run;
	char	*makestring();
	struct	cmd *cp;
	char	line[128];
	char	*args[20];

#ifndef ims
	extern	jmp_buf env;

	val = setjmp(env);
	if (val != 0)
		fprintf(stdout, "caught signal on cycle %ld\n", run);
#endif
	while (1) {
		fprintf(stdout, "<%ld>: ", run);
		fflush(stdout);
		if (main_select(line) == 0)
			do_quit();
		if (parse(line, args) == -1) {
			freeargv(args);
			continue;
		}
		if (args[0] == 0)
			continue;
		for (cp = cmds; cp->name != 0; cp++) {
			if (startsame(args[0], cp->name)) {
				call(cp, args);
				break;
			}
		}
		if (cp->name == 0) {
#ifdef notdef
			parseprint(makestring(args));
			fprintf(stdout, "\n");
#else
			fprintf(stdout, "bad command %s\n", args[0]);
#endif
		}
		freeargv(args);
	}
}

freeargv(argv)
	char	**argv;
{
	while (*argv != 0) {
		free(*argv);
		*argv = 0;
		argv++;
	}
}
call(cp, argv)
	struct	cmd *cp;
	char	**argv;
{
	switch (cp->how) {
	case ARG_STRING:
		cp->cmd(makestring(argv));
		break;
	case ARG_NONE:
		cp->cmd();
		break;
	case ARG_VEC:
		cp->cmd(argv);
		break;
	}
}

char *
makestring(args)
	char	**args;
{
	static	char line[250];
	int	i;

	*line = 0;
	for (i=0; args[i] != 0; i++) {
		strcat(line, args[i]);
		strcat(line, " ");
	}
	return line;
}
/*
vers() {
	extern	char version[];

	fprintf(stdout, "\nVersion is %s\n", version);
}
*/


ALIAS	*aliases;

/*
 * Parse the command line into an argv format. 
 */
int
parse(cmd, args)
	char   *cmd,
	       *args[];
{
	extern	char *get_var();
	extern	char *malloc();
	char	token[50];
	char	word[50];
	char	str[50];
	int	i;
	int	r;
	char	*t;
	char	*w;
	char	*s;
	char	*c;

	for (i = 0; (r = next_token(cmd, token)) > 0; i++) {
		t = token;
		w = word;
		while (*t) {
			switch (*t) {
			case '$':	    /* variable expansion */
				t++;
				s = str;
				while (isalpha(*t))
					*s++ = *t++;
				*s = '\0';
				c = get_var(str);
				if (c == NULL) {
					(void) putline(
					     "I don't know that variable");
					return (-1);
				}
				while (*c)
					*w++ = *c++;
				break;
			default:	    /* normal character */
				*w++ = *t++;
				break;
			}
		}
		/* null terminate word */
		*w = '\0';
		args[i] = malloc((u_int)strlen(word) + 1);
		strcpy(args[i], word);
	}
	/* end argument array */
	args[i] = NULL;
	/* make sure last token did not contain error */
	if (r)
		return (-1);
	else
		return (0);
}


/*
 * Return the next token from the line. 
 */
next_token(line, token)
	char   *line,
	       *token;
{
	ALIAS  *tmp;
	static	char *p = NULL;
	char   *t;

	if (p == NULL) {		    /* initially for each line */
		p = line;
		while (*p == ' ' || *p == '\t')
			p++;

		t = token;
		while (*p && *p != ' ' && *p != '\t')
			*t++ = *p++;
		*t = '\0';

		/* do alias expansion on first word */
		tmp = aliases;
		while (tmp) {		    /* look through all aliases */
			if (!strcmp(tmp->al_name, token)) {
				strcpy(token, tmp->al_str);
				break;
			}
			tmp = tmp->al_next;
		}
		if (*p)
			strcat(token, p);
		strcpy(line, token);
		p = line;
	} else if (*p == '\0') {	    /* done a line */
		p = NULL;
		return (0);
	}
	t = token;
	while (*p) {
		switch (*p) {
		case '\\':		    /* literal next */
			*t++ = *++p;
			p++;
			break;
		case '"':		    /* quotes */
			p++;		    /* get past initial " */
			while (*p && *p != '"') {
				if (*p == '\\')
					p++;
				*t++ = *p++;
			}
			if (*p == '\0' && *(p - 1) != '"') {
				(void) putline("Unmatched \".");
				return (-1);
			}
			break;
		case ' ':
		case '\t':		    /* white space */
		case '\n':
			*t = '\0';
			while (*p && (*p == ' ' || *p == '\t'))
				p++;
			return (t - token);
		default:		    /* normal character */
			*t++ = *p++;
			break;
		}
	}
	*t = '\0';
	return (t - token);
}

/* 
 * does s1 start the same as s2? s2 is the full version, 
 * s1 its possible beginning 
 */
startsame(s1,s2) 
	char	*s1, *s2; 
	{
	while (*s1) {
		if (*s1++ != *s2++)
			return(0);
	}
	return(1);
}

