1 #ifndef lint
2 static char sccsid[] = "@(#)input.c 3.1 (CWI) 85/07/30";
3 #endif lint
4
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #include "pic.h"
9 #include "y.tab.h"
10
11 Infile infile[10];
12 Infile *curfile = infile;
13
14 #define MAXSRC 50
15 Src src[MAXSRC]; /* input source stack */
16 Src *srcp = src;
17
pushsrc(type,ptr)18 pushsrc(type, ptr) /* new input source */
19 int type;
20 char *ptr;
21 {
22 if (++srcp >= src + MAXSRC)
23 fatal("inputs nested too deep");
24 srcp->type = type;
25 srcp->sp = ptr;
26 if (dbg > 1) {
27 printf("\n%3d ", srcp - src);
28 switch (srcp->type) {
29 case File:
30 printf("push file %s\n", ((Infile *)ptr)->fname);
31 break;
32 case Macro:
33 printf("push macro <%s>\n", ptr);
34 break;
35 case Char:
36 printf("push char <%c>\n", *ptr);
37 break;
38 case Thru:
39 printf("push thru\n");
40 break;
41 case String:
42 printf("push string <%s>\n", ptr);
43 break;
44 case Free:
45 printf("push free <%s>\n", ptr);
46 break;
47 default:
48 fatal("pushed bad type %d\n", srcp->type);
49 }
50 }
51 }
52
popsrc()53 popsrc() /* restore an old one */
54 {
55 if (srcp <= src)
56 fatal("too many inputs popped");
57 if (dbg > 1) {
58 printf("%3d ", srcp - src);
59 switch (srcp->type) {
60 case File:
61 printf("pop file\n");
62 break;
63 case Macro:
64 printf("pop macro\n");
65 break;
66 case Char:
67 printf("pop char <%c>\n", *srcp->sp);
68 break;
69 case Thru:
70 printf("pop thru\n");
71 break;
72 case String:
73 printf("pop string\n");
74 break;
75 case Free:
76 printf("pop free\n");
77 break;
78 default:
79 fatal("pop weird input %d\n", srcp->type);
80 }
81 }
82 srcp--;
83 }
84
definition(s)85 definition(s) /* collect definition for s and install */
86 char *s; /* definitions picked up lexically */
87 {
88 char *p;
89 struct symtab *stp;
90
91 p = delimstr("definition");
92 stp = lookup(s);
93 if (stp != NULL) { /* it's there before */
94 if (stp->s_type != DEFNAME) {
95 yyerror("%s used as variable and definition\n", s);
96 return;
97 }
98 free(stp->s_val.p);
99 stp->s_val.p = p;
100 } else {
101 YYSTYPE u;
102 u.p = p;
103 makevar(tostring(s), DEFNAME, u);
104 }
105 dprintf("installing %s as `%s'\n", s, p);
106 }
107
delimstr(s)108 char *delimstr(s) /* get body of X ... X */
109 char *s; /* message if too big */
110 {
111 int c, delim, rdelim, n, deep;
112 static char *buf = NULL;
113 static int nbuf = 0;
114 char *p;
115
116 if (buf == NULL)
117 buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
118 while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
119 ;
120 rdelim = baldelim(delim, "{}"); /* could be "(){}[]`'" */
121 deep = 1;
122 for (p = buf; ; ) {
123 c = input();
124 if (c == rdelim)
125 if (--deep == 0)
126 break;
127 if (c == delim)
128 deep++;
129 if (p >= buf + nbuf) {
130 n = p - buf;
131 buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
132 p = buf + n;
133 }
134 if (c == EOF)
135 fatal("end of file in %s %c %.20s... %c", s, delim, buf, delim);
136 *p++ = c;
137 }
138 *p = '\0';
139 dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
140 return tostring(buf);
141 }
142
baldelim(c,s)143 baldelim(c, s) /* replace c by balancing entry in s */
144 int c;
145 char *s;
146 {
147 for ( ; *s; s += 2)
148 if (*s == c)
149 return s[1];
150 return c;
151 }
152
undefine(s)153 undefine(s) /* undefine macro */
154 char *s;
155 {
156 while (*s != ' ' && *s != '\t') /* skip "undef..." */
157 s++;
158 while (*s == ' ' || *s == '\t')
159 s++;
160 freedef(s);
161 }
162
163
164 Arg args[10]; /* argument frames */
165 Arg *argfp = args; /* frame pointer */
166 int argcnt; /* number of arguments seen so far */
167
168 dodef(stp) /* collect args and switch input to defn */
169 struct symtab *stp;
170 {
171 int i, len;
172 char *p;
173 Arg *ap;
174
175 ap = argfp+1;
176 if (ap >= args+10)
177 fatal("arguments too deep");
178 argcnt = 0;
179 if (input() != '(')
180 fatal("disaster in dodef\n");
181 if (ap->argval == 0)
182 ap->argval = malloc(1000);
183 for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
184 ap->argstk[argcnt++] = p;
185 if (input() == ')')
186 break;
187 }
188 for (i = argcnt; i < MAXARGS; i++)
189 ap->argstk[i] = "";
190 if (dbg)
191 for (i = 0; i < argcnt; i++)
192 printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
193 argfp = ap;
194 pushsrc(Macro, stp->s_val.p);
195 }
196
getarg(p)197 getarg(p) /* pick up single argument, store in p, return length */
198 char *p;
199 {
200 int n, c, npar;
201
202 n = npar = 0;
203 for ( ;; ) {
204 c = input();
205 if (c == EOF)
206 fatal("end of file in getarg!\n");
207 if (npar == 0 && (c == ',' || c == ')'))
208 break;
209 if (c == '"') /* copy quoted stuff intact */
210 do {
211 *p++ = c;
212 n++;
213 } while ((c = input()) != '"' && c != EOF);
214 else if (c == '(')
215 npar++;
216 else if (c == ')')
217 npar--;
218 n++;
219 *p++ = c;
220 }
221 *p = 0;
222 unput(c);
223 return(n + 1);
224 }
225
226 #define PBSIZE 2000
227 char pbuf[PBSIZE]; /* pushback buffer */
228 char *pb = pbuf-1; /* next pushed back character */
229
230 char ebuf[200]; /* collect input here for error reporting */
231 char *ep = ebuf;
232
233 int begin = 0;
234 extern int thru;
235 extern struct symtab *thrudef;
236 extern char *untilstr;
237
input()238 input()
239 {
240 register int c;
241
242 if (thru && begin) {
243 do_thru();
244 begin = 0;
245 }
246 c = nextchar();
247 if (dbg > 1)
248 printf(" <%c>", c);
249 if (ep >= ebuf + sizeof ebuf)
250 ep = ebuf;
251 return *ep++ = c;
252 }
253
nextchar()254 nextchar()
255 {
256 register int c;
257
258 loop:
259 switch (srcp->type) {
260 case Free: /* free string */
261 free(srcp->sp);
262 popsrc();
263 goto loop;
264 case Thru: /* end of pushed back line */
265 begin = 1;
266 popsrc();
267 c = '\n';
268 break;
269 case Char:
270 if (pb >= pbuf) {
271 c = *pb--;
272 popsrc();
273 break;
274 } else { /* can't happen? */
275 popsrc();
276 goto loop;
277 }
278 case String:
279 c = *srcp->sp++;
280 if (c == '\0') {
281 popsrc();
282 goto loop;
283 } else {
284 if (*srcp->sp == '\0') /* empty, so pop */
285 popsrc();
286 break;
287 }
288 case Macro:
289 c = *srcp->sp++;
290 if (c == '\0') {
291 if (--argfp < args)
292 fatal("argfp underflow");
293 popsrc();
294 goto loop;
295 } else if (c == '$' && isdigit(*srcp->sp)) {
296 int n = 0;
297 while (isdigit(*srcp->sp))
298 n = 10 * n + *srcp->sp++ - '0';
299 if (n > 0 && n <= MAXARGS)
300 pushsrc(String, argfp->argstk[n-1]);
301 goto loop;
302 }
303 break;
304 case File:
305 c = getc(curfile->fin);
306 if (c == EOF) {
307 if (curfile == infile)
308 fatal("end of file inside .PS/.PE");
309 if (curfile->fin != stdin) {
310 fclose(curfile->fin);
311 free(curfile->fname); /* assumes allocated */
312 }
313 curfile--;
314 printf(".lf %d %s\n", curfile->lineno, curfile->fname);
315 popsrc();
316 thru = 0; /* chicken out */
317 thrudef = 0;
318 if (untilstr) {
319 free(untilstr);
320 untilstr = 0;
321 }
322 goto loop;
323 }
324 if (c == '\n')
325 curfile->lineno++;
326 break;
327 }
328 return c;
329 }
330
do_thru()331 do_thru() /* read one line, make into a macro expansion */
332 {
333 int c, i, n;
334 char *p;
335 Arg *ap;
336
337 ap = argfp+1;
338 if (ap >= args+10)
339 fatal("arguments too deep");
340 if (ap->argval == NULL)
341 ap->argval = malloc(1000);
342 p = ap->argval;
343 argcnt = 0;
344 c = nextchar();
345 if (thru == 0) { /* end of file was seen, so thru is done */
346 unput(c);
347 return;
348 }
349 for ( ; c != '\n' && c != EOF; ) {
350 if (c == ' ' || c == '\t') {
351 c = nextchar();
352 continue;
353 }
354 ap->argstk[argcnt++] = p;
355 if (c == '"') {
356 do {
357 *p++ = c;
358 if ((c = nextchar()) == '\\') {
359 *p++ = c;
360 *p++ = nextchar();
361 c = nextchar();
362 }
363 } while (c != '"' && c != '\n' && c != EOF);
364 *p++ = '"';
365 if (c == '"')
366 c = nextchar();
367 } else {
368 do {
369 *p++ = c;
370 } while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
371 if (c == ',')
372 c = nextchar();
373 }
374 *p++ = '\0';
375 }
376 if (c == EOF)
377 fatal("unexpected end of file in do_thru");
378 if (argcnt == 0) { /* ignore blank line */
379 pushsrc(Thru, (char *) 0);
380 return;
381 }
382 for (i = argcnt; i < MAXARGS; i++)
383 ap->argstk[i] = "";
384 if (dbg)
385 for (i = 0; i < argcnt; i++)
386 printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
387 if (strcmp(ap->argstk[0], ".PE") == 0) {
388 thru = 0;
389 thrudef = 0;
390 pushsrc(String, "\n.PE\n");
391 return;
392 }
393 if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
394 thru = 0;
395 thrudef = 0;
396 free(untilstr);
397 untilstr = 0;
398 return;
399 }
400 pushsrc(Thru, (char *) 0);
401 dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
402 argfp = ap;
403 pushsrc(Macro, thrudef->s_val.p);
404 }
405
unput(c)406 unput(c)
407 {
408 if (++pb >= pbuf + sizeof pbuf)
409 fatal("pushback overflow\n");
410 if (--ep < ebuf)
411 ep = ebuf + sizeof(ebuf) - 1;
412 *pb = c;
413 pushsrc(Char, pb);
414 return c;
415 }
416
pbstr(s)417 pbstr(s)
418 char *s;
419 {
420 int n;
421
422 pushsrc(String, s);
423 }
424
errcheck(x,s)425 double errcheck(x, s)
426 double x;
427 char *s;
428 {
429 extern int errno;
430
431 if (errno == EDOM) {
432 errno = 0;
433 yyerror("%s argument out of domain", s);
434 } else if (errno == ERANGE) {
435 errno = 0;
436 yyerror("%s result out of range", s);
437 }
438 return x;
439 }
440
fatal(s,s1,s2,s3,s4)441 fatal(s, s1, s2, s3, s4) /* should be a flag on yyerror */
442 char *s, *s1, *s2, *s3, *s4;
443 {
444 yyerror(s, s1, s2, s3, s4);
445 if (dbg)
446 abort();
447 else
448 exit(1);
449 }
450
yyerror(s,s1,s2,s3,s4)451 yyerror(s, s1, s2, s3, s4)
452 char *s, *s1, *s2, *s3, *s4;
453 {
454 extern char *cmdname, *sys_errlist[];
455 extern int errno, sys_nerr;
456
457 if (synerr)
458 return;
459 fprintf(stderr, "%s: ", cmdname);
460 fprintf(stderr, s, s1, s2, s3, s4);
461 if (errno > 0 && errno < sys_nerr)
462 fprintf(stderr, " (%s)", sys_errlist[errno]);
463 fprintf(stderr, " near line %d, file %s\n",
464 curfile->lineno, curfile->fname);
465 eprint();
466 synerr = 1;
467 errno = 0;
468 }
469
eprint()470 eprint() /* try to print context around error */
471 {
472 char *p, *q;
473 int c;
474
475 p = ep - 1;
476 if (p > ebuf && *p == '\n')
477 p--;
478 for ( ; p >= ebuf && *p != '\n'; p--)
479 ;
480 while (*p == '\n')
481 p++;
482 fprintf(stderr, " context is\n\t");
483 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
484 ;
485 while (p < q)
486 putc(*p++, stderr);
487 fprintf(stderr, " >>> ");
488 while (p < ep)
489 putc(*p++, stderr);
490 fprintf(stderr, " <<< ");
491 while (pb >= pbuf)
492 putc(*pb--, stderr);
493 fgets(ebuf, sizeof ebuf, curfile->fin);
494 fprintf(stderr, "%s", ebuf);
495 pbstr("\n.PE\n"); /* safety first */
496 ep = ebuf;
497 }
498
yywrap()499 yywrap() {;}
500
501 char *newfile = 0; /* filename for file copy */
502 char *untilstr = 0; /* string that terminates a thru */
503 int thru = 0; /* 1 if copying thru macro */
504 struct symtab *thrudef = 0; /* macro being used */
505
copyfile(s)506 copyfile(s) /* remember file to start reading from */
507 char *s;
508 {
509 newfile = s;
510 }
511
512 copydef(p) /* remember macro symtab ptr */
513 struct symtab *p;
514 {
515 thrudef = p;
516 }
517
copythru(s)518 struct symtab *copythru(s) /* collect the macro name or body for thru */
519 char *s;
520 {
521 struct symtab *p;
522 char *q, *addnewline();
523
524 p = lookup(s);
525 if (p != NULL) {
526 if (p->s_type == DEFNAME) {
527 p->s_val.p = addnewline(p->s_val.p);
528 return p;
529 } else
530 fatal("%s used as define and name", s);
531 }
532 /* have to collect the definition */
533 pbstr(s); /* first char is the delimiter */
534 q = delimstr("thru body");
535 s = "nameless";
536 p = lookup(s);
537 if (p != NULL) {
538 if (p->s_val.p)
539 free(p->s_val.p);
540 p->s_val.p = q;
541 } else {
542 YYSTYPE u;
543 u.p = q;
544 p = makevar(tostring(s), DEFNAME, u);
545 }
546 p->s_val.p = addnewline(p->s_val.p);
547 dprintf("installing %s as `%s'\n", s, p->s_val.p);
548 return p;
549 }
550
addnewline(p)551 char *addnewline(p) /* add newline to end of p */
552 char *p;
553 {
554 int n;
555 extern char *realloc();
556
557 n = strlen(p);
558 if (p[n-1] != '\n') {
559 p = realloc(p, n+2);
560 p[n] = '\n';
561 p[n+1] = '\0';
562 }
563 return p;
564 }
565
copyuntil(s)566 copyuntil(s) /* string that terminates a thru */
567 char *s;
568 {
569 untilstr = s;
570 }
571
copy()572 copy() /* begin input from file, etc. */
573 {
574 FILE *fin;
575
576 if (newfile) {
577 if ((fin = fopen(newfile, "r")) == NULL)
578 fatal("can't open file %s", newfile);
579 curfile++;
580 curfile->fin = fin;
581 curfile->fname = newfile;
582 curfile->lineno = 0;
583 printf(".lf 1 %s\n", curfile->fname);
584 pushsrc(File, curfile);
585 newfile = 0;
586 }
587 if (thrudef) {
588 thru = 1;
589 begin = 1; /* wrong place */
590 }
591 }
592
593 char shellbuf[1000], *shellp;
594
shell_init()595 shell_init() /* set up to interpret a shell command */
596 {
597 sprintf(shellbuf, "sh -c '");
598 shellp = shellbuf + strlen(shellbuf);
599 }
600
shell_text(s)601 shell_text(s) /* add string to command being collected */
602 char *s;
603 {
604 while (*shellp++ = *s++)
605 ;
606 shellp--;
607 }
608
shell_exec()609 shell_exec() /* do it */
610 {
611 *shellp++ = '\'';
612 *shellp = '\0';
613 system(shellbuf);
614 }
615