1 #ifndef lint
2 static char sccsid[] = "@(#)input.c	2.2 (CWI) 87/04/01";
3 #endif lint
4 #include <stdio.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include "e.h"
8 #include "y.tab.h"
9 
10 Infile	infile[10];
11 Infile	*curfile = infile;
12 
13 #define	MAXSRC	50
14 Src	src[MAXSRC];	/* input source stack */
15 Src	*srcp	= src;
16 
17 pushsrc(type, ptr)	/* new input source */
18 	int type;
19 	char *ptr;
20 {
21 	if (++srcp >= src + MAXSRC)
22 		fatal("inputs nested too deep");
23 	srcp->type = type;
24 	srcp->sp = ptr;
25 	if (dbg > 1) {
26 		printf("\n%3d ", srcp - src);
27 		switch (srcp->type) {
28 		case File:
29 			printf("push file %s\n", ((Infile *)ptr)->fname);
30 			break;
31 		case Macro:
32 			printf("push macro <%s>\n", ptr);
33 			break;
34 		case Char:
35 			printf("push char <%c>\n", *ptr);
36 			break;
37 		case String:
38 			printf("push string <%s>\n", ptr);
39 			break;
40 		case Free:
41 			printf("push free <%s>\n", ptr);
42 			break;
43 		default:
44 			fatal("pushed bad type %d\n", srcp->type);
45 		}
46 	}
47 }
48 
49 popsrc()	/* restore an old one */
50 {
51 	if (srcp <= src)
52 		fatal("too many inputs popped");
53 	if (dbg > 1) {
54 		printf("%3d ", srcp - src);
55 		switch (srcp->type) {
56 		case File:
57 			printf("pop file\n");
58 			break;
59 		case Macro:
60 			printf("pop macro\n");
61 			break;
62 		case Char:
63 			printf("pop char <%c>\n", *srcp->sp);
64 			break;
65 		case String:
66 			printf("pop string\n");
67 			break;
68 		case Free:
69 			printf("pop free\n");
70 			break;
71 		default:
72 			fatal("pop weird input %d\n", srcp->type);
73 		}
74 	}
75 	srcp--;
76 }
77 
78 Arg	args[10];	/* argument frames */
79 Arg	*argfp = args;	/* frame pointer */
80 int	argcnt;		/* number of arguments seen so far */
81 
82 dodef(stp)	/* collect args and switch input to defn */
83 	tbl *stp;
84 {
85 	int i, len;
86 	char *p;
87 	Arg *ap;
88 
89 	ap = argfp+1;
90 	if (ap >= args+10)
91 		fatal("arguments too deep");
92 	argcnt = 0;
93 	if (input() != '(')
94 		fatal("disaster in dodef\n");
95 	if (ap->argval == 0)
96 		ap->argval = malloc(1000);
97 	for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
98 		ap->argstk[argcnt++] = p;
99 		if (input() == ')')
100 			break;
101 	}
102 	for (i = argcnt; i < MAXARGS; i++)
103 		ap->argstk[i] = "";
104 	if (dbg)
105 		for (i = 0; i < argcnt; i++)
106 			printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
107 	argfp = ap;
108 	pushsrc(Macro, stp->defn);
109 }
110 
111 getarg(p)	/* pick up single argument, store in p, return length */
112 	char *p;
113 {
114 	int n, c, npar;
115 
116 	n = npar = 0;
117 	for ( ;; ) {
118 		c = input();
119 		if (c == EOF)
120 			fatal("end of file in getarg!\n");
121 		if (npar == 0 && (c == ',' || c == ')'))
122 			break;
123 		if (c == '"')	/* copy quoted stuff intact */
124 			do {
125 				*p++ = c;
126 				n++;
127 			} while ((c = input()) != '"' && c != EOF);
128 		else if (c == '(')
129 			npar++;
130 		else if (c == ')')
131 			npar--;
132 		n++;
133 		*p++ = c;
134 	}
135 	*p = 0;
136 	unput(c);
137 	return(n + 1);
138 }
139 
140 #define	PBSIZE	2000
141 char	pbuf[PBSIZE];		/* pushback buffer */
142 char	*pb	= pbuf-1;	/* next pushed back character */
143 
144 char	ebuf[200];		/* collect input here for error reporting */
145 char	*ep	= ebuf;
146 
147 input()
148 {
149 	register int c;
150 
151   loop:
152 	switch (srcp->type) {
153 	case File:
154 		c = getc(curfile->fin);
155 		if (c == EOF) {
156 			if (curfile == infile)
157 				break;
158 			if (curfile->fin != stdin) {
159 				fclose(curfile->fin);
160 				free(curfile->fname);	/* assumes allocated */
161 			}
162 			curfile--;
163 			printf(".lf %d %s\n", curfile->lineno, curfile->fname);
164 			popsrc();
165 			goto loop;
166 		}
167 		if (c == '\n')
168 			curfile->lineno++;
169 		break;
170 	case Char:
171 		if (pb >= pbuf) {
172 			c = *pb--;
173 			popsrc();
174 			break;
175 		} else {	/* can't happen? */
176 			popsrc();
177 			goto loop;
178 		}
179 	case String:
180 		c = *srcp->sp++;
181 		if (c == '\0') {
182 			popsrc();
183 			goto loop;
184 		} else {
185 			if (*srcp->sp == '\0')	/* empty, so pop */
186 				popsrc();
187 			break;
188 		}
189 	case Macro:
190 		c = *srcp->sp++;
191 		if (c == '\0') {
192 			if (--argfp < args)
193 				fatal("argfp underflow");
194 			popsrc();
195 			goto loop;
196 		} else if (c == '$' && isdigit(*srcp->sp)) {
197 			int n = 0;
198 			while (isdigit(*srcp->sp))
199 				n = 10 * n + *srcp->sp++ - '0';
200 			if (n > 0 && n <= MAXARGS)
201 				pushsrc(String, argfp->argstk[n-1]);
202 			goto loop;
203 		}
204 		break;
205 	case Free:	/* free string */
206 		free(srcp->sp);
207 		popsrc();
208 		goto loop;
209 	}
210 	if (ep >= ebuf + sizeof ebuf)
211 		ep = ebuf;
212 	*ep++ = c;
213 	return c;
214 }
215 
216 
217 unput(c)
218 {
219 	if (++pb >= pbuf + sizeof pbuf)
220 		fatal("pushback overflow\n");
221 	if (--ep < ebuf)
222 		ep = ebuf + sizeof(ebuf) - 1;
223 	*pb = c;
224 	pushsrc(Char, pb);
225 	return c;
226 }
227 
228 pbstr(s)
229 	char *s;
230 {
231 	pushsrc(String, s);
232 }
233 
234 fatal(s, s1, s2, s3, s4)	/* should be a flag on error */
235 	char *s, *s1, *s2, *s3, *s4;
236 {
237 	error(FATAL, s, s1, s2, s3, s4);
238 }
239 
240 error(die, s, s1, s2, s3, s4)
241 	int die;
242 	char *s, *s1, *s2, *s3, *s4;
243 {
244 	extern char *cmdname, *sys_errlist[];
245 	extern int errno, sys_nerr;
246 
247 	if (synerr)
248 		return;
249 	fprintf(stderr, "%s: ", cmdname);
250 	fprintf(stderr, s, s1, s2, s3, s4);
251 	if (errno > 0 && errno < sys_nerr)
252 		fprintf(stderr, " (%s)", sys_errlist[errno]);
253 	if (curfile->fin)
254 		fprintf(stderr, " near line %d, file %s",
255 			curfile->lineno, curfile->fname);
256 	fprintf(stderr, "\n");
257 	eprint();
258 	synerr = 1;
259 	errno = 0;
260 	if (die) {
261 		if (dbg)
262 			abort();
263 		else
264 			exit(1);
265 	}
266 }
267 
268 yyerror() {;}
269 
270 eprint()	/* try to print context around error */
271 {
272 	char *p, *q;
273 	int c;
274 
275 	if (ep == ebuf)
276 		return;				/* no context */
277 	p = ep - 1;
278 	if (p > ebuf && *p == '\n')
279 		p--;
280 	for ( ; p >= ebuf && *p != '\n'; p--)
281 		;
282 	while (*p == '\n')
283 		p++;
284 	fprintf(stderr, " context is\n\t");
285 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
286 		;
287 	while (p < q)
288 		putc(*p++, stderr);
289 	fprintf(stderr, " >>> ");
290 	while (p < ep)
291 		putc(*p++, stderr);
292 	fprintf(stderr, " <<< ");
293 	while (pb >= pbuf)
294 		putc(*pb--, stderr);
295 	if (curfile->fin)
296 		fgets(ebuf, sizeof ebuf, curfile->fin);
297 	fprintf(stderr, "%s", ebuf);
298 	pbstr("\n.EN\n");	/* safety first */
299 	ep = ebuf;
300 }
301