/* Copyright (c) 1979 Regents of the University of California */
/*
 * pi - Pascal interpreter code translator
 *
 * Charles Haley, Bill Joy UCB
 * Version 1.1 February 1978
 *
 *
 * pxp - Pascal execution profiler
 *
 * Bill Joy UCB
 * Version 1.1 February 1978
 */

#include "0.h"
#include "yy.h"

#ifdef PXP
int	yytokcnt;
#endif

/*
 * Readch returns the next
 * character from the current
 * input line or -1 on end-of-file.
 * It also maintains yycol for use in
 * printing error messages.
 */
readch()
{
	register i, c;

	if (*bufp == '\n' && bufp >= charbuf) {
#ifdef PXP
		yytokcnt = 0;
#endif
		if (getline() < 0)
			return (-1);
	}
	c = *++bufp;
	if (c == '\t')
		yycol = ((yycol + 8) & ~7);
	else
		yycol++;
	return (c);
}

/*
 * Definitions of the structures used for the
 * include facility.  The variable "ibp" points
 * to the getc buffer of the current input file.
 * There are "inclev + 1" current include files,
 * and information in saved in the incs stack
 * whenever a new level of include nesting occurs.
 *
 * Ibp in the incs structure saves the pointer
 * to the previous levels input buffer;
 * filename saves the previous file name;
 * Printed saves whether the previous file name
 * had been printed before this nesting occurred;
 * and yyline is the line we were on on the previous file.
 */

#define	MAXINC	10

struct inc {
	FILE	*ibp;
	char	*filename;
	int	Printed;
	int	yyline;
	int	yyLinpt;
} incs[MAXINC];

extern	char printed;

int	inclev	= -1;

#ifdef PXP
/*
 * These initializations survive only if
 * pxp is asked to pretty print one file.
 * Otherwise they are destroyed by the initial
 * call to getline.
 */
char	charbuf[CBSIZE]	= " program x(output);\n";
int	yycol = 8;
char	*bufp = charbuf;

#endif
/*
 * YyLinpt is the seek pointer to the beginning of the
 * next line in the file.
 */
int	yyLinpt;

/*
 * Getline places the next line
 * from the input stream in the
 * line buffer, returning -1 at YEOF.
 */
getline()
{
	register char *cp;
	register CHAR c;
#ifdef PXP
	static char ateof;
#endif
	register FILE *ib;
	int i;

	if (opt('l') && yyprtd == 0)
		yyoutline();
	yyprtd = 0;
top:
	yylinpt = yyLinpt;
	yyline++;
	yyseqid++;
	cp = charbuf;
	ib = ibp;
	i = sizeof charbuf - 1;
	for (;;) {
		c = getc(ib);
		if (c == EOF) {
			if (uninclud())
				goto top;
#ifdef PXP
			if (ateof == 0 && bracket) {
				strcpy(charbuf, "begin end.\n");
				ateof = 1;
				goto out;
			}
#endif
			bufp = "\n";
			yyline--;
			yyseqid--;
			yyprtd = 1;
			return (-1);
		}
		*cp++ = c;
		if (c == '\n')
			break;
		if (--i == 0) {
			line = yyline;
			error("Input line too long - QUIT");
			pexit(DIED);
		}
	}
	*cp = 0;
	yyLinpt = yylinpt + cp - charbuf;
	if (includ())
		goto top;
#ifdef PXP
	if (cp == &charbuf[1])
		commnl();
	else if (cp == &charbuf[2])
		switch (charbuf[0]) {
			case ' ':
				commnlbl();
				break;
			case '\f':
				commform();
		}
#endif
	if (opt('u'))
		setuflg();
out:
	bufp = charbuf - 1;
	yycol = 8;
	return (1);
}

/*
 * Check an input line to see if it is a "#include" pseudo-statement.
 * We allow arbitrary blanks in the line and the file name
 * may be delimited by either 's or "s.  A single semicolon
 * may be placed after the name, but nothing else is allowed
 */
includ()
{
	register char *cp, *dp;
	char ch;
	register struct inc *ip;

	cp = charbuf;
	if (*cp++ != '#')
		return (0);
	cp = skipbl(cp);
	for (dp = "include"; *dp; dp++)
		if (*dp != *cp++)
			return (0);
	line = yyline;
	cp = skipbl(cp);
	ch = *cp++;
	if (ch != '\'' && ch != '"') {
		/*
		 * This should be a yerror flagging the place
		 * but its not worth figuring out the column.
		 */
		line = yyline;
		error("Include syntax error - expected ' or \" not found - QUIT");
		pexit(DIED);
	}
	for (dp = cp; *dp != ch; dp++)
		if (*dp == 0) {
			line = yyline;
			error("Missing closing %c for include file name - QUIT", ch);
			pexit(DIED);
		}
	*dp++ = 0;
/*
	if (*dp == ';')
		dp++;
	dp = skipbl(dp);
	if (*dp != '\n') {
		line = yyline;
		error("Garbage after filename in include");
		pexit(DIED);
	}
*/
	if (!dotted(cp, 'i')) {
		line = yyline;
		error("Include filename must end in .i");
	}
#ifdef PXP
	commincl(cp, ch);
	if (noinclude)
		return (1);
#endif
	inclev++;
	if (inclev > MAXINC) {
		line = yyline;
		error("Absurdly deep include nesting - QUIT");
		pexit(DIED);
	}
	ip = &incs[inclev];
	ip->filename = filename;
	filename = savestr(cp);
/*
 *	left over from before stdio
 *
 *	cp = malloc(518);
 *	if (cp == -1) {
 *		error("Ran out of memory (include)");
 *		pexit(DIED);
 *	}
 *
 */
	ip->ibp = ibp;
	if ( ( ibp = fopen(filename, "r" ) ) == NULL ) {
		perror(filename);
		pexit(DIED);
	}
	if (inpflist(filename)) {
#ifdef PI
		opush('l');
#endif
#ifdef PXP
		opush('z');
#endif
	}
	ip->Printed = printed;
	printed = 0;
	ip->yyline = yyline;
	yyline = 0;
	ip->yyLinpt = yyLinpt;
	yyLinpt = 0;
/*
 *	left over from before stdio
 *
 *	ip->ibp = ibp;
 *	ibp = cp;
 *
 */
	return (1);
}

skipbl(ocp)
	char *ocp;
{
	register char *cp;

	cp = ocp;
	while (*cp == ' ' || *cp == '\t')
		cp++;
	return (cp);
}


/*
 * At the end of an include,
 * close the file, free the input buffer,
 * and restore the environment before
 * the "push", including the value of
 * the z option for pxp and the l option for pi.
 */
uninclud()
{
	register struct inc *ip;

	if (inclev < 0)
		return (0);
/*
 *	left over from before stdio: becomes fclose ( ibp )
 *
 *	close(ibp[0]);
 *	free(ibp);
 *
 */
	fclose ( ibp );
	ip = &incs[inclev];
	ibp = ip->ibp;
	yyline = ip->yyline;
	if (inpflist(filename)) {
#ifdef PI
		opop('l');
#endif
#ifdef PXP
		opop('z');
#endif
	}
	filename = ip->filename;
	yyLinpt = ip->yyLinpt;
	/*
	 * If we printed out the nested name,
	 * then we should print all covered names again.
	 * If we didn't print out the nested name
	 * we print the uncovered name only if it
	 * has not been printed before (unstack).
	 */
	if (printed) {
		printed = 0;
		while (ip >= incs) {
			ip->Printed = 0;
			ip--;
		}
	} else
		printed = ip->Printed;
	inclev--;
	return (1);
}
