/*	@(#)rio.c	2.1		*/
#include "r.h"
#define	BUFSIZE	512
char	ibuf[BUFSIZE];
char	*ip = ibuf;

char	type[] = {
	0,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,
	CRAP,	'\t',	'\n',	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,
	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,
	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,	CRAP,
	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,	DIG,
	DIG,	DIG,	':',	';',	'<',	'=',	'>',	'?',
	'@',	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	'[',	'\\',	']',	'^',	'_',
	'`',	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	LET,	LET,	LET,	LET,	LET,
	LET,	LET,	LET,	'{',	'|',	'}',	'~',	0,
};

gtok(s) char *s; {	/* get token into s */
	register c, t;
	register char *p;
	struct nlist *q;

	for(;;) {
		p = s;
		*p++ = c = getchr();
		switch(t = type[c]) {
		case 0:
			if (infptr > 0) {
				fclose(infile[infptr]);
				infptr--;
				continue;
			}
			if (svargc > 1) {
				svargc--;
				svargv++;
				if (infile[infptr] != stdin)
					fclose(infile[infptr]);
				if( (infile[infptr] = fopen(*svargv,"r")) == NULL )
					cant(*svargv);
				linect[infptr] = 0;
				curfile[infptr] = *svargv;
				continue;
			}
			return(EOF);	/* real eof */
		case ' ':
		case '\t':
			while ((c = getchr()) == ' ' || c == '\t')
				;	/* skip others */
			if (c == COMMENT || c == '_') {
				putbak(c);
				continue;
			}
			if (c != '\n') {
				putbak(c);
				*p = '\0';
				return(' ');
			} else {
				*s = '\n';
				*(s+1) = '\0';
				return(*s);
			}
		case '_':
			while ((c = getchr()) == ' ' || c == '\t')
				;
			if (c == COMMENT) {
				putbak(c);
				gtok(s);	/* recursive */
			}
			else if (c != '\n')
				putbak(c);
			continue;
		case LET:
		case DIG:
			while ((t=type[*p = getchr()]) == LET || t == DIG)
				p++;
			putbak(*p);
			*p = '\0';
			if ((q = lookup(s))->name != NULL && q->ydef == 0) {	/* found but not keyword */
				if (q->def != fcnloc) {	/* not "function" */
					pbstr(q->def);
					continue;
				}
				getfname();	/* recursive gtok */
			}
			for (p=s; *p; p++)
				if (*p>='A' && *p<='Z')
					*p += 'a' - 'A';
			for (p=s; *p; p++)
				if (*p < '0' || *p > '9')
					return(LET);
			return(DIG);
		case '[':
			*p = '\0';
			return('{');
		case ']':
			*p = '\0';
			return('}');
		case '$':
		case '\\':
			if ((*p = getchr()) == '(' || *p == ')') {
				putbak(*p=='(' ? '{' : '}');
				continue;
			}
			if (*p == '"' || *p == '\'')
				p++;
			else
				putbak(*p);
			*p = '\0';
			return('$');
		case COMMENT:
			comment[comptr++] = 'c';
			while ((comment[comptr++] = getchr()) != '\n')
				;
			flushcom();
			*s = '\n';
			*(s+1) = '\0';
			return(*s);
		case '"':
		case '\'':
			for (; (*p = getchr()) != c; p++) {
				if (*p == '\\')
					*++p = getchr();
				if (*p == '\n') {
					error("missing quote");
					putbak('\n');
					break;
				}
			}
			*p++ = c;
			*p = '\0';
			return(QUOTE);
		case '%':
			while ((*p = getchr()) != '\n')
				p++;
			putbak(*p);
			*p = '\0';
			return('%');
		case '>': case '<': case '=': case '!': case '^':
			return(peek(p, '='));
		case '&':
			return(peek(p, '&'));
		case '|':
			return(peek(p, '|'));
		case CRAP:
			continue;
		default:
			*p = '\0';
			return(*s);
		}
	}
}

gnbtok(s) char *s; {
	register c;
	while ((c = gtok(s)) == ' ' || c == '\t')
		;
	return(c);
}

getfname() {
	while (gtok(fcname) == ' ')
		;
	pbstr(fcname);
	putbak(' ');
}

peek(p, c1) char *p, c1; {
	register c;
	c = *(p-1);
	if ((*p = getchr()) == c1)
		p++;
	else
		putbak(*p);
	*p = '\0';
	return(c);
}

pbstr(str)
register char *str;
{
	register char *p;

	p = str;
	while (*p++);
	--p;
	if (ip >= &ibuf[BUFSIZE]) {
		error("pushback overflow");
		exit(1);
	}
	while (p > str)
		putbak(*--p);
}

getchr() {
	register c;

	if (ip > ibuf)
		return(*--ip);
	c = getc(infile[infptr]);
	if (c == '\n')
		linect[infptr]++;
	if (c == EOF)
		return(0);
	return(c);
}
