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