#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <math.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "symbol.h"
#include "code.h"
#include "macro.h"
#ifdef VMS
#include "math_tab.h"
#else
#include "math.tab.h"
#endif
#include <readline/history.h>
#include "fudgit.h"
#include "setshow.h"
#include "help.h"
#include "command.h"
#include "head.h"

#ifndef INT_MAX
#define INT_MAX 2147483647
#endif

extern FILE *popen(const char *, const char *);
extern int errno;
extern int Ft_Interact;
extern char *strstr(const char *, const char *);
extern void exit(int);
extern int Ft_printversion(void);
extern Ft_mathyyparse(void);

extern int write_history(char *);
extern int append_history(int, char *);
extern HIST_ENTRY **history_list(void);

typedef union {
	double db;
	char* str;
	} Vardesc;

static int Slowterm = 0;
static int balmost(register char *str1, register char *str2);
static int subcommand(int lvl, int argc, char **argv, char *l, Command *cmp);
static int dataread(int argc, char **argv, int exec, Command *cmp);
static int getrange(char *arg, int i, double range[][MAXVAR], int *lines,
int irange[][MAXVAR], int *loctable,
Symbol **table, int alloc_if_not, Command *cmp);
static int let(int argc, char **argv, char *line, Command *cmp);
static int usage(Command *cmd);
static int splitvar(int ifrom, int xto, char **argv, Vardesc *dbvec,
	int *astringvec, Command *cmp);
static int macrun(Macro *mac, int level);
static void signal_off(void), signal_on(void);

/***********
typedef int Do ();
typedef struct {
	char	 *name;
	Do	   *func;
	char	 *fname;
	char	 *usage;
	char	 *help;
} Command;
***********/

/* LEVEL 0 COMMANDS */
int Ft_pmode(int c, char **v, char *l, Command *com);
int Ft_help(int c, char **v, char *l, Command *com);

static int do_killplot(int c, char **v, char *l, Command *com);
static int do_list(int c, char **v, char *l, Command *com);
static int do_system(int argc, char **argv, char *line, Command *cmp);
static int do_adjust(int argc, char **argv, char *l, Command *cmp);
static int do_alias(int argc, char **argv, char *line, Command *cmp);
static int go_append(int argc, char **argv, char *l, Command *cmp);
static int do_cd(int argc, char **argv, char *l, Command *cmp);
static int do_cmode(int argc, char **argv, char *l, Command *cmp);
static int do_dumplot(int argc, char **argv, char *l, Command *cmp);
static int do_echo(int argc, char **argv, char *line, Command *cmp);
static int do_end(int c, char **v, char *l, Command *cmp);
static int do_end(int c, char **v, char *l, Command *cmp);
static int do_exec(int c, char **v, char *l, Command *cmp);
static int do_quit(int c, char **v, char *l, Command *cmp);
static int do_fft(int argc, char **argv, char *l, Command *cmp);
static int do_fmode(int c, char **v, char *l, Command *cmp);
static int do_foreach(int argc, char **argv, char *line, Command *cmp);
static int do_free(int argc, char **argv, char *line, Command *cmp);
static int do_let(int c, char **v, char *l, Command *cmp);
static int do_lock(int argc, char **argv, char *l, Command *cmp);
static int do_ls(int argc, char **argv, char *line, Command *cmp);
static int do_pause(int argc, char **argv, char *line, Command *cmp);
static int do_pwd(int argc, char **argv, char *l, Command *cmp);
static int do_read(int c, char **v, char *l, Command *cmp);
static int go_save(int argc, char **argv, char *l, Command *cmp);
static int go_set(int argc, char **argv, char *l, Command *cmp);
static int go_show(int argc, char **argv, char *l, Command *cmp);
static int do_stop(int c, char **v, char *l, Command *cmp);
static int do_unalias(int argc, char **argv, char *l, Command *cmp);
static int do_unlock(int argc, char **argv, char *l, Command *cmp);
static int do_vi(int c, char **v, char *line, Command *cmp);
static int do_load(int argc, char **argv, char *l, Command *cmp);
static int do_fit(int argc, char **argv, char *l, Command *cmp);
static int do_hist(int argc, char **argv, char *mode, Command *cmp);
static int do_invfft(int argc, char **argv, char *l, Command *cmp);
static int do_parse(int argc, char **argv, char *line, Command *cmp);
static int do_if(int argc, char **argv, char *line, Command *cmp);
static int do_endif(int argc, char **argv, char *line, Command *cmp);
static int do_else(int argc, char **argv, char *line, Command *cmp);
static int do_while(int argc, char **argv, char *line, Command *cmp);
static int do_udefmac(int argc, char **argv, char *l, Command *cmp);
static int do_defmac(int argc, char **argv, char *l, Command *cmp);
static int do_version(int argc, char **argv, char *l, Command *cmp);
static int do_spline(int argc, char **argv, char *line, Command *cmp);
static int do_smooth(int argc, char **argv, char *l, Command *cmp);
static int do_install(int argc, char **argv, char *l, Command *cmp);

Command Ft_Cmds[] = {
	{"?", do_list, "?", "",
		"display this summary"},
	{"ad!just", do_adjust, "adjust", "value_list",
		"select parameter[s] to adjust in nonlinear fits"},
	{"al!ias", do_alias, "alias", "command command_list",
		"give another name to a command or a list of commands"},
	{"ap!pend", go_append, "append", "object_type [object_list] filename",
		"append different things to a given file"},
	{"cd", do_cd, "cd", "directory",
		"change current working directory"},
	{"cm!ode", do_cmode, "cmode", "[cmode_commands]",
		"switch to C mathematical mode"},
	{"_d!umplot", do_dumplot, "_dumplot", "vector_list",
		"dump given vector[s] to plotting program stdin"},
	{"ec!ho", do_echo, "echo" ,"string",
		"print a string to stdout"},
	{"el!se", do_else, "else", "",
		"fmode style else conditionnal statement"},
	{"end", do_end, "end", "",
		"terminate a do or foreach loop"},
	{"en!dif", do_endif, "endif", "",
		"terminate if conditionnal statement"},
	{"exe!c", do_exec, "exec", "program vector_assignments",
		"assign vector[s] to the output of a program"},
	{"exi!t", do_quit, "exit", "",
		"exit the program"},
	{"fi!t", do_fit, "fit", "dep-VEC indep-VEC [sig-VEC]",
		"fit given vector[s] using pre-selected method and function"},
	{"ff!t", do_fft, "fft", "real-VEC ima-VEC tr-real-VEC tr-ima-VEC",
		"Fourier transform the given vectors"},
	{"fm!ode", do_fmode, "fmode", "",
		"switch to fitting mode from either plotting or C mode"},
	{"fore!ach", do_foreach, "foreach", "Var_Name `in' shell_command\n...\nend",
		"make a macro loop over a series of values"},
	{"fr!ee", do_free, "free", "varname|procname|funcname|\"@all\"...",
		"remove the given object[s] from memory"},
	{"he!lp", Ft_help, "help", "[command]",
		"interactive help"},
	{"hi!story", do_hist, "history", "",
		"display complete history"},
	{"if", do_if, "if", "(condition) `then'",
		"fmode if conditionnal statement"},
	{"ins!tall", do_install, "install", "objfile objname[:|=]name(arg_list)...",
		"link procedures(:) or functions(=) as name()"},
	{"inv!fft", do_invfft, "invfft", "real-VEC ima-VEC tr-real-VEC tr-ima-VEC",
		"Inverse Fourier transform the given vectors"},
	{"_k!illplot", do_killplot, "_killplot", "",
		"kill current plotting program"},
	{"le!t", do_let, "let", "cmode_commands",
		"give a command in C mode from the fitting mode"},
	{"lo!ad", do_load, "load", "filename",
		"read and interpret from command script file"},
	{"loc!k", do_lock, "lock", "variable_list",
		"turn variable[s] into constant[s]"},
	{"ls", do_ls, "ls", "[files]",
		"list files and directories"},
	{"ma!cro", do_defmac, "macro", "name argno\n...\nstop",
		"define a macro"},
	{"parse", do_parse, "parse", "commands",
		"test parsing"},
	{"pa!use", do_pause, "pause", "delay [string]",
		"suspend for the given delay and print string to stderr"},
	{"pm!ode", Ft_pmode, "pmode", "[plotting_commands]",
		"switch to plotting mode"},
	{"pw!d", do_pwd, "pwd", "",
		"print current working directory"},
	{"q!uit", do_quit, "quit", "",
		"same as exit"},
	{"rea!d", do_read, "read", "file vector_assignments",
		"assign vector[s] to column[s] of a file"},
	{"rei!nstall", do_install, "reinstall",
		"objfile objname[:|=]name(arg_list)...",
		"relink procedures(:) or functions(=) as name()"},
	{"sa!ve", go_save, "save", "objet_type [object_list] filename",
		"save specified object[s] to a file"},
	{"se!t", go_set, "set", "object value",
		"set a lot of things"},
	{"she!ll", do_system, "shell", "unix_commands",
		"shell escape bang operator"},
	{"sho!w", go_show, "show", "object_type [object_list]",
		"show a lot of things"},
	{"sm!ooth", do_smooth, "smooth", "sm-factor in-VEC out-VEC",
		"smooth a vector by a given factor"},
	{"sp!line", do_spline, "spline", "XVEC YVEC [dy1] [dyn]",
		"initialize cubic spline interpolation"},
	{"stop", do_stop, "stop", "",
		"indicate end of macro"},
	{"sy!stem", do_system, "system", "unix_commands",
		"shell escape bang operator"},
	{"una!lias", do_unalias, "unalias", "alias_list",
		"undefine an alias"},
	{"unm!acro", do_udefmac, "unmacro", "macro_list",
		"undefine macro"},
	{"unl!ock", do_unlock, "unlock", "constant_list",
		"turn constant[s] into variable[s]"},
	{"ve!rsion", do_version, "version", "",
		"display version number"},
	{"vi", do_vi, "vi", "file_list",
		"call vi editor"},
	{"wh!ile", do_while, "while", "(condition)\n...\nend",
		"while conditionnal loop"},
	{0,	  0,		0,		 0,	   0}
	};

/* FUNCTIONS */
static int do_stfunc(int argc, char **argv, char *l, Command *cmp);

static Command Funcs[] = {
	{"?", do_list, "set function ?", "",
		"display this summary"},
	{"c!osine", do_stfunc, "set function cosine", "",
		"cosine series: n = 1,...N { A[n]*cos(n*X) }"},
	{"e!xponential", do_stfunc, "set function exponential", "",
		"exponential series: n = 2, 4...N { A[n-1]*exp(A[n]*X) }"},
	{"g!aussian", do_stfunc, "set function gaussian", "",
	"Gaussian series: n = 3, 6...N { A[n-2]*exp(A[n-1]*(X-A[n])^2) }"},
	{"le!gendre", do_stfunc, "set function legendre", "",
		"legendre series: n = 1,...N { Pn(X) }"},
	{"lo!rentzian", do_stfunc, "set function lorentzian", "",
	    "Lorentzian series: n = 3, 6...N { A[n-1]*((X*A[n])^2/((X^2-A[n-2]^2)^2+(X*A[n])^2) }"},
	{"p!olynomial", do_stfunc, "set function polynomial", "",
		"power series: n = 1,...N { A[n]*X^(n-1) }"},
	{"u!ser", do_stfunc, "set function user", "definition",
		"user defined function"},
	{"si!ne", do_stfunc, "set function sine", "",
		"sine series: n = 1,...N { A[n]*sin(n*X) }"},
	{"st!raight", do_stfunc, "set function straight_line", "",
		"straight line: { A[1]+A[2]*X }"},
	{ 0,	 0,		0,		0,		0 }
	};

static int do_stmeth(int argc, char **argv, char *l, Command *cmp);

static Command Meths[] = {
	{"?", do_list, "set method ?", "",
		"display this summary"},
	{"la!_reg", do_stmeth, "set method la_reg", "",
		"least absolute deviation linear regression"},
	{"ls_f!it", do_stmeth, "set method ls_fit", "",
		"least square linear fit"},
	{"ls_r!eg", do_stmeth, "set method ls_reg", "",
		"least square linear regression"},
	{"m!l_fit", do_stmeth, "set method ml_fit", "",
		"Marquardt-Levenberg iterative nonlinear fit"},
	{"s!vd_fit", do_stmeth, "set method svd_fit", "",
		"singular value decomposition linear fit"},
	{ 0,	 0,		0,		0,		0 }
	};

static int do_stcomm(int argc, char **argv, char *l, Command *cmp);
static int do_stdata(int argc, char **argv, char *l, Command *cmp);
static int do_stdebug(int argc, char **argv, char *l, Command *cmp);
static int do_stslow(int argc, char **argv, char *l, Command *cmp);
static int do_stsamp(int argc, char **argv, char *l, Command *cmp);
static int do_stplotting(int argc, char **argv, char *l, Command *cmp);
static int do_stparam(int argc, char **argv, char *l, Command *cmp);
static int go_stfunc(int argc, char **argv, char *l, Command *cmp);
static int go_stmeth(int argc, char **argv, char *l, Command *cmp);
static int do_stform(int argc, char **argv, char *l, Command *cmp);
static int do_stiter(int argc, char **argv, char *l, Command *cmp);
static int do_stpager(int argc, char **argv, char *l, Command *cmp);
static int do_stexp(int argc, char **argv, char *l, Command *cmp);
static int do_stnexp(int argc, char **argv, char *l, Command *cmp);
static int do_stpromptcm(int argc, char **argv, char *l, Command *cmp);
static int do_stpromptfm(int argc, char **argv, char *l, Command *cmp);
static int do_stpromptpm(int argc, char **argv, char *l, Command *cmp);
static int do_stvform(int argc, char **argv, char *l, Command *cmp);
static int do_stoutput(int argc, char **argv, char *l, Command *cmp);
static int do_stinput(int argc, char **argv, char *l, Command *cmp);
static int do_sterr(int argc, char **argv, char *l, Command *cmp);

static Command Sets[] = {
	{"?", do_list, "set ?", "",
		"display this summary"},
	{"c!omment", do_stcomm, "set comment", "character",
		"change comment escape character (default: '#')"},
	{"da!ta", do_stdata, "set data", "integer",
		"set current vector size"},
	{"de!bug", do_stdebug, "set debug", "integer_list",
		"select and toggle debugging levels"},
	{"er!ror", do_sterr, "set error", "value",
		"define type of math error check"},
	{"ex!pand", do_stexp, "set expand", "",
		"allow history expansion"},
	{"fo!rmat", do_stform, "set format", "string",
		"change number display format (default: \"% 10.8e\")"},
	{"fu!nction", go_stfunc, "set function", "string [userdef]",
		"set function to fit"},
	{"in!put", do_stinput, "set input", "filename",
		"select cmode 'read' command input file"},
	{"it!eration", do_stiter, "set iteration", "integer",
		"set iteration number for nonlinear fits (default: 10)"},
	{"m!ethod", go_stmeth, "set method", "string",
		"select fitting method"},
	{"noex!pand", do_stnexp, "set noexpand", "",
		"disable history expansion"},
	{"ou!tput", do_stoutput, "set output", "filename",
		"select cmode 'print' command output file"},
	{"pag!er", do_stpager, "set pager", "pager_name",
		"select pager (default: PAGER environement)"},
	{"par!ameters", do_stparam, "set parameters", "NAME size",
		"define parameter list to be NAME[1] to NAME[size]"},
	{"pl!otting", do_stplotting, "set plotting", "string",
		"select plotting program (default: /usr/local/bin/gnuplot)"},
	{"prompt-cm", do_stpromptcm, "set prompt-cm", "string",
		"select C-calculator mode prompt (default: \"cmode> \")"},
	{"prompt-fm", do_stpromptfm, "set prompt-fm", "string",
		"select fitting mode prompt (default: \"fudgit> \")"},
	{"prompt-pm", do_stpromptpm, "set prompt-pm", "string",
		"select plotting mode prompt (default: \"pmode> \")"},
	{"sa!mples", do_stsamp, "set samples", "integer",
		"change vector maximum capacity (default: 4000)"},
	{"sl!owterm", do_stslow, "set slowterm", "",
		"toggle prompt after system command"},
	{"vf!ormat", do_stvform, "set vformat", "string",
		"change format for number expansion (default: \"%.3g\")"},
	{ 0,	 0,		0,		0,		0 }
	};

static int do_shcomm(int argc, char **argv, char *l, Command *cmp);
static int do_shdata(int argc, char **argv, char *l, Command *cmp);
static int do_shdebug(int argc, char **argv, char *l, Command *cmp);
static int do_shslow(int argc, char **argv, char *l, Command *cmp);
static int do_shsamp(int argc, char **argv, char *l, Command *cmp);
static int do_shplotting(int argc, char **argv, char *l, Command *cmp);
static int do_shfunc(int argc, char **argv, char *l, Command *cmp);
static int do_shmeth(int argc, char **argv, char *l, Command *cmp);
static int do_shform(int argc, char **argv, char *l, Command *cmp);
static int do_shiter(int argc, char **argv, char *l, Command *cmp);
static int do_shpager(int argc, char **argv, char *l, Command *cmp);
static int do_shfit(int argc, char **argv, char *l, Command *cmp);
static int do_shtab(int argc, char **argv, char *l, Command *cmp);
static int do_shmem(int argc, char **argv, char *l, Command *cmp);
static int do_shvform(int argc, char **argv, char *l, Command *cmp);
static int do_svvec(int argc, char **argv, char *mode, Command *cmp);
static int do_shmac(int argc, char **argv, char *l, Command *cmp);
static int do_svpar(int argc, char **argv, char *mode, Command *cmp);
static int do_shsetup(int argc, char **argv, char *l, Command *cmp);
static int do_svvar(int argc, char **argv, char *mode, Command *cmp);
static int do_shexp(int argc, char **argv, char *l, Command *cmp);
static int do_shpromptcm(int argc, char **argv, char *l, Command *cmp);
static int do_shpromptfm(int argc, char **argv, char *l, Command *cmp);
static int do_shpromptpm(int argc, char **argv, char *l, Command *cmp);
static int do_shoutput(int argc, char **argv, char *l, Command *cmp);
static int do_shinput(int argc, char **argv, char *l, Command *cmp);
static int do_sherr(int argc, char **argv, char *l, Command *cmp);

static Command Shows[] = {
	{"?", do_list, "show ?", "",
		"display this summary"},
	{"c!omment", do_shcomm, "show comment", "",
		"display current comment escape character"},
	{"da!ta", do_shdata, "show data", "",
		"show current vector size"},
	{"de!bug", do_shdebug, "show debug", "",
		"display current debugging levels"},
	{"er!ror", do_sherr, "show error", "",
		"display type of math error check"},
	{"ex!pansion", do_shexp, "show expansion", "",
		"display current expansion value"},
	{"fi!t", do_shfit, "show fit", "",
		"complete display of last fit results"},
	{"fo!rmat", do_shform, "show format", "",
		"show current number display format"},
	{"fu!nction", do_shfunc, "show function", "",
		"show current function to fit"},
	{"in!put", do_shinput, "show input", "",
		"display cmode 'read' active input file"},
	{"it!eration", do_shiter, "show iteration", "",
		"show active iteration number for nonlinear fits"},
	{"ma!cros", do_shmac, "show macros", "[macro_name]",
		"display definitions of one or all active macros"},
	{"mem!ory", do_shmem, "show memory", "",
		"display complete state of allocated memory"},
	{"met!hod", do_shmeth, "show method", "",
		"display selected fitting method"},
	{"o!utput", do_shoutput, "show output", "",
		"display cmode 'print' active output file"},
	{"pag!er", do_shpager, "show pager", "",
		"display active pager"},
	{"par!ameters", do_svpar, "show parameters", "[variable_list]",
		"show selected parameter list"},
	{"pl!otting", do_shplotting, "show plotting", "",
		"show selected plotting program"},
	{"prompt-cm", do_shpromptcm, "show prompt-cm", "",
		"select C-calculator mode prompt"},
	{"prompt-fm", do_shpromptfm, "show prompt-fm", "",
		"select fitting mode prompt"},
	{"prompt-pm", do_shpromptpm, "show prompt-pm", "",
		"select plotting mode prompt"},
	{"sa!mples", do_shsamp, "show samples", "",
		"show current vector maximum capacity"},
	{"sl!owterminal", do_shslow, "show slowterminal", "",
		"show current state of slow terminal switch"},
	{"se!tup", do_shsetup, "show setup", "",
		"display current setup"},
	{"va!riables", do_svvar, "show variables", "variable_list",
		"display contents of selected variables"},
	{"ve!ctors", do_svvec, "show vector", "vector_list",
		"display contents of selected vectors"},
	{"vf!ormat", do_shvform, "show vformat", "",
		"show current string expansion format of numbers"},
	{"t!able", do_shtab, "show table", "",
		"display state of internal symbol lookup table"},
	{ 0,	0,		0,		0,		0}
	};

static int do_svhist(int argc, char **argv, char *mode, Command *cmp);
static int do_svvec(int argc, char **argv, char *mode, Command *cmp);
static int do_svvar(int argc, char **argv, char *mode, Command *cmp);
static int do_svmac(int argc, char **argv, char *mode, Command *cmp);
static int do_svpar(int argc, char **argv, char *mode, Command *cmp);

static Command Saves[] = {
	{"?", do_list, "save ?", "",
		"display this summary"},
	{"h!istory", do_svhist, "save history", "filename",
		"save all of history to a file"},
	{"m!acros", do_svmac, "save macros", "filename",
		"save all active macro definitions to a file"},
	{"p!arameters", do_svpar, "save parameters", "[variable_list] filename",
		"save all parameters and errors to a file"},
	{"va!riables", do_svvar, "save variables", "variable_list filename",
		"save specified variables to a file"},
	{"ve!ctors", do_svvec, "save vectors", "vector_list filename",
		"save specified vectors to a file"},
	{ 0,	0,		0,			0,		0}
	};

static Command Appends[] = {
	{"?", do_list, "append ?", "",
		"display this summary"},
	{"h!istory", do_svhist, "append history", "filename",
		"append all of history to a file"},
	{"m!acros", do_svmac, "append macros", "filename",
		"append all active macro definitions to a file"},
	{"p!arameters", do_svpar, "append parameters", "[variable_list] filename",
		"append all parameters and errors to a file"},
	{"va!riables", do_svvar, "append variables", "variable_list filename",
		"append specified variables to a file"},
	{"ve!ctors", do_svvec, "append vectors", "vector_list filename",
		"append specified vectors to a file"},
	{ 0,	0,		0,		0,		0}
	};

/* HERE WE START */

int Ft_exit (int val);
int Ft_almost (register char *str1, register char *str2);

extern int Ft_iolevel (void);
extern int Ft_popio (void);
extern int Ft_killplot (void);
extern int Ft_fits (int argc, char **argv, int ndata);
extern int Ft_pushio (char *string, int type, char *name);
extern int Ft_varcpy (char *, char *);
extern int Ft_readvar (char **argp, Symbol **sym, int *loc, int (*irange)[32], double (*range)[32], int *lines, int num, int exec, char *comname);
extern int Ft_dumplot (double **dblv, int ndata);
extern int Ft_processline (char *lp);
extern int Ft_run_smooth (int argc, char **argv, int ndata);
extern int Ft_run_fft (int argc, char **argv, int dir, int ndata);
extern int Ft_setparam (char *name, int n);
extern int Ft_symremove (char *name, int verb);
extern int Ft_clearpush_cwd (void);
extern void Ft_initmathyylex (char *str);
extern int Ft_save_macros (int type, char *name, char *mode);
extern int Ft_showmac (int argc, char **argv, int type);
extern int Ft_showsetup (void);
extern int Ft_showfit (void);
extern int Ft_showmem (void);
extern int Ft_showtable (void);
extern int Ft_more_input (int level, char *iprompt);
extern int Ft_macremove (char *name, int type);
extern int Ft_lock (int i, char *name, char *fname);
extern int Ft_switchif (int val);
extern int Ft_pushif (int val);
extern int Ft_popif (void);
extern int Ft_spline (double *x, double *y, double yp1, double ypn, int n);

int Ft_command(int argc, char **argv, char *line)
{
	int i;
	Command *cmp = Ft_Cmds;

	if (argv[0][0] == '!') {
		line[0] = ' ';  /* erase the bang */
		return(do_system(0, argv, line, 0));
	}
	for (i=0; Ft_Cmds[i].name; i++, cmp++)
		if (balmost(argv[0], Ft_Cmds[i].name))
			return(Ft_Cmds[i].func(argc, argv, line, cmp));

	fprintf(stderr, "%s: Command not found.\n", argv[0]);
	return(ERRR);
}

static int do_list(int c, char **v, char *l, Command *com)
{
	int i;
	FILE *fp = stdout;
	char *cp;

	 if (c == 1 && Ft_Interact && *Ft_Pager) {
		if ((fp = popen(Ft_Pager, "w")) == (FILE *)NULL)  {
			fprintf(stderr, "Warning: Could not open pager %s.\n", Ft_Pager);
			fp = stdout;
		}
	}
	for (i=0; com[i].name; i++) {
		if ((cp = strrchr(com[i].fname, ' ')) == NULL)
			cp = com[i].fname;
		fprintf(fp, "%14s: %s;\n", cp, com[i].help);
	}
	if (fp != stdout) {
		fflush(fp);
		pclose(fp);
	}

	return(0);
}

static int do_end(int c, char **v, char *l, Command *cmp)
{
	fprintf(stderr, "%s: Not in `foreach' or `while' loop.\n", cmp->fname);
	return(ERRR);
}

static int do_fmode(int c, char **v, char *l, Command *cmp)
{
	fprintf(stderr,
	"Warning: %s: Program already in fitting mode: Line ignored.\n",
	cmp->fname);
	return(0);
}

static int do_killplot(int c, char **v, char *l, Command *cmp)
{
	extern int Ft_killplot(void);

	if (c != 1)
		return(usage(cmp));

	return(Ft_killplot());
}

static int do_stop(int c, char **v, char *l, Command *cmp)
{
	if (Ft_iolevel()) {
		Ft_popio();
	}
	fprintf(stderr, "Warning: %s: Not in macro.\n", cmp->fname);
	return(0);
}

static int do_let(int c, char **v, char *l, Command *cmp)
{
	return(let(c, v, l, cmp));
}

static int do_read(int c, char **v, char *l, Command *cmp)
{
	return(dataread(c, v, 0, cmp));
}

static int do_exec(int c, char **v, char *l, Command *cmp)
{
	return(dataread(c, v, 1, cmp));
}

static int do_quit(int c, char **v, char *l, Command *cmp)
{
	if (c != 1)
		return(usage(cmp));

	return(Ft_exit(0));
}

int Ft_exit(int val)
{
	char buffer[512];

	signal_off();
	signal(SIGQUIT, SIG_IGN);
	Ft_killplot();
	fclose(Ft_Outprint);
#ifndef VMS
	signal(SIGCHLD, SIG_IGN);
#endif
#ifdef VMS
	sprintf(buffer,
	"if f$search(\"sys$scratch:fudgit%d*.*;*\") .nes. \"\" then delete sys$scratch:fudgit%d*.*;*",
	getpid(),getpid());
#else
	sprintf(buffer, "exec /bin/rm -f /tmp/fudgit%d*", getpid());
#endif
	system(buffer);
	sprintf(buffer, "%s/%s", Ft_Home, HISTORY);
	if (Ft_Interact)
		write_history(buffer);
	if (val == 2) {
		fputs("Do you know why I received that signal?\nIf not report that bug!\n\n", stderr);
	}
	if (val > 1) {
		signal(SIGTERM, SIG_IGN);
#ifndef VMS
#ifdef NOKILLPG
		kill( -getpid(), SIGTERM);
#else
		killpg(getpid(), SIGTERM);
#endif
#endif /*VMS*/
	}
	exit(val);
}

/* BALMOST UTILITY */
static int balmost(register char *str1, register char *str2)  /* account for built-in functions */

{
	if (*str1 == '&')
		str1++;
	return(Ft_almost(str1, str2));
}

/* ALMOST UTILITY  */
int Ft_almost(register char *str1, register char *str2)
{
	int ok = 0;
	register int i = 0;

	while (*str1 != ' ' && *str1 != '\t' && *str1 != '\n' &&
	*str1 != '\0' && i++ < TOKENSIZE) { /* avoid runaway  */
		if (*str1 != *str2) {
			if (*str2 != '!') {
				return(0);
			}
			else {
				ok = 1;
				str2++;;
				continue;
			}
		}
		str1++;
		str2++;
	}
	return(ok || *str2 == '!' || *str2 == '\0');
}

/*  DO_SET FUNCTION  */
static int go_set(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 && argv[1][0] == '?')
		return(do_list(argc, argv, l, Sets));
	return(subcommand(1, argc, argv, l, Sets));
}

/*  DO_SHOW FUNCTION  */
static int go_show(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 && *argv[1] == '?')
		return(do_list(argc, argv, l, Shows));
	return(subcommand(1, argc, argv, "s", Shows));
}

/*  DO_APPEND FUNCTION  */
static int go_append(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 && *argv[1] == '?')
		return(do_list(argc, argv, l, Appends));
	return(subcommand(1, argc, argv, "a", Appends));
}

/*  DO_SAVE FUNCTION  */
static int go_save(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 && *argv[1] == '?')
		return(do_list(argc, argv, l, Saves));
	return(subcommand(1, argc, argv, "w", Saves));
}

/*  DO_SET_FUNCTION FUNCTION  */
static int go_stfunc(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 3 && *argv[2] == '?')
		return(do_list(argc, argv, l, Funcs));
	return(subcommand(2, argc, argv, l, Funcs));
}

/*  DO_SET_METHOD FUNCTION  */
static int go_stmeth(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 3 && *argv[2] == '?')
		return(do_list(argc, argv, l, Meths));
	return(subcommand(2, argc, argv, l, Meths));
}

static int subcommand(int lvl, int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc <= lvl) {
		fputs("Command incomplete.\n", stderr);
		return(ERRR);
	}
	for (i=0; cmp->name; i++, cmp++)
		if (Ft_almost(argv[lvl], cmp->name))
			return(cmp->func(argc, argv, l, cmp));

	fprintf(stderr, "%s: Name not found.\n", argv[lvl]);
	return(ERRR);
}

/* VERSION */
static int do_version(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 1)
		return(usage(cmp));
	return(Ft_printversion());
}

/* COMMENT */
static int do_stcomm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	if (argv[2][1] != '\0') {
		fprintf(stderr, "%s: Not a character.\n", argv[2]);
		return(ERRR);
	}
	Ft_Comchar = argv[2][0];
	return(0);
}

static int do_shcomm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%c\n", Ft_Comchar);
	return(0);
}

/* DEBUG */
static int do_stdebug(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 || argv[2][0] == '?') {
		fputs("Debugging levels:\n", stderr);
		fputs("\t 0: Clear debugging bits.\n", stderr);
		fputs("\t 1: Echo expanded input lines.\n", stderr);
		fputs("\t 2: Echo raw input lines.\n", stderr);
		fputs("\t 3: Display ignored line numbers while reading data.\n",
		stderr);
		fputs("\t 4: Echo input lines passed to math parser.\n", stderr);
		fputs("\t 5: Debug parser (if compiled with -DYYDEBUG).\n", stderr);
		fputs("\t 6: Trace `if' constructions.\n", stderr);
	}
	else {  /* must be larger than 2 */
		float fldeb;
		int deb;
		int i;
#ifdef YYDEBUG
		extern int Ft_mathyydebug;
#endif

		for (i=2;i<argc;i++) {
			if (sscanf(argv[i], "%f", &fldeb) != 1) {
				fprintf(stderr, "%s: Could not read number \"%s\".\n",
				cmp->fname, argv[i]);
				return(ERRR);
			}
			deb = (int)fldeb;
			if (deb)
				Ft_Debug |= 01<<(deb-1);
			else
				Ft_Debug = 0;
		}
#ifdef YYDEBUG
		Ft_mathyydebug = (Ft_Debug & DEBUG_PARSER);
#endif
	}
	return(0);
}

static int do_shdebug(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%o\n", Ft_Debug);
	return(0);
}

/* VFORMAT */
static int do_stvform(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	sprintf(Ft_Vformat, "%s", argv[2]);
	return(0);
}

/* FORMAT */
static int do_stform(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	sprintf(Ft_Format, "%s", argv[2]);
	sprintf(Ft_TFormat, "\t%s", argv[2]);
	return(0);
}

static int do_shvform(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "\"%s\"\n", Ft_Vformat);
	return(0);
}

static int do_shform(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "\"%s\"\n", Ft_Format);
	return(0);
}

/* FUNCTION */
static int do_stfunc(int argc, char **argv, char *l, Command *cmp)
{
	int i;
	char *cp;

	if (argc != 3)
		return(usage(cmp));
	for (i=0;i<FUNCNUM;i++) {  /* look twice I know!... */
		if (Ft_almost(argv[2], Ft_Function[i].cname)) {
			Ft_Funci = i;
			break;
		}
	}
	if (Ft_Funci != USER)
		return(0);
	/* DO USER */
	if ((cp = Ft_readmacro("user? ")) == NULL) {
		return(ERRR);
	}
	sprintf(Ft_UFunction, "%s", cp);
	return(0);
}

static int do_shfunc(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	if (Ft_Funci == USER)
		fprintf(stdout, "user:\n{\n%s}\n", Ft_UFunction);
	else
		fprintf(stderr, "%s\n", Ft_Function[Ft_Funci].name);

	return(0);
}

/* ITER */
static int do_stiter(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc != 3)
		return(usage(cmp));
	if (sscanf(argv[2], "%d", &i) != 1) {
		fprintf(stderr, "%s: Could not read value %s.\n",
		cmp->fname, argv[2]);
		return(ERRR);
	}
	Ft_Iter = i;
	return(0);
}

static int do_shiter(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%d\n", Ft_Iter);
	return(0);
}

/* OUTPUT */
static int do_stoutput(int argc, char **argv, char *l, Command *cmp)
{
	extern FILE *Ft_Outprint;
	extern char Ft_Outname[];

	if (argc != 3)
		return(usage(cmp));
	if (Ft_Outprint != stderr && Ft_Outprint != stdout) {
		fflush(Ft_Outprint);
		fclose(Ft_Outprint);
	}
	if (Ft_almost(argv[2], "stdout")) {
		sprintf(Ft_Outname, "stdout");
		Ft_Outprint = stdout;
		return(0);
	}
	if (Ft_almost(argv[2], "stderr")) {
		sprintf(Ft_Outname, "stderr");
		Ft_Outprint = stderr;
		return(0);
	}
	if ((Ft_Outprint = fopen(argv[2], "w")) == (FILE *)NULL) {
		fprintf(stderr, "%s: %s: Permission denied.\n", cmp->fname, argv[2]);
		sprintf(Ft_Outname, "stdout");
		Ft_Outprint = stdout;
		return(ERRR);
	}
	sprintf(Ft_Outname, "%s", argv[2]);
	return(0);
}

/* INPUT */
static int do_stinput(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	if (Ft_Inread != stdin) {
		fclose(Ft_Inread);
	}
	if (Ft_almost(argv[2], "stdin")) {
		sprintf(Ft_Inname, "stdin");
		Ft_Inread = stdin;
		return(0);
	}
	if ((Ft_Inread = fopen(argv[2], "r")) == (FILE *)NULL) {
		fprintf(stderr, "%s: %s: Permission denied.\n", cmp->fname, argv[2]);
		sprintf(Ft_Inname, "stdin");
		Ft_Inread = stdin;
		return(ERRR);
	}
	sprintf(Ft_Inname, "%s", argv[2]);
	return(0);
}

static int do_shoutput(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", Ft_Outname);
	return(0);
}

static int do_shinput(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", Ft_Inname);
	return(0);
}

/* PAGER */
static int do_stpager(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	sprintf(Ft_Pager, "%s", argv[2]);
	return(0);
}

static int do_shpager(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", Ft_Pager);
	return(0);
}

/* PLOTTING */
static int do_stplotting(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc < 3)
		return(usage(cmp));
	for (i=0;i<argc-2 && i < MAXPARG-1;i++) {
		sprintf(Ft_Plotting[i], "%s", argv[i+2]);
	}
	Ft_Plotting[i][0] = '\0';
	Ft_killplot();
	return(0);
}

static int do_shplotting(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc != 2)
		return(usage(cmp));
	for (i=0;Ft_Plotting[i][0] != '\0' && i < MAXPARG-1;i++) {
		fprintf(stderr, "%s ", Ft_Plotting[i]);
	}
	fputc('\n', stderr);
	return(0);
}

/* DATA */
static int do_stdata(int argc, char **argv, char *l, Command *cmp)
{
	extern double *Ft_Data;
	int i;

	if (argc != 3)
		return(usage(cmp));
	if (sscanf(argv[2], "%d", &i) != 1) {
		fprintf(stderr, "%s: Could not read value %s.\n",
		cmp->fname, argv[2]);
		return(ERRR);
	}
	if (i<1 || i > Ft_Samples) {
		fprintf(stderr, "%s: Value out of current capacity.\n",
		cmp->fname);
		fputs("Enlarge with `set samples' first.\n", stderr);
		return(ERRR);
	}
	else if (i < (int) *Ft_Data) {
		fprintf(stderr, "Warning: possible hidden data (%d -> %d).\n",
		(int) *Ft_Data, i);
	}
	*Ft_Data = (double)i;
	return(0);
}

static int do_shdata(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%d\n", (int) *Ft_Data);
	return(0);
}

/* METHOD */
static int do_stmeth(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc != 3)
		return(usage(cmp));
	for (i=0;i< METHNUM;i++) {  /* twice again...*/
		if (Ft_almost(argv[2], Ft_Method[i].cname)) {
			Ft_Methi = i;
			return(0);
		}
	}
	fprintf(stderr, "%s: Invalid option.\n.", argv[2]);
	return(ERRR);
}

static int do_shmeth(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", Ft_Method[Ft_Methi].name);
	return(0);
}

/* PARAMETERS */
static int do_stparam(int argc, char **argv, char *l, Command *cmp)
{
	float flnumber;

	if (argc != 4)
		return(usage(cmp));
	if (sscanf(argv[3], "%f", &flnumber) != 1) {
		fprintf(stderr, "%s: Could not read number \"%s\".\n",
		cmp->fname, argv[3]);
		return(ERRR);
	}
	if (Ft_setparam(argv[2], (int)flnumber) == ERRR) {
		fprintf(stderr,
		"%s: Could not set parameter \"%s\".\n", cmp->fname, argv[2]);
		return(ERRR);
	}
	return(0);
}

/* SAMPLES */
static int do_stsamp(int argc, char **argv, char *l, Command *cmp)
{
	float flvalue;
	int value;

	if (argc != 3)
		return(usage(cmp));
	if (sscanf(argv[2], "%f", &flvalue) != 1) {
		fprintf(stderr, "%s: Could not read number \"%s\".\n",
		cmp->fname, argv[2]);
		return(ERRR);
	}
	value = (int)flvalue;
	if (value < 1) {
		fprintf(stderr, "%s: %d: Illegal value.\n", cmp->fname, value);
		return(ERRR);
	}
	Ft_symremove("@allvec", 0);
	Ft_Samples = value;
	return(0);
}

static int do_shsamp(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%d\n", Ft_Samples);
	return(0);
}

/* SLOWTERM */
static int do_stslow(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	Slowterm = !Slowterm;
	return(0);
}

/* SLOWTERM */
static int do_shslow(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", Slowterm? "on": "off");
	return(0);
}

/* DO_CD FUNCTION */
static int do_cd(int argc, char **argv, char *l, Command *cmp)
{
	extern char Ft_Cwd[PATH_MAXIM];
#if !defined(USE_GETCWD)
	extern char *getwd(char *);
#endif

	switch (argc) {
		case 1:
			if (chdir(Ft_Home) == ERRR) {
				fprintf(stderr, "%s: ", Ft_Home);
				perror("");
				return(ERRR);
			}
			break;
		case 2:
			if (chdir(argv[1]) == ERRR) {
				fprintf(stderr, "chdir: %s: ", argv[1]);
				perror("");
				return(ERRR);
			}
			break;
		default:
			return(usage(cmp));
	}

#if defined(USE_GETCWD)   /* HPUX,VMS  uses getcwd()  */
	if (getcwd(Ft_Cwd, PATH_MAXIM-1) == (char *) NULL) {
		perror("getcwd");
#else
	if (getwd(Ft_Cwd) == (char *)NULL) {
		/* getwd places an error message in Cwd */
		fprintf(stderr, "%s\n", Ft_Cwd);
#endif
		return(ERRR);
	}
	else if (Ft_Interact) {
	/* NeXT sometimes echoes it */
#ifndef NEVER
		fprintf(stderr, "%s\n", Ft_Cwd);
#endif
	}
	Ft_clearpush_cwd();
	return(0);
}

/* DO_FREE FUNCTION */
static int do_free(int argc, char **argv, char *line, Command *cmp)
{
	int i;

	if (argc == 1)
		return(usage(cmp));
	for (i=1;i<argc;i++) {
		Ft_symremove(argv[i], 1);
	}
	return(0);
}

/* DO_PAUSE FUNCTION  */
static int do_pause(int argc, char **argv, char *line, Command *cmp)
{
	int value;
	float flvalue;

	if (argc < 2)
		return(usage(cmp));

	if (argc > 2) {
		char *cp;

		cp = line + strlen(argv[0]) + strlen(argv[1]) + 2;
		line[strlen(line)-1] = '\0';
		fprintf(stderr, "%s ", cp);
		fflush(stderr);
	}
	if (sscanf(argv[1], "%f", &flvalue) != 1) {
		fprintf(stderr, "%s: Could not read number \"%s\".\n",
		cmp->fname, argv[1]);
		return(ERRR);
	}
	if ((value = (int)flvalue) >= 0) {
		sleep(value);
		fputc('\n', stderr);
		fflush(stderr);
	}
	else {
		char fromline[LINESIZE];

		fgets(fromline, LINESIZE, stdin);
	}
	return(0);
}

/* DO_PWD FUNCTION  */
static int do_pwd(int argc, char **argv, char *l, Command *cmp)
{
	extern char Ft_Cwd[PATH_MAXIM];

	if (argc != 1)
		return(usage(cmp));

	fprintf(stderr, "%s\n", Ft_Cwd);
	return(0);
}

/* DO_LS FUNCTION */
static int do_ls(int argc, char **argv, char *line, Command *cmp)
{
	char fromline[LINESIZE +16];
	int  val;

	signal_off();
	if (argc == 1) {
#ifdef VMS
	val = system("dir");
#else
		val = system("exec ls -FC");
#endif
	}
	else {
		char *cp;

		cp = line + strlen(argv[0]) + 1;
#ifdef VMS
	sprintf(fromline,"dir %s", cp);
#else
		sprintf(fromline, "exec ls -FC %s", cp);
#endif
		val = system(fromline);
	}
	signal_on();
	if (Slowterm && Ft_Interact && !Ft_iolevel()) {
		fputs("\nHit return to continue", stdout);
		fgets(fromline, LINESIZE, stdin);
	}
	return(val);
}

/* LET FUNCTION */
static int let(int argc, char **argv, char *line, Command *cmp)
{
	char *argp;
	void Ft_let(char *string);

	if (argc == 1)
		return(usage(cmp));
	if (argc == 0) {
		argp = line;
	}
	else {
		argp = line + strlen(argv[0]) + 1;
	}
	Ft_let(argp);
	return(0);
}

void Ft_let(char *string)
{
	Ft_initcode();
	Ft_initmathyylex(string);
	Ft_mathyyparse();
}

/* DO_SAVE FUNCTIONS */
static int do_svhist(int argc, char **argv, char *mode, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	if (*mode == 'w')
		return(write_history(argv[2]) ? ERRR: 0);
	return(append_history(512, argv[2]) ? ERRR: 0);
}

static int do_hist(int argc, char **argv, char *mode, Command *cmp)
{
	HIST_ENTRY **h_list;
	FILE *fp = stderr;
	int i;

	if (argc > 2)
		return(usage(cmp));
	if ((h_list = history_list())) {
		if (Ft_Interact && *Ft_Pager) {
		   if ((fp = popen(Ft_Pager, "w")) == (FILE *)NULL)  {
				fprintf(stderr, "Warning: %s: Could not open pager %s.\n",
				cmp->fname, Ft_Pager);
				fp = stderr;
			}
		}
		for (i=0; h_list[i]; i++) {
			fprintf(fp, "%d: %s\n", (i + history_base), h_list[i]->line);
		}
	}
	if (fp != stderr) {
		fflush(fp);
		pclose(fp);
	}

	return(0);
}

/* MACROS  */
static int do_svmac(int argc, char **argv, char *mode, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	return(Ft_save_macros(AMACRO, argv[2], mode));
}

/* SHOW FUNCTIONS */
static int do_shmac(int argc, char **argv, char *l, Command *cmp)
{
	if (argc > 3)
		return(usage(cmp));
	return(Ft_showmac(argc, argv, AMACRO));
}

/* SETUP */
static int do_shsetup(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 1)
		return(usage(cmp));
	return(Ft_showsetup());
}

/* FIT  */
static int do_shfit(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 1)
		return(usage(cmp));
	return(Ft_showfit());
}

/* MEMORY */
static int do_shmem(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
#if !defined(NOMALLINFO)
	return(Ft_showmem());
#else
	fprintf(stderr, "%s: Function not supported.\n", cmp->fname);
	return(ERRR);
#endif
}

/* TABLE */
static int do_shtab(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	return(Ft_showtable());
}

#define SWALLOW_SPACE(c) {while (*c && (*c == ' ' || *c == '\t')) c++;}

/* DO_ECHO FUNCTION */
static int do_echo(int argc, char **argv, char *line, Command *cmp)
{
	char *cp;

	if (argc == 1) {
		fputc('\n', stdout);
		return(0);
	}
	cp = line + strlen(argv[0]) + 1;
	if (strcmp(argv[1], "-n") == 0) {
		SWALLOW_SPACE(cp);
		cp += 2;
		SWALLOW_SPACE(cp);
		line[strlen(line)-1] = '\0';
	}

	fputs(cp, stdout);
	return(0);
}

/* DO_SYSTEM FUNCTION */
static int do_system(int argc, char **argv, char *line, Command *cmp)
{
	int val;
	char fromline[80];
	extern char Ft_Shell[];
	extern int errno;

	errno = 0;
	signal_off();
	switch (argc) {
		case 0:
			val = system(line);
			break;
		case 1:
#ifdef VMS
		sprintf(fromline, "%s", Ft_Shell);
#else
			sprintf(fromline, "exec %s", Ft_Shell);
#endif
			val = system(fromline);
			fputc('\n', stderr);
			break;
		default:
			val = system((line + strlen(argv[0]) + 1));
			break;
	}
	signal_on();
	if (Slowterm && Ft_Interact && !Ft_iolevel()) {
		fputs("\nHit return to continue", stdout);
		fgets(fromline, 80, stdin);
	}
	if (val) {
		if (val == ERRR)
			perror("system");
		else
			fputs("Warning: System returned an error.\n", stderr);
		return(ERRR);
	}
	return(0);
}

/* DO_VI FUNCTION */
static int do_vi(int c, char **v, char *line, Command *cmp)
{
	signal_off();
	system(line);
	signal_on();
	return(0);
}

/* DO_FIT FUNCTION  */
static int do_fit(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 4 && (argc != 3 || (Ft_Methi != LS_REG && Ft_Methi != LA_REG)))
		return(usage(cmp));
	return(Ft_fits(argc, argv, (int) *Ft_Data));
}

/* DO_ADJUST FUNCTION */
static int do_adjust(int argc, char **argv, char *l, Command *cmp)
{
	int i, j;
	float flj;

	if (argc < 2 || (int) *Ft_Param < argc - 1) {
		fprintf(stderr, "%s: Invalid number of parameters.\n",
		cmp->fname);
		return(ERRR);
	}
	else if (Ft_Methi != ML_FIT && Ft_Methi != LS_FIT) {
		fprintf(stderr, "%s: Warning: Not active under `%s' method.\n",
		cmp->fname, Ft_Method[Ft_Methi].name);
	}
	for (i=1;i < argc; i++) {
		if (sscanf(argv[i], "%f", &flj) != 1) {
			fprintf(stderr, "%s: Could not read number \"%s\".\n",
			cmp->fname, argv[i]);
			return(ERRR);
		}
		j = (int)flj;
		if (j<1 || j> (int) *Ft_Param) {
			fprintf(stderr, "%s: Invalid parameter %d.\n",
			cmp->fname, j);
			Ft_Mlist = 0;
			return(ERRR);
		}
		Ft_Miparx1[i] = j;
	}
	Ft_Mlist = i -1;
	return(0);
}

/* DO_LOAD FUNCTION */
static int do_load(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	return(Ft_pushio(argv[1], AFILE, (char *) 0));
}

/* DO_READ FUNCTION  */
static int dataread(int argc, char **argv, int exec, Command *cmp)
{
	int i;
	Symbol *table[MAXVAR];
	int loctable[MAXVAR];
	int irange[2][MAXVAR];
	int lines[3];
	double range[2][MAXVAR];

	if (argc < 3)
		return(usage(cmp));
	if (argc > MAXVAR) {
		fprintf(stderr, "%s: %d: Too many variables.\n", cmp->fname, argc-2);
		return(ERRR);
	}
	lines[0] = 1;
#ifndef INT_MAX
#define INT_MAX 2147483647
#endif
	lines[1] = INT_MAX;
	lines[2] = 1;
	for (i=0; i<argc-2;i++) {
		if (getrange(argv[i+2], i, range, lines, irange,
		loctable, table, 1, cmp) == ERRR) {
			return(ERRR);
		}
	}
	return(Ft_readvar(argv, table, loctable, irange, range,
	lines, argc-2, exec, cmp->fname));
}

static int getrange(char *arg, int i, double range[][MAXVAR], int *lines,
int irange[][MAXVAR], int *loctable,
Symbol **table, int alloc_if_not, Command *cmp)
{
	char *sc, *ec, *cp;
	char name[TOKENSIZE];
	extern double strtod(const char *, char **);
	extern Symbol *Ft_lookup(char *);

	cp = arg;
	sc = name;
	while (*cp && *cp != ':' && *cp != '[' && *cp != '{')
		*sc++ = *cp++;
	*sc = '\0';
	if (loctable != (int *)NULL) {
		if (*cp++ == ':') {
			loctable[i] = atoi(cp);
		}
		else {
			loctable[i] = i+1;
		}
	}
	if ((table[i] = Ft_lookup(name)) == 0) {
		if (Ft_varcpy(0, name) != VEC) {
			fprintf(stderr, "%s: %s: Illegal vector name.\n",
			cmp->fname, name);
			return(ERRR);
		}
		if (alloc_if_not) {
			table[i] = Ft_install(name, UNDEFVEC, Ft_Samples);
		}
		else {
			fprintf(stderr, "%s: %s: Inexistant vector.\n",
			cmp->fname, name);
			return(ERRR);
		}
	}
	else if (table[i]->type != VEC && table[i]->type != UNDEFVEC) {
		fprintf(stderr, "%s: %s: Not a vector.\n",
		cmp->fname, table[i]->name);
		return(ERRR);
	}

	if ((sc = strstr(arg, "{")) != 0) {
		char *eh;
		char low[TOKENSIZE+1];
		char high[TOKENSIZE+1];
		char skip[TOKENSIZE+1];

		if ((ec = strstr(arg, "}")) == 0) { /* get last address */
			fprintf(stderr, "%s: %s: Unmatched brace.\n",
			cmp->fname, arg);
			return(ERRR);
		}
		sc++; /* skip brace */
		cp = low;
		while (*sc != ':' && sc < ec) { /* read in lower boundary */
			*cp = *sc;
			cp++; sc++;
		}
		*cp = '\0';
		if (cp == low || *sc != ':') {
			fprintf(stderr, "%s: Low line range misconstruction at: %s.\n",
			cmp->fname, sc);
			return(usage(cmp));
		}
		sc++; /* skip colon */
		cp = high;
		while (*sc != ':' && sc < ec) { /* read in upper boundary */
			*cp = *sc;
			cp++; sc++;
		}
		*cp = '\0';
		if (cp == high) {
			fprintf(stderr, "%s: High line range misconstruction at: %s.\n",
				cmp->fname, sc);
			return(usage(cmp));
		}
		if (*sc == ':') { /* read in optional skip */
			sc++; /* skip colon */
			cp = skip;
			while (sc < ec) { /* read in skip */
				*cp = *sc;
				cp++; sc++;
			}
			*cp = '\0';
			if (cp == skip) {
				fprintf(stderr,
				"%s: Skip line range misconstruction at: %s.\n",
				cmp->fname, sc);
				return(usage(cmp));
			}
			if (strcmp(skip, "*") == 0) {
				lines[2] = 1;
			}
			else {
				lines[2] = (int) strtod(skip, &eh);
				if (lines[2] <=0)
					lines[2] = 1;
#ifndef SUN3
				if (*eh != '\0') {
#else
				if (*--eh != '\0') {  /* SUN OS3.5 strtod brain dead */
#endif
					fprintf(stderr,
					"%s: Skip line range not a number: %s.\n",
					cmp->fname, skip);
				}
			}
		}
		if (strcmp(low, "*") == 0) {
		   	lines[0] = 0;
		}
		else {
			lines[0] = (int) strtod(low, &eh);
#ifndef SUN3
			if (*eh != '\0') {
#else
			if (*--eh != '\0') {  /* SUN OS3.5 strtod brain dead */
#endif
				fprintf(stderr,
				"%s: Low line range not a number: %s.\n",
				cmp->fname, low);
				return(usage(cmp));
			}
		}
		if (strcmp(high, "*") == 0) {
			lines[1] = INT_MAX; /* in theory... */
		}
		else {
			lines[1] = (int) strtod(high, &eh);
#ifndef SUN3
			if (*eh != '\0') {
#else
			if (*--eh != '\0') {  /* SUN OS3.5 strtod brain dead */
#endif
				fprintf(stderr,
				"%s: High range line not a number: %s.\n",
				cmp->fname, high);
				return(usage(cmp));
			}
		}
	}

	irange[0][i] = irange[1][i] = 0;
	if ((sc = strstr(arg, "[")) != 0) {
		char *eh;
		char *cplow, *cphigh;
		char low[TOKENSIZE+1];
		char high[TOKENSIZE+1];

		if (strstr(arg, "]") == 0) {
			fprintf(stderr, "%s: %s: Unmatched bracket.\n",
			cmp->fname, arg);
			return(ERRR);
		}
		if (sscanf(sc, "[%[^:]:%[^]]", low, high) != 2) {
			fprintf(stderr, "%s: Range misconstruction at: %s.\n",
			cmp->fname, sc);
			return(usage(cmp));
		}
		cplow = low;
		if (cplow[0] == 'c' || cplow[0] == 'C') {
			/* irange[0][i] = 0; already */
			cplow++;
		}
		if (cplow[0] == 'b' || cplow[0] == 'B') {
			irange[0][i] = 1;  /* irange will be 2 on break */
			cplow++;
		}
		if (strcmp(cplow, "*") == 0) {
			irange[0][i] = 0; /* must be reset for stupid case b* or B* */
		}
		else {
			irange[0][i]++;
			range[0][i] = strtod(cplow, &eh);
#ifndef SUN3
			if (*eh != '\0') {
#else
			if (*--eh != '\0') {  /* SUN OS3.5 strtod brain dead */
#endif
				fprintf(stderr, "%s: Low range misconstruction at: %s.\n",
				cmp->fname, sc);
				return(usage(cmp));
			}
		}
		cphigh = high;
		if (cphigh[0] == 'c' || cphigh[0] == 'C') {
		/* 	irange[1][i] = 0; already */
			cphigh++;
		}
		if (cphigh[0] == 'b' || cphigh[0] == 'B') {
			irange[1][i] = 1;  /* irange will be 2 on break */
			cphigh++;
		}
		if (strcmp(cphigh, "*") == 0) {
			irange[1][i] = 0; /* must be reset in case b* or B* */
		}
		else {
			irange[1][i]++;
			range[1][i] = strtod(cphigh, &eh);
#ifndef SUN
			if (*eh != '\0') {
#else
			if (*--eh != '\0') {  /* SUN OS3.5 strtod brain dead */
#endif
				fprintf(stderr, "%s: High range misconstruction at: %s.\n",
				cmp->fname, sc);
				return(usage(cmp));
			}
		}
	}
	return(0);
}

#define BREAKLOOP 1
#define CONTLOOP  2

static int do_svvec(int argc, char **argv, char *mode, Command *cmp)
{
	FILE *fp = stdout;
	int breakcond;
	int i, j;
	Symbol *sym[MAXVAR];
	int lines[3];
	int irange[2][MAXVAR];
	double range[2][MAXVAR];

	if ((int) *Ft_Data == 0) {
		fprintf(stderr, "%s: No data!\n", cmp->fname);
		return(ERRR);
	}
	if (argc > MAXVAR) {
		fprintf(stderr, "%s: %d: Too many vectors.\n", cmp->fname, argc);
		return(ERRR);
	}
	if (*mode != 's') argc--;
	if (argc < 3)
		return(usage(cmp));

	lines[0] = 1;
#ifndef INT_MAX
#define INT_MAX 2147483647
#endif
	lines[1] = INT_MAX;
	lines[2] = 1;
	for (i=0; i<argc-2;i++) {
		if (getrange(argv[i+2], i, range, lines, irange, (int *)0,
		sym, 0, cmp) == ERRR) {
			return(ERRR);
		}
	}
	switch (*mode) {
		case 'w':
		case 'a':
			if ((fp = fopen(argv[argc], mode)) == 0) {
				fprintf(stderr, "%s: %s: Permission denied.\n",
				cmp->fname, argv[argc]);
				return(ERRR);
			}
#if 1
			fprintf(fp, "%c\n", Ft_Comchar);
			{  /* routines to include time */
				time_t tt;
				char *ct;
		
				tt = time(NULL);
				ct = asctime(localtime(&tt));     /* puts a trailing \n */
				fprintf(fp, "%c Saved on %s", Ft_Comchar, ct);
			}
			fprintf(fp, "%c Column list of vectors: ", Ft_Comchar);
			for (j=0;j<argc-2;j++) {
				fprintf(fp, " %s", sym[j]->name);
			}
			fprintf(fp, "\n%c\n", Ft_Comchar);
#endif
			break;
		case 's':
			if ((int) *Ft_Data > 24 && Ft_Interact && *Ft_Pager) {
				if ((fp = popen(Ft_Pager, "w")) == (FILE *)NULL)  {
					fprintf(stderr, "Warning: %s: Could not open pager %s.\n",
					cmp->fname, Ft_Pager);
					fp = stdout;
				}
			}
			break;
		default:
			fprintf(stderr, "%s: Impossible printing mode.\n",
			cmp->fname);
			Ft_catcher(ERRR);
	}

	for (i=1;i<= (int) *Ft_Data;i+=lines[2]) {
		if (i < lines[0])
			continue;
 		if (i > lines[1])
       		break;
		breakcond = 0;
		for (j=1;j<argc-2;j++) { /* A loop to check conditions */
       		if (irange[0][j] && sym[j]->u.vec[i] < range[0][j]) {
          		if (irange[0][j] == 2)
               		breakcond = BREAKLOOP;
           		else
               		breakcond = CONTLOOP;
           		break;
       		}
       		if (irange[1][j] && sym[j]->u.vec[i] > range[1][j]) {
           		if (irange[1][j] == 2)
               		breakcond = BREAKLOOP;
           		else
               		breakcond = CONTLOOP;
           		break; 
			}
		}
   		if (breakcond) { /* Do we continue? */
       		if (breakcond == CONTLOOP) {
           		breakcond = 0;
           		continue;
       		}
       		else if (breakcond == BREAKLOOP) {
           		break;
       		}
       		/* What the heck is going on ? */
       		fprintf(stderr, "ERROR: Impossible condition in svvec.\n");
       		Ft_catcher(ERRR);
   		} 

		if (*mode == 's') {  /* Now show the line */
			if (fprintf(fp, " %4d:", i) < 0)
				break;
			for (j=0;j<argc-2;j++) {
				fprintf(fp, Ft_TFormat, sym[j]->u.vec[i]);
			}
			if (fputc('\n', fp) < 0)
				break;
		}
		else { /* or  save it */
			fprintf(fp, Ft_Format, sym[0]->u.vec[i]);
			for (j=1;j<argc-2;j++) {
				fprintf(fp, Ft_TFormat, sym[j]->u.vec[i]);
			}
			fputc('\n', fp);
		}
	}
	if (*mode == 's') {
		if (fp != stdout) {
			fflush(fp);
			pclose(fp);
		}
	}
	else {	
		fclose(fp);
	}
	return(0);
}

/*
typedef union {
	double db;
	char* str;
	} Vardesc;
*/

static int do_svvar(int argc, char **argv, char *mode, Command *cmp)
{
	FILE *fp = stdout;
	int j;
	Vardesc vvec[MAXVAR];
	int astring[MAXVAR];

	if (*mode != 's')
		argc--;
	if (argc < 3)
		return(usage(cmp));
	if (argc-2 > MAXVAR) {
		fprintf(stderr, "%s: %d: Too many variables.\n",
		cmp->fname, argc-2);
		return(ERRR);
	}
	if (splitvar(2, argc, argv, vvec, astring, cmp) == ERRR)
		return(ERRR);

	switch(*mode) {
		case 'w':
		case 'a':
			if ((fp = fopen(argv[argc], mode)) == 0) {
				fprintf(stderr, "%s: %s: Permission denied.\n",
				cmp->fname, argv[argc]);
				return(ERRR);
			}
			if (astring[0]) {
				   fputs(vvec[0].str, fp);
			}
			else {
				   fprintf(fp, Ft_Format, vvec[0].db);
			}
			for (j=1;j<argc-2;j++) {
				if (astring[j]) {
					fprintf(fp, "\t%s", vvec[j].str);
				}
				else {
					fprintf(fp, Ft_TFormat, vvec[j].db);
				}
			}
			fputc('\n', fp);
			fclose(fp);
			break;
		case 's':
			for (j=0;j<argc-2;j++) {
				if (astring[j]) {
					fprintf(fp, "\t%s", vvec[j].str);
				}
				else {
					fprintf(fp, Ft_TFormat, vvec[j].db);
				}
			}
			fputc('\n', fp);
			break;
		default:
			fprintf(stderr, "%s: Impossible printing mode.\n", cmp->fname);
			Ft_catcher(ERRR);
	}
	return(0);
}

static int splitvar(int ifrom, int xto, char **argv, Vardesc *dbvec, int *astringvec, Command *cmp)
{
	register int i, j;
	char *cp;
	int index;
	Symbol *sym;
	char name[TOKENSIZE+4];
	extern Symbol *Ft_lookup(char *);

	for (i=0, j=ifrom; j<xto; i++, j++) {
		sscanf(argv[j], "%[^[]", name);
		index = 0;
		if ((sym = Ft_lookup(name)) == 0) {
			fprintf(stderr, "%s: %s: Unknown variable.\n", cmp->fname, name);
			return(ERRR);
		}
		astringvec[i] = 0;  /* assume they all are numbers */
		switch(sym->type) {
			case BLTINSTRVAR:
			case BLTINSTRCONST:
			case STRVAR:
			case STRCONST:
				astringvec[i] = 1;
				dbvec[i].str = sym->u.str;
				break;
			case BLTINVAR:
			case BLTINCONST:
			case VAR:
			case CONST:
				dbvec[i].db = sym->u.val;
				break;
			case PARAM:
				if ((int) *Ft_Param == 0) {
					fprintf(stderr, "%s: %s: Null size vector!\n",
					cmp->fname, name);
					return(ERRR);
				}
				if ((cp = strstr(argv[j], "[")) != NULL) {
					if (sscanf(cp+1, "%d]", &index) != 1) {
						fprintf(stderr,
						"%s: %s: Badly formed vector element.\n",
						cmp->fname, argv[j]);
						return(ERRR);
					}
				}
				if (index < 1 || (int) *Ft_Param < index) {
					fprintf(stderr, "%s: %s: Illegal parameter index.\n",
					cmp->fname, name);
					return(ERRR);
				}
				dbvec[i].db = sym->u.vec[index];
				break;
			case VEC:
				if ((int) *Ft_Data == 0) {
					fprintf(stderr, "%s: %s: Null size vector!\n",
					cmp->fname, name);
					return(ERRR);
				}
				if ((cp = strstr(argv[j], "[")) != NULL) {
					if (sscanf(cp+1, "%d]", &index) != 1) {
						fprintf(stderr,
						"%s: %s: Badly formed vector element.\n",
						cmp->fname, argv[j]);
						return(ERRR);
					}
				}
				if (index < 1 || (int) *Ft_Data < index) {
					fprintf(stderr, "%s: %s: Illegal vector index.\n",
					cmp->fname, name);
					return(ERRR);
				}
				dbvec[i].db = sym->u.vec[index];
				break;
			default:
				fprintf(stderr, "%s: %s: Not a printable variable.\n",
				cmp->fname, sym->name);
				return(ERRR);
		}
	}
	return(i);
}

static int do_svpar(int argc, char **argv, char *mode, Command *cmp)
{
	int j;
	FILE *fp = stdout;
	Vardesc vvec[MAXVAR];
	int astring[MAXVAR];
	extern char Ft_Pname[];

	if ((int) *Ft_Param == 0) {
		fprintf(stderr, "%s: No parameters!\n", cmp->fname);
		return(ERRR);
	}
	if (*mode != 's')
		argc--;
	if (argc < 2)
		return(usage(cmp));
	if (argc-2 > MAXVAR) {
		fprintf(stderr, "%s: %d: Too many variables.\n",
		cmp->fname, argc-2);
		return(ERRR);
	}
	if (argc > 2) {
		if (splitvar(2, argc, argv, vvec, astring, cmp) == ERRR)
			return(ERRR);
	}
	switch (*mode) {
		case 'w':
		case 'a':
		if ((fp = fopen(argv[argc], mode)) == 0) {
			fprintf(stderr, "%s: %s: Permission denied.\n",
			cmp->fname, argv[argc]);
			return(ERRR);
		}
		if (argc > 2) {
			if (astring[0]) {
				fputs(vvec[0].str, fp);
			}
			else {
				fprintf(fp, Ft_Format, vvec[0].db);
			}
			for (j=1;j<argc-2;j++) {
				if (astring[j]) {
					   fprintf(fp, "\t%s", vvec[j].str);
				}
				else {
					   fprintf(fp, Ft_TFormat, vvec[j].db);
				}
			}
			fputc('\t', fp);
		}
		fprintf(fp, Ft_Format, Ft_A[1]);
		fprintf(fp, Ft_TFormat, Ft_DA[1]);
		for (j=2;j<=(int) *Ft_Param;j++) {
			fprintf(fp, Ft_TFormat, Ft_A[j]);
			fprintf(fp, Ft_TFormat, Ft_DA[j]);
		}
		fputc('\n', fp);
		fclose(fp);
		break;
		case 's':
		if ((int) *Ft_Param > 24 && Ft_Interact && *Ft_Pager) {
			if ((fp = popen(Ft_Pager, "w")) == (FILE *)NULL)  {
				fprintf(stderr, "Warning: %s: Could not open pager %s.\n",
				cmp->fname, Ft_Pager);
				fp = stdout;
			}
		}
		if (argc > 2) {
			if (astring[0]) {
				fputs(vvec[0].str, fp);
			}
			else {
				fprintf(fp, Ft_Format, vvec[0].db);
			}
			for (j=1;j<argc-2;j++) {
				if (astring[j]) {
					   fprintf(fp, "\t%s", vvec[j].str);
				}
				else {
					   fprintf(fp, Ft_TFormat, vvec[j].db);
				}
			}
			fputc('\n', fp);
		}
		for (j=1;j <= (int) *Ft_Param;j++) {
			fprintf(fp, " %s[%d]:", Ft_Pname, j);
			fprintf(fp, Ft_TFormat, Ft_A[j]);
			fprintf(fp, " +/- ");
			fprintf(fp, Ft_TFormat, Ft_DA[j]);
			fputc('\n', fp);
		}
		if (fp != stdout) {
			fflush(fp);
			pclose(fp);
		}
		break;
		default:
		fprintf(stderr, "%s: Impossible printing mode.\n", cmp->fname);
		Ft_catcher(ERRR);
	}
	return(0);
}

#include <setjmp.h>
/* CMODE FUNCTION */
static int do_cmode(int argc, char **argv, char *l, Command *cmp)
{
	extern jmp_buf Ft_Jump;
	extern FILE *Ft_Outprint;
	int val;

	if (argc != 1)  /* send to let if some command  */
		return(let(argc, argv, l, cmp));
	if (Ft_Interact && !Ft_iolevel()) {
		fputs("\tUse `fmode' or ^D to come back...\n", stderr);
		setjmp(Ft_Jump);
	}
	Ft_Mode = CMODE;
	for(Ft_initcode(); (val = Ft_more_input(0, 0));Ft_initcode()) {
		if (val == ERRR)
			continue;
		Ft_mathyyparse();
	}
	fflush(Ft_Outprint);
	return(0);
}

/* DO_DUMPLOT FUNCTION  */
static int do_dumplot(int argc, char **argv, char *l, Command *cmp)
{
	int i;
	Symbol *sym;
	double *dblv[MAXDARG];
	extern Symbol *Ft_lookup(char *);

	if ((int) *Ft_Data == 0) {
		fprintf(stderr, "%s: No data!\n", cmp->fname);
		return(ERRR);
	}

	if (argc < 2 || MAXDARG < argc) {
		fprintf(stderr, "%s: %d: Unsupported number of argument.\n",
		cmp->fname, argc);
		return(ERRR);
	}
	for (i=0;i<argc-1;i++) {
		if ((sym = Ft_lookup(argv[i+1])) == 0) {
			fprintf(stderr, "%s: %s: Unknown vector.\n",
			cmp->fname, argv[i+1]);
			return(ERRR);
		}
		if (sym->type != VEC) {
			fprintf(stderr, "%s: %s: Not a vector.\n",
			cmp->fname, sym->name);
			return(ERRR);
		}
		dblv[i] = sym->u.vec;
	}
	dblv[i] = 0;
	return(Ft_dumplot(dblv, (int) *Ft_Data));
}

/* DO_DEFINE FUNCTION */
static int do_defmac(int argc, char **argv, char *l, Command *cmp)
{
	Macro *mac;
	char *cp;

	if (argc != 3)
		return(usage(cmp));

	if (Ft_almost(argv[1], "m!acro") || Ft_almost(argv[1], "u!nmacro")) {
		fprintf(stderr, "%s: %s: Too dangerous to define that!\n",
		cmp->fname, argv[1]);
		return(ERRR);
	}
	if ((mac = Ft_maclook(argv[1], ANALIAS)) != NULL) {
		fprintf(stderr, "%s: %s: Name conflict with existing alias.\n",
		cmp->fname, argv[1]);
		return(ERRR);
	}
	if ((cp = Ft_readmacro("macro? ")) == NULL) {
		return(ERRR);
	}
	if ((mac = Ft_maclook(argv[1], AMACRO)) != NULL) {
		if (Ft_macremove(argv[1], AMACRO) == ERRR) {
			return(ERRR);
		}
	}
	if ((mac = Ft_macinstall(argv[1], cp, AMACRO)) == NULL) {
		return(ERRR);
	}
	mac->nargs = atoi(argv[2]);
	return(0);
}

/* DO_UNDEFINE FUNCTION */
static int do_udefmac(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc < 2)
		return(usage(cmp));
	for (i=1;i<argc;i++) {
		Ft_macremove(argv[i], AMACRO);
	}
	return(0);
}

/* DO_WHILE FUNCTION */
static int do_while(int argc, char **argv, char *line, Command *cmp)
{
	char condition[TOKENSIZE+16];
	extern double *Ft_If_value;
	Macro *lmac;
	int liolevel;
	int ivalue;
	char *cp;
	char macroname[MAXMACRO];
	extern int Ft_Dolevel;
	extern char *Ft_read_loop(char **argv, char *fprom);

	if (argc < 2 || argv[1][0] != '(')
		return(usage(cmp));

	sprintf(condition, "if_value = %s\n", argv[1]);
	if (let(0, argv, condition, 0) == ERRR)
		return(ERRR);
	sprintf(macroname, "while_loop%d", Ft_Dolevel+1);
	if ((lmac = Ft_maclook(macroname, AMACRO)) != NULL) {
		   if (Ft_macremove(macroname, AMACRO) == ERRR) {
			   return(ERRR);
		   }
	}
	if (argc > 2) {
		cp = line + strlen(argv[0]) + strlen(argv[1]) + 2;
	}
	else if ((cp = Ft_read_loop(argv, "while")) == NULL) {
		   return(ERRR);
	}
	if ((lmac = Ft_macinstall(macroname, cp, AMACRO)) == NULL) {
		return(ERRR);
	}
	lmac->nargs = 0;
	liolevel = Ft_iolevel();
	Ft_Dolevel++;
	ivalue = (int) *Ft_If_value;
	while (ivalue) {
		if (macrun(lmac, liolevel) == ERRR) {
			Ft_Dolevel--;
			return(ERRR);
		}
		if (let(0, argv, condition, 0) == ERRR) {
			Ft_Dolevel--;
			return(ERRR);
		}
		ivalue = (int) *Ft_If_value;
	}
	Ft_Dolevel--;
	return(0);
}

/* DO_FOREACH FUNCTION */
static int do_foreach(int argc, char **argv, char *line, Command *cmp)
{
	Macro *lmac;
	Symbol *lvar;
	FILE *pfp;
	int liolevel;
	int looploop, i, c;
	char *cp;
	char macroname[MAXMACRO];
	char commandline[LINESIZE+4];
	extern int Ft_Dolevel;
	extern char *Ft_read_loop(char **argv, char *fprom);

	if (argc < 4)
		return(usage(cmp));
	if (!Ft_almost(argv[2], "in"))
		return(usage(cmp));
	if (Ft_varcpy(0, argv[1]) != STRVAR) {
		fprintf(stderr, "foreach: %s: Not a legal string name.\n", argv[1]);
		return(ERRR);
	}
	if ((lvar = Ft_lookup(argv[1])) != NULL) {
		if (Ft_symremove(argv[1], 1)) {
			return(ERRR);
		}
	}
	lvar = Ft_install(argv[1], STRVAR, TOKENSIZE+4);
	cp = line + strlen(argv[0]) + strlen(argv[1]) + strlen(argv[2]) + 3;
	sprintf(commandline, "%s", cp);
	sprintf(macroname, "foreach_loop%d", Ft_Dolevel+1);
	if ((lmac = Ft_maclook(macroname, AMACRO)) != NULL) {
		if (Ft_macremove(macroname, AMACRO) == ERRR) {
			return(ERRR);
		}
	}
	if ((cp = Ft_read_loop(argv, "foreach")) == NULL) {
		return(ERRR);
	}
	if ((lmac = Ft_macinstall(macroname, cp, AMACRO)) == NULL) {
		return(ERRR);
	}
	lmac->nargs = 0;

	if ((pfp = popen(commandline, "r")) == (FILE *)NULL) {
		commandline[strlen(commandline)-1] = '\0';
		fprintf(stderr, "%s: Could not open `%s' process.\n",
		cmp->fname, commandline);
		return(ERRR);
	}
	liolevel = Ft_iolevel();
	Ft_Dolevel++;
	looploop = 0;
	cp = lvar->u.str;
	while (1) {
		i = 0;
		while ((c = fgetc(pfp)) >= 0 && isspace(c) ) { /* swallow space */
			;
		}
		if (c < 0 ) {		/* EOF ? */
			break;
		}
		cp[i++] = c;
		/* read the token */
		while ((c = fgetc(pfp)) >= 0 && !isspace(c) && i < LINESIZE) {
			cp[i++] = c;
		}
		if (i >= LINESIZE) {
			fprintf(stderr, "Warning: %s: String %d is too long.\n",
			cmp->fname, ++looploop);
			continue;
		}
		cp[i] = 0;
		if (i == 0)
			break;
		if (macrun(lmac, liolevel) == ERRR) {
			fflush(pfp);
			pclose(pfp);
			Ft_Dolevel--;
			return(ERRR);
		}
		looploop++;
	}
	fflush(pfp); pclose(pfp);
	Ft_Dolevel--;
	if (looploop == 0) {
		commandline[strlen(commandline)-1] = '\0';
		fprintf(stderr, "Warning: %s: Command `%s' is an empty loop.\n",
		cmp->fname, commandline);
	}
	return(0);
}

static int macrun(Macro *mac, int level)
{
	char *cp;
	int eof;
	extern char *Ft_nextline(char *, int *);

	Ft_pushio(mac->line, AMACRO, mac->name);
	while (Ft_iolevel() > level) {
		if ((cp = Ft_nextline(Ft_Prompt_fm, &eof)) == NULL) {
			continue;
		}
		if (Ft_processline(cp) == ERRR) {
			return(ERRR);
		}
	}
	return(0);
}

static int do_alias(int argc, char **argv, char *line, Command *cmp)
{
	Macro *mac;
	char *cp;

	switch (argc) {
	case 1:
		return(Ft_showmac(2, argv, ANALIAS));
	case 2:
		if ((mac = Ft_maclook(argv[1], ANALIAS)) != NULL) {
			fputs(mac->line, stdout);
		}
		return(0);
	default:
		if (Ft_almost(argv[1], "al!ias") || Ft_almost(argv[1], "una!lias")) {
			fprintf(stderr, "%s: %s: Too dangerous to alias that!\n",
			argv[1], cmp->fname);
			return(ERRR);
		}
		if (*argv[1] == '&') {
			fprintf(stderr,
			"%s: %s: Not allowed to start an alias with `&'!\n",
			argv[1], cmp->fname);
			return(ERRR);
		}
		if (Ft_almost(argv[2], argv[1])) {
			fprintf(stderr, "%s: %s: Circular alias.\n",
			cmp->fname, argv[1]);
			return(ERRR);
		}
		if ((mac = Ft_maclook(argv[1], AMACRO)) != NULL) {
			fprintf(stderr, "%s: %s: Name conflict with existing macro.\n",
			cmp->fname, argv[1]);
			return(ERRR);
		}
		if ((mac = Ft_maclook(argv[1], ANALIAS)) != NULL) {
			if (Ft_macremove(argv[1], ANALIAS) == ERRR) {
				return(ERRR);
			}
		}
		cp = line + strlen(argv[0]) + strlen(argv[1]) + 2;
		if ((mac = Ft_macinstall(argv[1], cp, ANALIAS)) == NULL) {
			return(ERRR);
		}
		mac->nargs = 0;
		return(0);
	}
}

static int do_unalias(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc < 2)
		return(usage(cmp));
	for (i=1;i<argc;i++) {
		Ft_macremove(argv[i], ANALIAS);
	}
	return(0);
}

static int do_lock(int argc, char **argv, char *l, Command *cmp)
{
	int i, j;

	if (argc < 2)
		return(usage(cmp));
	for (j=0, i=1;i<argc;i++) {
		j += Ft_lock(1, argv[i], cmp->fname);
	}
	if (j)
		return(ERRR);
	return(0);
}

static int do_unlock(int argc, char **argv, char *l, Command *cmp)
{
	int i;

	if (argc < 2)
		return(usage(cmp));
	for (i=1;i<argc;i++) {
		Ft_lock(0, argv[i], cmp->fname);
	}
	return(0);
}

static int usage(Command *cmd)
{
	fprintf(stderr, "Usage: `%s' %s\n", cmd->fname, cmd->usage);
	return(ERRR);
}

static int do_stexp(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	Ft_Expandhist = 1;
	return(0);
}

static int do_stnexp(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	Ft_Expandhist = 0;
	return(0);
}

static int do_shexp(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%s\n", (Ft_Expandhist == 1? "on": "off") );
	return(0);
}

static int do_smooth(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 4)
		return(usage(cmp));
	return(Ft_run_smooth(argc, argv, (int) *Ft_Data));
}

static int do_fft(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 5)
		return(usage(cmp));
	return(Ft_run_fft(argc, argv, 1, (int) *Ft_Data));
}

static int do_invfft(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 5)
		return(usage(cmp));
	return(Ft_run_fft(argc, argv, -1, (int) *Ft_Data));
}

static int do_stpromptfm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	strncpy(Ft_Prompt_fm, argv[2], MAXPROMPT);
	Ft_Prompt_fm[MAXPROMPT] = '\0';
	return(0);
}

static int do_stpromptcm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	strncpy(Ft_Prompt_cm, argv[2], MAXPROMPT);
	Ft_Prompt_cm[MAXPROMPT] = '\0';
	return(0);
}

static int do_stpromptpm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 3)
		return(usage(cmp));
	strncpy(Ft_Prompt_pm, argv[2], MAXPROMPT);
	Ft_Prompt_pm[MAXPROMPT] = '\0';
	return(0);
}

static int do_shpromptpm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fputs(Ft_Prompt_pm, stderr);
	return(0);
}

static int do_shpromptcm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fputs(Ft_Prompt_cm, stderr);
	return(0);
}

static int do_shpromptfm(int argc, char **argv, char *l, Command *cmp)
{
	if (argc != 2)
		return(usage(cmp));
	fputs(Ft_Prompt_fm, stderr);
	return(0);
}

static int do_sterr(int argc, char **argv, char *l, Command *cmp)
{
	if (argc == 2 || argv[2][0] == '?') {
		fputs("Error check levels:\n", stderr);
		fputs("\t 0: Clear check bits.\n", stderr);
		fputs("\t 1: Check for `infinity' values.\n", stderr);
		fputs("\t 2: Check for `not a number' values.\n", stderr);
		fputs("\t 3: Check for `out of domain' math function errors.\n",
		stderr);
		fputs("\t 4: Check for `out of range' math function errors.\n",
		stderr);
	}
	else {
		 int chk, i;
		float flchk;

		for (i=2;i<argc;i++) {
			if (sscanf(argv[i], "%f", &flchk) != 1) {
				fprintf(stderr, "%s: Could not read number \"%s\".\n",
				cmp->fname, argv[i]);
				return(ERRR);
			}
			chk = (int)flchk;
			if (chk)
				Ft_Check |= 01<<(chk-1);
			else
				Ft_Check = 0;
		}
	}
	return(0);
}

static int do_sherr(int argc, char **argv, char *l, Command *cmp)
{
	extern int Ft_Check;

	if (argc != 2)
		return(usage(cmp));
	fprintf(stderr, "%o\n", Ft_Check);
	return(0);
}

static int do_if(int argc, char **argv, char *line, Command *cmp)
{
	char condition[TOKENSIZE+16];
	extern double *Ft_If_value;
	int elseif;
	int ivalue;

	elseif = Ft_almost(cmp->fname, "else");  /* who called me? */
	if (argc < 3 || argv[1][0] != '(') {
		if (!elseif) {
			return(usage(cmp));
		}
		else {
			fputs("if: Bad 'else if' construction.\n", stderr);
			return(ERRR);
		}
	}
	sprintf(condition, "if_value = %s\n", argv[1]);
	if (let(0, argv, condition, 0) == ERRR)
		return(ERRR);
	ivalue = (int) *Ft_If_value;
	if (!ivalue) { /* FALSE */
		if (Ft_almost(argv[2], "th!en")) {
			if (elseif) {
				return(Ft_switchif(FALSE_IF));
			}
			else {
				return(Ft_pushif(FALSE_IF));
			}
		}
	}
	if (elseif) {	 /* TRUE */
		if (Ft_switchif(TRUE_IF) == ERRR)
			return(ERRR);
		return(0);
	}
	if (!Ft_almost(argv[2], "th!en")) {
		char *cp;

		cp = line + strlen(argv[0]) + strlen(argv[1]) + 2;
		return(Ft_command(argc-2, argv+2, cp));
	}
	return(Ft_pushif(TRUE_IF));
}

static int do_else(int argc, char **argv, char *line, Command *cmp)
{
	if (argc == 1)
		return(Ft_switchif(FORCED_IF));
	if (Ft_almost(argv[1], "if")) {
		char *cp;

		cp = line + strlen(argv[0]) + 1;
		return(do_if(argc-1, argv+1, cp, cmp));
	}
	return(usage(cmp));
}

static int do_endif(int argc, char **argv, char *line, Command *cmp)
{
	if (argc != 1)
		return(usage(cmp));
	return(Ft_popif());
}

static int do_parse(int argc, char **argv, char *line, Command *cmp)
{
	int i;

	fprintf(stderr, "line: %s", line);
	for (i=0; i< argc;i++)
		fprintf(stderr, "argv[%d]: %s\n", i, argv[i]);
	return(0);
}

static int do_spline(int argc, char **argv, char *line, Command *cmp)
{
	double dy1, dyn;
	double *vec1, *vec2;
	Symbol *sym;
	extern Symbol *Ft_lookup(char *);

	if (3 > argc || argc > 5)
		return(usage(cmp));

	dyn = dy1 = 1.0e30; /* natural by default */
	switch (argc) {
		case 5:
		if (strcmp(argv[5], "*") != 0 && sscanf(argv[4], "%lf", &dyn) != 1) {
			fprintf(stderr,
			"%s: Could not read number from argument 5.\n", cmp->fname);
			return(ERRR);
		}
		case 4:
		if (strcmp(argv[4], "*") != 0 && sscanf(argv[3], "%lf", &dy1) != 1) {
			fprintf(stderr,
			"%s: Could not read number from argument 4.\n", cmp->fname);
			return(ERRR);
		}
		case 3:
		break;
	}
	if ((sym = Ft_lookup(argv[1])) == NULL || sym->type != VEC) {
		fprintf(stderr, "%s: %s: No such vector.\n", cmp->fname, argv[1]);
		return(ERRR);
	}
	vec1 = sym->u.vec;
	if ((sym = Ft_lookup(argv[2])) == NULL || sym->type != VEC) {
		fprintf(stderr, "%s: %s: No such vector.\n", cmp->fname, argv[2]);
		return(ERRR);
	}
	vec2 = sym->u.vec;
	return(Ft_spline(vec1, vec2, dy1, dyn, (int) *Ft_Data));
}

static void signal_on(void)
{
	signal(SIGINT, Ft_catcher);
	signal(SIGHUP, Ft_catcher);
#ifdef SIGTSTP
	signal(SIGTSTP, Ft_catcher);
#endif
}

static void signal_off(void)
{
	/**
	signal(SIGINT, SIG_DFL);
	signal(SIGHUP, SIG_DFL);
	***/
#ifdef SIGTSTP
	signal(SIGTSTP, SIG_DFL);
#endif
}

/* The module for dynamic loading */
#ifdef DL_YES

#ifdef SVR4
#include "install.svr4.c"
#define DL_INCLUDED
#endif

#ifdef IRIX5
#include "install.irix5.c"
#define DL_INCLUDED
#endif

#ifndef DL_INCLUDED
#include "install.c"
#endif

#undef DL_INCLUDED

#else  /* AIX or HP-UX or VMS */

#ifdef VMS
#include "install_dummy.c"
#else
#include "install.dummy.c"
#endif /* VMS */

#endif /* DL_YES */
