#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef NOMALLOC_H
#include <malloc.h>
#endif

#ifdef __GNUC__
#ifndef alloca
#define alloca __builtin_alloca
#endif
#else
#if defined (sparc) || defined (sgi)
#include <alloca.h>
#endif
#endif

#include "fudgit.h"
#include "macro.h"
#include "setshow.h"
#include <readline/history.h>
#include "head.h"

/* Dealing with the IO stack  */

typedef struct Iodes {
	union {
		FILE *fp;
		char *lp;
	} u;
	int type;
	int lino;
	int iflvl;
	char line[MAXMACRO];  /* contain possible emacro */
	char name[TOKENSIZE];
} Iodes;

static Iodes Io[MAXLEVEL];
static int Iolevel = 0;
static int Filelevel = 0;
static char **argv;
static int Working = 0;

static int checkalmac(int , char **);
static int alreplace(int , char **, Macro *, char *);
static int mreplace(Macro *, char **, char *), clearpop(void);
static char *brkline(Iodes *, char *);
static int reporterr(void);
static int add_hist(char *);
static int contline(char *);
static FILE *curio(void);

jmp_buf Ft_Jump;

extern int history_expand(char *, char **);
extern void add_history(char *);
extern char *readline(char *);
extern int Ft_Interact;

char *Ft_nextline(char *, int *);

/* ALLOCATE ARGV */

int Ft_popio (void);
int Ft_processline (char *lp);
int Ft_pushio (char *string, int type, char *name);
extern int Ft_ifexp (char *cline);
extern int Ft_vgetargp (char *b, char **p, int type, char **add);
extern int Ft_ifrun (int c, char *v);
extern char *strcat (char *, const char *);
extern int Ft_iflevel (void);
extern int Ft_push_cwd (void);
extern int Ft_pop_cwd (void);
extern int Ft_clearpop_cwd (void);
extern int Ft_clearpop_if (void);
extern void Ft_cleanframe (void);
extern int Ft_autosymremove (int level);
extern int Ft_funcprocnotdef (void);
extern int Ft_cleansym (void);
extern int Ft_almost (char *, char *);
extern int Ft_command (int , char **, char *);
extern int Ft_exit (int val);

int Ft_initmac(void)
{
	int i;

	argv = (char **)calloc((unsigned)MAXTOKEN+1, sizeof(char *));
	if (argv == (char **)NULL) {
		fputs("Allocation error.\n", stderr);
		exit(1);
	}
	for (i=0; i< MAXTOKEN;i++) {
		argv[i] = (char *)calloc((unsigned)TOKENSIZE+1, sizeof(char));
		if (argv[i] == (char *)NULL) {
			fputs("Allocation error.\n", stderr);
			exit(1);
		}
	}
	Io[0].lino = 0;
	Io[0].u.fp = stdin;
	Io[0].type = AFILE;
	sprintf(Io[0].name, "stdin");
	return(0);
}

/* THE MAIN FMODE LOOP */
int Ft_run(void)
{
	char *cp;
	int eof;

	for (;;) {
#ifndef alloca
		alloca(0); /* cleanup */
#endif
		setjmp(Ft_Jump);
		Ft_Mode = FMODE;
		Working = NO;
		if ((cp = Ft_nextline(Ft_Prompt_fm, &eof)) == NULL) {
			if (eof == -2) {
				fputs("Use 'quit' or 'exit' to exit.\n", stderr);
			}
			continue;
		}
		if (Ft_Debug & DEBUG_RAW) {
			fputs(cp, stderr);
		}
		if (Ft_processline(cp) == ERRR) {
			int Ft_processline (char *lp);
			reporterr();
		}
	}
}

int Ft_processline(char *lp)
{
	int argc;
	char *cexp;
	int check = NOTHING;

	if (Ft_ifexp(lp))
		check = (QUOTES | EXPANSION | PARENTH);

	if ((argc = Ft_vgetargp(lp, argv, check, &cexp)) <= 0) { /* expand tokens */
	   	if (argc == VERRR && !Iolevel && Ft_Interact) {
			add_hist(lp);
			return(0);
	   	}
	   	return((argc? ERRR: 0));
	}
	if (!Iolevel && Ft_Interact) {
		add_hist(lp);
	}
	if ((check = checkalmac(argc, argv))) { /* expand aliases or macros */
		return(check);
	}
	if ((check = Ft_ifrun(argc, argv[0])) == TRUE_IF) {
		if (Ft_Debug & DEBUG_EXP) {
			fputs(cexp, stderr);
		}
		Working = YES;
		return(Ft_command(argc, argv, cexp));
	}
	return(check);
}

static int checkalmac(int margc, char **margv)
{
	Macro *mac;
	char macroline[MAXMACRO];

	if ((mac = Ft_maclook(margv[0], ANALIAS)) != 0) {  /* an alias */
		if (alreplace(margc, margv, mac, macroline) == ERRR) {
			return(ERRR);
		}
		Ft_pushio(macroline, ANALIAS, mac->name);
		return(1);
	}
	if ((mac = Ft_maclook(margv[0], AMACRO)) != 0) {  /* a macro */
		if (margc < mac->nargs + 1) {
			fprintf(stderr, "%s: Missing argument.\n", mac->name);
			return(ERRR);
		}
		if (margc > mac->nargs + 1) {
			fprintf(stderr, "Warning: %s: Too many arguments.\n", mac->name);
		}
		if (mac->nargs > 0) {
			if (mreplace(mac, margv, macroline) == ERRR) {
				return(ERRR);
			}
			Ft_pushio(macroline, AMACRO, mac->name);
		}
		else {
			Ft_pushio(mac->line, AMACRO, mac->name);
		}
		return(1);
	}
	return(0);
}

/* expand alias macro and keep argv[1] argv[2] ... */
static int alreplace(int margc, char **margv, Macro *mac, char *out)
{
	int i;
	int len, size;
	char *cp;

	cp = out;
	*cp = '\0';
	size = len = strlen(mac->line);
	strcat(cp, mac->line);
	cp += size;
	*(cp-1) = ' ';	/* remove trailing \n */
	for (i=1;i<margc;i++) {
		size = strlen(margv[i]);
		len += size;
		if (len < MAXMACRO) {
			strcat(cp, margv[i]);
			cp += size;
			*cp++ = ' '; len++;
			*cp = '\0';
		}
		else {
			fprintf(stderr, "%s: Alias expansion too long.\n", mac->name);
			return(ERRR);
		}
	}
	*cp++ = '\n';
	*cp = '\0';
	return(0);
}

/* replaces $1 $2 with macro arguments in argv[1] argv[2] ... */
static int mreplace(Macro *mac, char **v, char *out)
{
	int i;
	char *cp;
	char *in;
	int cnt = 0;

	in = mac->line;
	while (*in != '\0' && cnt < MAXMACRO) {
		if (*in == '$' && isdigit((int)*(in+1))) {
			if (in != mac->line && *(in-1) == '$') {
				in++; /* skip it */
				continue;
			}
			in++;
			i = *in - '0';
			in++;
			if (i>mac->nargs || i<1) {
				fprintf(stderr,
				"%s: Index %d out of range.\n", mac->name, i);
				return(ERRR);
			}
			cp = v[i];
			while (*cp) {
				*out = *cp;
				out++; cp++;
			}
		}
		else {
			*out = *in;
			out++; in++;
		}
		cnt++;
	}
	if (*in) {
		fprintf(stderr, "%s: Expanded macro too long.\n", mac->name);
		return(ERRR);
	}
	*out = '\0';
	return(0);
}

/* break a macro in multiple lines */
static char *brkline(Iodes *iop, char *out)
{
	if (*(iop->u.lp) == '\0')  /* a last new line */
		return(NULL);
	while (*(iop->u.lp) != '\n' && *(iop->u.lp) != '\0') {
		*out = *(iop->u.lp);
		iop->u.lp++; out++;
	}
	out[0] = '\n';
	out[1] = '\0';
	if (*(iop->u.lp) == '\0') {
		fputs("Non nl-terminated string.\n", stderr);
		return(NULL);
	}
	else {
		iop->u.lp++;
		return(iop->u.lp);
	}
}

char *Ft_nextline(char *prompt, int *eof)
{
	static char buffer[LINESIZE+4];
	char *buf;
	int cc = 0;

	if (Ft_Interact && !Iolevel) { /* Interactive mode  */
		char *cp, *out;
		int expt = 0;
		int continued = 0;
		char *promptr = prompt;

		fflush(stdout);
		fflush(stderr);
		if (Ft_iflevel())
			promptr = "if? ";
		*eof = ERRR;
		do { /* read multiple lines */
			buf = buffer + cc;
			if ((cp = readline((continued? "? ": promptr)))) {
				*eof = 0;
				if (Ft_Expandhist) {
					int iexp;

					iexp = history_expand(cp, &out);
					if (iexp == ERRR) { /* no history on wrong expansions */
						fprintf(stderr, "%s\n", out);
						free(out); free(cp);
						return(NULL);
					}
					expt += iexp;
					if (iexp) { /* copy expansion */
						if (buf - buffer + strlen(out) > LINESIZE) {
							fputs("Line too long.\n", stderr);
							return(NULL);
						}
						sprintf(buf, "%s\n", out);
					}
					else {
						if (buf - buffer + strlen(cp) > LINESIZE) {
							fputs("Line too long.\n", stderr);
							return(NULL);
						}
						sprintf(buf, "%s\n", cp);
					}
					free(out);
				}
				else {  /* no expansion */
					if (buf - buffer + strlen(cp) > LINESIZE) {
						fputs("Line too long.\n", stderr);
						return(NULL);
					}
					sprintf(buf, "%s\n", cp);
				}
				free(cp);
			}
			else {
				*eof = -2;
				fputc('\n', stderr);
				return(NULL);
			}
			continued = 1;
		}  while ((cc = contline(buffer)) >= 0);
		if (Ft_Expandhist && expt) { /* echo expansion */
		   	fputs(buffer, stderr);
		}
		return(buffer);
	}

	*eof = 0;
	switch(Io[Iolevel].type) {
		case AFILE:
			do {
				buf = buffer + cc;
				if (fgets(buf, LINESIZE - (buf-buffer),
				Io[Iolevel].u.fp) == NULL) {
					if (Io[Iolevel].iflvl != Ft_iflevel()) {
						fprintf(stderr,
						"Error: %s: Eof occurred with unmatched 'if'.\n",
						Io[Iolevel].name);
						Ft_catcher(ERRR);
					}
					*eof = 1;
					Ft_popio();
					return(NULL);
				}
				Io[Iolevel].lino++;
			} while ((cc = contline(buffer)) >= 0);
			return(buffer);
		case AMACRO:
		case ANALIAS:
			if (brkline(&Io[Iolevel], buffer) == NULL) {
				if (Io[Iolevel].iflvl != Ft_iflevel()) {
					fprintf(stderr,
					"Error: %s: Eom occurred with unmatched 'if'.\n",
					Io[Iolevel].name);
					Ft_catcher(ERRR);
				}
				*eof = 1;
				Ft_popio();
				return(NULL);
			}
			Io[Iolevel].lino++;
			return(buffer);
		default:
			fputs("Impossible IO case.\n", stderr);
			return(NULL);
	}
}

int Ft_pushio(char *string, int type, char *name)
{
	FILE *fp = 0;

	if (Iolevel + 2 >= MAXLEVEL) {
		fputs("I/O stack overflow. Circular definition?\n", stderr);
		if (Ft_Interact) {
			fputs("Do you want to trace loop? [yn]", stderr);
			if (getchar() == 'y')
				reporterr();
			fflush(stdin);
		}
		return(ERRR);
	}
	switch(type) {
		case ANALIAS:
		case AMACRO:
			Iolevel++;
			strcpy(Io[Iolevel].line, string);
			strcpy(Io[Iolevel].name, name);
			Io[Iolevel].u.lp = Io[Iolevel].line;
			break;
		case AFILE:
			if (strcmp(string, "-") == 0) {
				fp = stdin;
			}
			else {
#ifdef EXTENSION
				char fname[TOKENSIZE+8];
				int len = strlen(string);

				strcpy(fname, string);
				if (len < 3 || strcmp(fname + len - 3, EXTENSION)) {
					strcpy(fname + len, EXTENSION);
				}
				if ((fp = fopen(fname, "r")) == NULL) {
					fname[len] = '\0';
					if ((fp = fopen(fname, "r")) == NULL) {
						fprintf(stderr, "load: %s: No such file.\n", fname);
						reporterr();
						return(ERRR);
					}
				}
#else
				if ((fp = fopen(string, "r")) == NULL) {
					fprintf(stderr, "load: %s: No such file.\n", string);
					reporterr();
					return(ERRR);
				}
#endif
			}
			Ft_push_cwd();
			Iolevel++;
			Filelevel++;
			Io[Iolevel].u.fp = fp;
			strcpy(Io[Iolevel].name, string);
			break;
		default:
			fputs("Impossible IO case.\n", stderr);
			return(ERRR);
	}
	Io[Iolevel].lino = 0;
	Io[Iolevel].iflvl = Ft_iflevel();
	Io[Iolevel].type = type;
	return(0);
}

int Ft_popio(void)
{
	if (Ft_Interact && !Iolevel) {
		fputs("Trying to close stdin!\n", stderr);
		Ft_catcher(ERRR);
	}
	if (!Ft_Interact && Iolevel <= 1)
		Ft_exit(0);  /* stack is empty -> exit  */
	switch(Io[Iolevel].type) {
		case AFILE:
			if (Io[Iolevel].u.fp != stdin) {
				fclose(Io[Iolevel].u.fp);
			}
			Iolevel--;
			Filelevel--;
			Ft_pop_cwd();
			break;
		case ANALIAS:
		case AMACRO:
			Iolevel--;
			break;
		default:
			fputs("Impossible IO case.\n", stderr);
			return(ERRR);
	}
	return(0);
}

static int clearpop(void)
{
	while (Iolevel)
		Ft_popio();
	return(0);
}

static FILE *curio(void)
{
	if (Io[Iolevel].type == AFILE) {
		return(Io[Iolevel].u.fp);
	}
	else {
		return(NULL);
	}
}

/* read a while or foreach loop  */
char *Ft_read_loop(char **margv, char *fprom)
{
	static char line[MAXMACRO];
	char prompt[128];
	char *cp, *ce, *cl;
	int size = 0;
	int osize = 0;
	int prompr;
	int dolevel = 1;
	int i;
	int margc;
	int cmode = 0;
	extern int Ft_Interact;

	prompr = Ft_Interact && !Iolevel;   /* Do we build a prompt ? */
	if (prompr) {
		sprintf(prompt, "%s? ", fprom);
	}
	else {
		prompt[0] = '\0';
	}
	for (;;) {
		if ((cp = Ft_nextline(prompt, &i)) == (char *)NULL) {
			if (i)
				break;
			if (Ft_Interact && !Iolevel && !i) {
				fputs("Line ignored, continue...\n", stderr);
				continue;
			}
		}
		/* prepare tokens */
		if ((margc = Ft_vgetargp(cp, margv, PARENTH, &cl)) <= 0)
			continue;
		if (margc == 1 && Ft_almost(margv[0], "cm!ode")) {
			if (cmode) {
				fputs("Error: Double cmode call in loop.\n", stderr);
				return(NULL);
			}
			cmode = 1;
		}
		else if (Ft_almost(margv[0], "fm!ode")) {
			if (!cmode) {
				fputs("Warning: Redundant fmode call in loop.\n", stderr);
			}
			cmode = 0;
		}
		else if (!cmode &&
		(Ft_almost(margv[0], "wh!ile ") || Ft_almost(margv[0], "fore!ach "))) {
			dolevel++;
			if (prompr) {  /* build a prompt */
				i = dolevel;
				ce = prompt + strlen(fprom);
				while (i) {
					*ce = '?';
					ce++; i--;
				}
				*ce++ = ' ';
				*ce = '\0';
			}
		}
		else if (Ft_almost(margv[0], "end")) {
			if (margc != 1)
				fputs("Warning: Ignoring tokens following `end'.\n", stderr);
			if (cmode) {
				fputs("Error: `end' statement while in cmode.\n", stderr);
				return(NULL);
			}
			dolevel--;
			if (!dolevel) {
				line[size] = '\0';
				return(line);
			}
			if (prompr) {
				i = dolevel;
				ce = prompt + strlen(fprom);
				while (i) {
					*ce = '?';
					ce++; i--;
				}
				*ce = ' ';
				*ce = '\0';
			}
		}
		size += strlen(cl);
		if (size > MAXMACRO) {
			fputs("Sorry, loop statements too large.\n", stderr);
			return(NULL);
		}
		sprintf(&line[osize], "%s", cl);
		osize = size;
	}
	if (cmode)
		fprintf(stderr, "%s: Eof while still in cmode.\n", fprom);
	else
		fprintf(stderr, "%s: Eof occurred before `end' of loop.\n", fprom);
	return(NULL);
}

/* read a macro  */
char *Ft_readmacro(char *prompt)
{
	static char line[MAXMACRO];
	char *cp, *cb, *ce;
	int size = 0;
	int osize = 0;
	int eof;

	if (Io[Iolevel].type == AMACRO) {
		fputs("Cannot have imbedded definitions.\n", stderr);
		return(NULL);
	}
	for (;;) {
		if ((cp = Ft_nextline(prompt, &eof)) == (char *)NULL) {
			if (eof)
				break;
			if (Ft_Interact && !Iolevel) {
				fputs("Line ignored, continue...\n", stderr);
			}
			continue;
		}
		cb = cp;
		while (isspace(*cb)) cb++;
		if (Ft_almost(cb, "st!op")) {
			line[size] = '\0';
			return(line);
		}
		ce = cb;
		while (*ce != Ft_Comchar && *ce != '\n' && *ce != '\0')
			ce++;
		if (cb == ce)
			continue;
		if (*ce == Ft_Comchar) { /* get rid of it */
			*ce++ = '\n';
			*ce = '\0';
		}
		size += strlen(cb) + 1;
		if (size > MAXMACRO) {
			fputs("Sorry, too big a macro.\n", stderr);
			return(NULL);
		}
		line[osize] = '\t';
		sprintf(&line[osize+1], "%s", cb);
		osize = size;
	}
	fputs("Eof occurred before 'stop' of macro.\n", stderr);
	return(NULL);
}

static int reporterr(void)
{
	int level;

	if (Ft_Interact && !Iolevel)
		return(0);

	fputs("Error trace:\n", stderr);
	for (level = 1; level <= Iolevel;level++) {
		switch (Io[level].type) {
		case ANALIAS:
			fprintf(stderr, "\tAlias \"%s\"\n", Io[level].name);
			break;
		case AMACRO:
			fprintf(stderr,
			"\tMacro \"%s\", line %d;\n", Io[level].name, Io[level].lino);
			break;
		case AFILE:
			fprintf(stderr,
			"\tFile \"%s\", line %d;\n", Io[level].name, Io[level].lino);
			break;
		}
	}
	clearpop();
	Ft_clearpop_cwd();
	Ft_clearpop_if();
	return(0);
}

int Ft_filelevel(void)
{
	return(Filelevel);
}

int Ft_iolevel(void)
{
	return(Iolevel);
}

char *Ft_expandedline(char *prompt, int type, int *eof)
{
	int narg;
	char *in, *out;
	extern char **argv;

	*eof = 0;
	if ((in = Ft_nextline(prompt, eof)) == NULL) {
		return(NULL);
	}
	narg = Ft_vgetargp(in, argv, type, &out);
	if (narg > 0) {
		if (!Iolevel && Ft_Interact)
			add_hist(in);
		return(out);
	}
	if (narg == VERRR && !Iolevel && Ft_Interact)
		add_hist(in);
	return(NULL);
}

static void reaper(void)
{
#ifdef WAIT3_INT
	int status;
#else
	union wait status;
#endif

	while (wait3(&status, WNOHANG, 0) > 0) {
		;
	}
	return;
}

SIGHANDLER Ft_catcher(int sig)
{
	extern int Ft_Dolevel, Ft_Inbrace, Ft_Inauto, Ft_Indef, Ft_Inproto;
	extern int Working;
	extern int Ft_Interact;
	extern void Ft_resetindex(void);
	extern FILE *Ft_Outprint;

	switch (sig) {
	case SIGCHLD:
		reaper();
#ifdef RESTART_SIGHANDLER
		signal(SIGCHLD, Ft_catcher);
#endif
#ifdef VOID_SIGHANDLER
		return;
#else
		return(0);
#endif
		break;
	case SIGPIPE:
		fputs("Warning: Broken pipe signal received.\n", stderr);
#ifdef RESTART_SIGHANDLER
		signal(SIGCHLD, Ft_catcher);
#endif
#ifdef VOID_SIGHANDLER
		return;
#else
		return(0);
#endif
		break;
	case SIGINT:
#ifdef RESTART_SIGHANDLER
		signal(SIGINT, Ft_catcher);
#endif   /* restart */
		if (Ft_Interact) {
			if (Working == YES) {  /* In interactive mode */
				fputs("\nAborting on request.\n", stderr);
				Ft_clearpop_cwd();
			}
			else
				fputs("Interupt.\n", stderr);
		}
		else if (!Ft_Interact) { /* In batch mode */
			fputs("\nExiting on request.\n", stderr);
			Ft_exit(1);
		}
		break;
	case SIGFPE:
		fputs("\nFloating point exception.\n", stderr);
#ifdef RESTART_SIGHANDLER
		signal(SIGFPE, Ft_catcher);
#endif   /* restart */
		if (!Ft_Interact) {
			Ft_exit(1);
		}
		break;
	case ERRR:
		reporterr();
		if (!Ft_Interact) {
			fputs("\nFatal error, exiting...\n", stderr);
			Ft_exit(1);
		}
		break;
	case RESET:
		break;
	case SIGHUP:
		fputs("\nHangup signal received... quitting...\n", stderr);
		Ft_exit(1);
	case SIGQUIT:
		fputs("\nQuit signal received... quitting...\n", stderr);
		Ft_exit(3);
	case SIGSEGV:
		fputs("\nSegmentation violation signal received.\n", stderr);
		Ft_exit(2);
#ifdef SIGBUS
	case SIGBUS:
		fputs("\nBus error signal received.\n", stderr);
		Ft_exit(2);
#endif
	case SIGILL:
		fputs("\nIllegal instruction signal received.\n", stderr);
		Ft_exit(2);
#ifdef SIGTSTP /* VMS does not have this function */
	case SIGTSTP:
		fputs("\nStop signal received.\n", stderr);
		fputs("Use 'fg' to call in foreground.\n", stderr);
		kill(0, SIGSTOP);
#endif
#ifdef VOID_SIGHANDLER
		return;
#else
		return(0);
#endif
		break;
	default:
		fprintf(stderr, "Unknown signal %d received.\n", sig);
		Ft_exit(1);
	}
	reaper();
	/* reset check variable */
	Ft_Dolevel = Ft_Indef = Ft_Inbrace = Ft_Inproto = Ft_Inauto = 0;
	Ft_resetindex();
	Ft_cleanframe();
	Ft_autosymremove(0);
	clearpop();
	Ft_clearpop_if();
	if (Ft_funcprocnotdef())
		Ft_cleansym();
	fflush(Ft_Outprint);
	longjmp(Ft_Jump, 1);
#ifdef VOID_SIGHANDLER
	return;
#else
	return(0);
#endif
}

static int add_hist(char *line)
{
	line[strlen(line)-1] = '\0';
	add_history(line);
	return(0);
}

static int contline(char *line)
{
	int len;

	len = strlen(line) - 2;
	if (len < 0)
		return(-1);
	if (line[len] == '\\' && line[len+1] == '\n') {
		return(len);
	}
	return(-1);
}

#include "symbol.h"
#include "code.h"
#ifdef VMS
#include "math_tab.h"
#else
#include "math.tab.h"
#endif

#define MAX(u, v)  ((u>v)? u: v)
#define BREAKLOOP	1
#define CONTLOOP 	2

static FILE *Readfp;
static SIGHANDLER closepipe(int sig);

int Ft_readvar(char **argp, Symbol **sym, int *loc, int (*irange)[32], double (*range)[32], int *lines, int num, int exec, char *comname)
{
	register int i;
	char buffer[LINESIZE];
	int argn;
	int max = 0;
	int breakcond;
	int line;
	int nerr = 0;
	int actline;
	int file = 1;
	extern int Ft_Interact;
	extern double *Ft_Data;
	extern FILE *popen(const char *, const char *);

	for (i=0;i< num;i++) {
		max = MAX(max, loc[i]);  /* store maximum number  */
		--loc[i];  /* convert number to index */
		if (loc[i] < 0) {
			fprintf(stderr, "%s: %d: Invalid column number.\n",
			comname, loc[i]+1);
			fputs("First column is 1!\n", stderr);
			return(ERRR);
		}
	}
	if (exec) {
		errno = 0;
		file = 0;
		signal(SIGPIPE, closepipe);
		if ((Readfp = popen(argp[1], "r")) == (FILE *)NULL) {
			fprintf(stderr, "%s: %s: Program not found.\n",
			comname, argp[1]);
			signal(SIGPIPE, Ft_catcher);
			return(ERRR);
		}
		sprintf(Ft_ReadFile, "%s", argp[1]);
	}
	else {
		file = 1;
		if (strcmp(argp[1], "-") == 0) {
			if ((Readfp = curio()) == NULL) {
				fprintf(stderr, "%s: Current input is not a file.\n", comname);
				return(ERRR);
			}
			sprintf(Ft_ReadFile, "stdin");
			file = 0;
		}
		else if ((Readfp = fopen(argp[1], "r")) == 0) {
			fprintf(stderr, "%s: %s: File not found.\n", comname, argp[1]);
			return(ERRR);
		}
		else {
			sprintf(Ft_ReadFile, "%s", argp[1]);
		}
	}

	line = 1;   /* one ahead  */
	actline = 0;
	while (fgets(buffer, LINESIZE, Readfp) != (char *)NULL) {
		actline++;
		if (actline < lines[0])
			continue;
		if ((actline - lines[0])%lines[2])
			continue;
		if (actline > lines[1])
			break;
		if ((argn = Ft_vgetargp(buffer, argp, NOTHING, 0)) <= 0) {
			if (Ft_Debug & DEBUG_READ) {
				fprintf(stderr,
				"Warning: %s: File \"%s\": line %d ignored.\n",
				comname, Ft_ReadFile, actline);
			}
			else if (argn == ERRR) {
				fprintf(stderr,
				"Warning: %s: File \"%s\": line %d ignored.\n",
				comname, Ft_ReadFile, actline);
			}
			continue;
		}
		if (strcmp(argp[0], "end") == 0) {
			break;
		}
		if (argn < max) {
			fprintf(stderr,
		   "Warning: %s: File \"%s\": line %d ignored: Less than %d columns.\n",
			comname, Ft_ReadFile, actline, max);
			if (nerr++ > MAXERR) {
				fprintf(stderr,
				"%s: File \"%s\": Too many errors returning...\n",
				comname, Ft_ReadFile);
				if (file) fclose(Readfp);
				if (exec) {
					fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
				}
				return(ERRR);
			}
			continue;
		}
		breakcond = 0;
#define isnumb(c)  (((c) >= '0' && (c) <= '9')	|| (c) == '-' || (c) == '+' || (c) == '.')
		for (i=0;i<num;i++) {
			if (!isnumb(argp[loc[i]][0])) { /*  check for NaN ... */
				fprintf(stderr,
				"%s: File \"%s\" line %d: Column %d is \"%s\".\n",
				comname, Ft_ReadFile, actline, loc[i]+1, argp[loc[i]]);
				if (file) fclose(Readfp);
				if (exec) {
					fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
				}
				return(ERRR);
			}
			if (sscanf(argp[loc[i]], "%lf", &sym[i]->u.vec[line]) != 1) {
				fprintf(stderr,
				"%s: File \"%s\" line %d: Column %d unreadable.\n",
				comname, Ft_ReadFile, actline, loc[i]+1);
				if (file) fclose(Readfp);
				if (exec) {
					fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
				}
				return(ERRR);
			}
			if (irange[0][i] && sym[i]->u.vec[line] < range[0][i]) {
				if (irange[0][i] == 2)
					breakcond = BREAKLOOP;
				else
					breakcond = CONTLOOP;
				break;
			}
			if (irange[1][i] && sym[i]->u.vec[line] > range[1][i]) {
				if (irange[1][i] == 2)
					breakcond = BREAKLOOP;
				else
					breakcond = CONTLOOP;
				break;
			}
		}
		if (breakcond) {
			if (breakcond == CONTLOOP) {
				breakcond = 0;
				continue;
			}
			else if (breakcond == BREAKLOOP) {
				break;
			}
			/* What the heck is going on ? */
			fprintf(stderr, "ERROR: Impossible condition in readvar.\n");
			Ft_catcher(ERRR);
		}
		if(line++ == Ft_Samples) {
			fprintf(stderr,
			"%s: File \"%s\" line %d: File too large.\n",
			comname, Ft_ReadFile, actline);
			fputs("Use `set samples' to enlarge capacity.\n", stderr);
			if (file) fclose(Readfp);
			if (exec) {
				fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
			}
			return(ERRR);
		}
	}
	if (file) fclose(Readfp);
	if (exec) {
		fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
	}

	*Ft_Data = (double) (line - 1);
	for (i=0;i<num;i++) {
		sym[i]->type = VEC;
	}
	if (Ft_Interact && !Iolevel)
		fprintf(stderr, "Read %d data points from %d lines.\n",
		(int) *Ft_Data, actline);
	return(0);
}

static SIGHANDLER closepipe(int sig)
{
		fflush(Readfp); pclose(Readfp); signal(SIGPIPE, Ft_catcher);
		Ft_catcher(RESET);
#ifdef VOID_SIGHANDLER
		return;
#else
		return(0);
#endif

}
