#include <stdio.h>
#include "both.h"

int     new = 1;
int     lineno = 0;		/* current line number */
char    line[512] = {
    0
};
char    lastline[512];		/* keep previous line for error prints */
char   *linep = line;
int     fd = 0;
int     fd_stack[10],
        fd_depth = 0;
int     line_num_stack[10];
char   *f_name_stack[10] = { "stdin" };
int     within_ms = 0;

file_open (s) char *s;
{
    int     f = open (s, 0);
    if (f < 0) {
/*	  fprintf( stderr, "Can't open file %s\n", s ); */
    }
    else {
/*	  fprintf( stderr, "Opened file %s fd %d depth %d\n",
	    s, f, fd_depth+1 ); */
	fd_stack[fd_depth++] = fd;
	f_name_stack[fd_depth] = s;
	line_num_stack[fd_depth] = 0;
	fd = f;
    }
    linep = line;
    *line = 0;
    return f;
}

file_close () {
    if (fd == 0 || close (fd) < 0) {
	fprintf (stderr, "Can't close fd %d\n", fd);
    }
    else {
	fd = fd_stack[--fd_depth];
/*	  fprintf( stderr, "Closed file new fd %d depth %d\n", fd, fd_depth );
*/
    }
    linep = line;
    *line = 0;
}

getline () {
    char    c = 0;
    char    eol;
    int     n = 1;
/* save last line if not blank */
    if (*(line + 1))
	strcpy (lastline, line);
/* read, skip lines starting # */
    do {
	lineno++;
	line_num_stack[fd_depth]++;
	linep = line;
/* read on if line ends with escape */
	do {
	    if (fd == 0) {
		while ((c = getchar ()) > 0 && c != '\n') {
		    *linep++ = c;
		}
		n = c > 0;
	    }
	    else {		/* fd != 0 */
		while ((n = read (fd, &c, 1)) > 0 && c != '\n')
		    *linep++ = c;
	    }
	    if (linep > line)
		eol = *(linep - 1);/* line ending with backslash */
	    else
		eol = ' ';
	    if (eol == '\\')
		*(linep - 1) = ' ';
	} while (eol == '\\');
	if (c == '\n')
	    *linep++ = '\n';
	*linep = 0;
    } while (*line == '#');

/* remove from # to eol */
    linep = line;
    while (*linep) {
	if (*(linep + 1) == '#' && *linep != ESCAPE)
	    *(linep + 1) = 0;
	linep++;
    }
    linep = line;
    if (fd == 0 && n == 0) {
	within_ms = 0;
	*line = 0;
	return - 1;
    }
    if (fd != 0 && n == 0) {	/* EOF on file */
	file_close ();
	*line = 0;
	return - 1;
    }
    if (*line == '.') {		/* nroff line */
	if (strncmp (".MS", line, 3) == 0) {
	    within_ms = 1;
	}
	if (strncmp (".ME", line, 3) == 0) {
	    within_ms = 0;
	}
    }
    return 1;
}

putline () {
    char   *linep = line;
    while (putchar (*linep++) != '\n');
}

nextchar () {
    static char ch = ' ';
    if (new == 0) {
	new = 1;
	return ch;
    }
    while (*linep == 0) {
	if (getline () < 0)
	    return - 1;
    }
    return ch = *linep++;
}

nextvischar () {		/* next visible character */
    char    c;
    do {
	c = nextchar ();
    }
    while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
    return c;
}

backup () {
    if (linep > line)
	linep--;
    else
	new = 0;
}

visbackup () {
    char    c;
    do {
	c = *--linep;
    }
    while (
	    (c == ' ' || c == '\t' || c == '\n' || c == '\r')
	    && linep > line
	);
}

readint () {			/* read integer value and deliver it, skip
				   other symbols */
    int     val;
    int     neg = 1;
    int     decimal = -1;
    char    ch;
    while (((ch = nextchar ()) < '0' || ch > '9')
	    && ch != '.' && ch != '-')
	if (ch <= 0)
	    return 0;

    if (ch == '-') {
	neg = -1;
	ch = nextvischar ();
    }

    if (ch == '.') {
	decimal = 1;
	ch = nextchar ();
    }

    val = ch - '0';
    while (((ch = nextchar ()) >= '0' && ch <= '9')
	    || ch == '.')
	if (ch != '.') {
	    val = val * 10 + ch - '0';
	    if (decimal >= 0)
		decimal++;
	}
	else {
	    decimal = 0;
	}

    if (ch == 'i') {		/* inches */
	if (decimal < 0)
	    decimal = 0;
	ch = nextvischar ();
    }
    else
	if (decimal == 0) {
	    backup ();
	    decimal = -1;
	}

    switch (decimal) {
	case 0: 
	    val *= 100;
	    break;
	case 1: 
	    val *= 10;
	    break;
	default: 
	    break;
    }

    backup ();

    return val * neg;
}

int     no_of_errors = 0;

ioerror (s, c1, c2) char   *s;	/* print error message */
{
    char   *p = line;
    fprintf (stderr, "\n****** Error file \"%s\" line %d *******\n****** ",
	    f_name_stack[fd_depth], line_num_stack[fd_depth]);
    fprintf (stderr, s, c1, c2);
    fprintf (stderr, " ******\nlast line: %s", lastline);
    fprintf (stderr, "this line: %s", line);
    fprintf (stderr, "position : ");
    for (p = line + 1; p < linep; p++)
	fprintf (stderr, " ");
    fprintf (stderr, "^\n****** End error message\n");
    if (no_of_errors++ > 10) {
	fprintf (stderr, "abandon after 10 ioerrors\n");
	abandon (1);
    }
}

iowarn (s, c1, c2) char *s;	/* print warning message */
{
    char   *p = line;
    fprintf (stderr, "\n****** Warning file \"%s\" line %d *******\n****** ",
	    f_name_stack[fd_depth], line_num_stack[fd_depth]);
    fprintf (stderr, s, c1, c2);
    fprintf (stderr, " ******\nlast line: %s", lastline);
    fprintf (stderr, "this line: %s", line);
    fprintf (stderr, "position : ");
    for (p = line + 1; p < linep; p++)
	fprintf (stderr, " ");
    fprintf (stderr, "^\n****** End warning message\n");
}

nerrs () {			/* number of errors */
    return no_of_errors;
}

saveinput (s) char *s;
{
    strcpy (s, linep);
}

pushinput (s) char *s;
{
    int     ls = strlen (s), ll = strlen (linep);
    char   *p = linep + ll;
    while (p >= linep) {
	*(p + ls) = *p;
	p--;
    }
    p = linep;
    while (*s)
	*p++ = *s++;
}

abandon (n) {
    exit (n);
}
