#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#ifndef NOSTDLIB_H
#include <stdlib.h>
#endif
#ifndef NOUNISTD_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 hl_history_expand(char *, char **);
extern void hl_add_history(char *);
#ifdef AMIGA
char * rl_readline(char * msgt) {
	
	static char lbuf[512];
	printf("%s",msgt);
	gets(lbuf);
	
	return lbuf;
}
#else
extern char *rl_readline(char *);
#endif
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))) {
            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;
		char *promptr = prompt;

		fflush(stdout);
		fflush(stderr);
		if (Ft_iflevel())
			promptr = "if? ";
    	*eof = ERRR;
		do { /* read multiple lines */
			buf = buffer + cc;
        	if ((cp = rl_readline((buf == buffer? promptr: "? ")))) {
            	*eof = 0;
#ifdef AMIGA
            	if (0) {
                	int iexp;
                	iexp = 0;
#else
            	if (Ft_Expandhist) {
                	int iexp;
                	iexp = hl_history_expand(cp, &out);
#endif
                	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);
            	}
#ifndef AMIGA
            	free(cp);
#endif
        	}
        	else {
				*eof = -2;
				fputc('\n', stderr);
            	return(NULL);
        	}
		}  while ((cc = contline(buffer)));
        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)));
            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 = ce = cp;
        while (isspace(*cb)) cb++;
        if (Ft_almost(cb, "st!op")) {
            line[size] = '\0';
            return(line);
        }
        while (*ce != Ft_Comchar && *ce != '\n' && *ce != '\0')
            ce++;
        if (*ce == Ft_Comchar) { /* get rid of it */
            if (cb == ce)
                continue;
            *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);
}

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 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);
        if (!Ft_Interact) {
            Ft_exit(1);
        }
        break;
    case ERRR:
        reporterr();
        if (!Ft_Interact) {
            fputs("\nFatal error, exiting...\n", stderr);
            Ft_exit(1);
        }
        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);
    case SIGTSTP:
        fputs("\nStop signal received.\n", stderr);
        fputs("Use 'fg' to call in foreground.\n", stderr);
        kill(0, SIGSTOP);
#ifdef VOID_SIGHANDLER
		return;
#else
		return(0);
#endif
		break;
    default:
        fprintf(stderr, "Unknown signal %d received.\n", sig);
        Ft_exit(1);
    }
    /* 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)
{
#ifndef AMIGA
    line[strlen(line)-1] = '\0';
    hl_add_history(line);
#endif
    return(0);
}

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

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

#include "symbol.h"
#include "code.h"
#include "math.tab.h"

#define MAX(u, v)  ((u>v)? u: v)

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;
    FILE *fp;
    char buffer[LINESIZE];
    int argn;
    int max = 0;
    int cont;
    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, SIG_DFL);
        if ((fp = popen(argp[1], "r")) == (FILE *)NULL) {
            fprintf(stderr, "%s: %s: Program not found.\n",
			comname, argp[1]);
            return(ERRR);
        }
        sprintf(Ft_ReadFile, "%s", argp[1]);
    }
    else {
        file = 1;
        if (strcmp(argp[1], "-") == 0) {
            if ((fp = curio()) == NULL) {
            	fprintf(stderr, "%s: Current input is not a file.\n", comname);
				return(ERRR);
			}
            sprintf(Ft_ReadFile, "stdin");
            file = 0;
        }
        else if ((fp = 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, fp) != (char *)NULL) {
		actline++;
		if (actline < lines[0])
			continue;
        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(fp);
                if (exec) { fflush(fp); pclose(fp); }
                return(ERRR);
            }
            continue;
        }
        cont = 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(fp);
                if (exec) { fflush(fp); pclose(fp); }
                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(fp);
                if (exec) { fflush(fp); pclose(fp); }
                return(ERRR);
            }
            if (irange[0][i] && sym[i]->u.vec[line] < range[0][i]) {
                cont = 1;
                break;
            }
            if (irange[1][i] && sym[i]->u.vec[line] > range[1][i]) {
                cont = 1;
                break;
            }
        }
		if (actline >= lines[1])
			break;
        if (cont == 1)
			continue;
        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(fp);
            if (exec) { fflush(fp); pclose(fp); }
            return(ERRR);
        }
    }
    if (file) fclose(fp);
    if (exec) { fflush(fp); pclose(fp); }
    *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);
}

