n1.c (20331B)
1 /* 2 * n1.c 3 * 4 * consume options, initialization, main loop, 5 * input routines, escape function calling 6 */ 7 8 #include <u.h> 9 #include "tdef.h" 10 #include "fns.h" 11 #include "ext.h" 12 #include "dwbinit.h" 13 14 #include <setjmp.h> 15 #include <time.h> 16 17 char *Version = "March 11, 1994"; 18 19 #ifndef DWBVERSION 20 #define DWBVERSION "???" 21 #endif 22 23 char *DWBfontdir = FONTDIR; 24 char *DWBntermdir = NTERMDIR; 25 char *DWBalthyphens = ALTHYPHENS; 26 char *DWBhomedir = ""; 27 28 dwbinit dwbpaths[] = { 29 &DWBfontdir, NULL, 0, 30 &DWBntermdir, NULL, 0, 31 &DWBalthyphens, NULL, 0, 32 &DWBhomedir, NULL, 0, 33 NULL, nextf, NS, 34 NULL, NULL, 0 35 }; 36 37 int TROFF = 1; /* assume we started in troff... */ 38 39 jmp_buf sjbuf; 40 Offset ipl[NSO]; 41 42 static FILE *ifile; 43 static FILE *ifl[NSO]; /* open input file pointers */ 44 char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */ 45 int cfline[NSO]; /* input line count stack */ 46 char *progname; /* program name (troff or nroff) */ 47 48 int trace = 0; /* tracing mode: default off */ 49 int trace1 = 0; 50 51 int 52 main(int argc, char *argv[]) 53 { 54 char *p; 55 int j; 56 Tchar i; 57 char buf[100]; 58 59 ifile = stdin; /* gcc */ 60 ptid = stdout; 61 62 buf[0] = '\0'; /* make sure it's empty (silly 3b2) */ 63 progname = argv[0]; 64 if ((p = strrchr(progname, '/')) == NULL) 65 p = progname; 66 else 67 p++; 68 DWBinit(progname, dwbpaths); 69 if (strcmp(p, "nroff") == 0) 70 TROFF = 0; 71 #ifdef UNICODE 72 alphabet = 128; /* unicode for plan 9 */ 73 #endif /*UNICODE*/ 74 mnspace(); 75 nnspace(); 76 mrehash(); 77 nrehash(); 78 numtabp[NL].val = -1; 79 80 while (--argc > 0 && (++argv)[0][0] == '-') 81 switch (argv[0][1]) { 82 83 case 'N': /* ought to be used first... */ 84 TROFF = 0; 85 break; 86 case 'd': 87 fprintf(stderr, "troff/nroff version %s\n", Version); 88 break; 89 case 'F': /* switch font tables from default */ 90 if (argv[0][2] != '\0') { 91 strcpy(termtab, &argv[0][2]); 92 strcpy(fontdir, &argv[0][2]); 93 } else { 94 argv++; argc--; 95 strcpy(termtab, argv[0]); 96 strcpy(fontdir, argv[0]); 97 } 98 break; 99 case 0: 100 goto start; 101 case 'i': 102 stdi++; 103 break; 104 case 'n': 105 npn = atoi(&argv[0][2]); 106 break; 107 case 'u': /* set emboldening amount */ 108 bdtab[3] = atoi(&argv[0][2]); 109 if (bdtab[3] < 0 || bdtab[3] > 50) 110 bdtab[3] = 0; 111 break; 112 case 's': 113 if (!(stop = atoi(&argv[0][2]))) 114 stop++; 115 break; 116 case 'r': 117 sprintf(buf + strlen(buf), ".nr %c %s\n", 118 argv[0][2], &argv[0][3]); 119 /* not yet cpushback(buf);*/ 120 /* dotnr(&argv[0][2], &argv[0][3]); */ 121 break; 122 case 'm': 123 if (mflg++ >= NMF) { 124 ERROR "Too many macro packages: %s", argv[0] WARN; 125 break; 126 } 127 strcpy(mfiles[nmfi], nextf); 128 strcat(mfiles[nmfi++], &argv[0][2]); 129 break; 130 case 'o': 131 getpn(&argv[0][2]); 132 break; 133 case 'T': 134 strcpy(devname, &argv[0][2]); 135 dotT++; 136 break; 137 case 'a': 138 ascii = 1; 139 break; 140 case 'h': 141 hflg++; 142 break; 143 case 'e': 144 eqflg++; 145 break; 146 case 'q': 147 quiet++; 148 save_tty(); 149 break; 150 case 'V': 151 fprintf(stdout, "%croff: DWB %s\n", 152 TROFF ? 't' : 'n', DWBVERSION); 153 exit(0); 154 case 't': 155 if (argv[0][2] != '\0') 156 trace = trace1 = argv[0][2]; 157 break; /* for the sake of compatibility */ 158 default: 159 ERROR "unknown option %s", argv[0] WARN; 160 done(02); 161 } 162 163 start: 164 /* 165 * cpushback maintains a LIFO, so push pack the -r arguments 166 * in reverse order to maintain a FIFO in case someone did -rC1 -rC3 167 */ 168 if (buf[0]) { 169 char *p = buf; 170 while(*p++) 171 ; 172 while(p > buf) { 173 while(strncmp(p, ".nr", 3) != 0) 174 p--; 175 cpushback(p); 176 *p-- = '\0'; 177 } 178 } 179 argp = argv; 180 rargc = argc; 181 nmfi = 0; 182 init2(); 183 setjmp(sjbuf); 184 loop: 185 copyf = lgf = nb = nflush = nlflg = 0; 186 if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) { 187 nflush++; 188 trap = 0; 189 eject((Stack *)0); 190 goto loop; 191 } 192 i = getch(); 193 if (pendt) 194 goto Lt; 195 if ((j = cbits(i)) == XPAR) { 196 copyf++; 197 tflg++; 198 while (cbits(i) != '\n') 199 pchar(i = getch()); 200 tflg = 0; 201 copyf--; 202 goto loop; 203 } 204 if (j == cc || j == c2) { 205 if (j == c2) 206 nb++; 207 copyf++; 208 while ((j = cbits(i = getch())) == ' ' || j == '\t') 209 ; 210 ch = i; 211 copyf--; 212 control(getrq(), 1); 213 flushi(); 214 goto loop; 215 } 216 Lt: 217 ch = i; 218 text(); 219 if (nlflg) 220 numtabp[HP].val = 0; 221 goto loop; 222 } 223 224 225 226 void init2(void) 227 { 228 int i; 229 char buf[100]; 230 231 for (i = NTRTAB; --i; ) 232 trtab[i] = i; 233 trtab[UNPAD] = ' '; 234 iflg = 0; 235 obufp = obuf; 236 if (TROFF) 237 t_ptinit(); 238 else 239 n_ptinit(); 240 mchbits(); 241 cvtime(); 242 numtabp[PID].val = getpid(); 243 numtabp[HP].val = init = 0; 244 numtabp[NL].val = -1; 245 nfo = 0; 246 copyf = raw = 0; 247 sprintf(buf, ".ds .T %s\n", devname); 248 cpushback(buf); 249 sprintf(buf, ".ds .P %s\n", DWBhomedir); 250 cpushback(buf); 251 numtabp[CD].val = -1; /* compensation */ 252 nx = mflg; 253 frame = stk = (Stack *)setbrk(STACKSIZE); 254 dip = &d[0]; 255 nxf = frame + 1; 256 for (i = 1; i < NEV; i++) /* propagate the environment */ 257 envcopy(&env[i], &env[0]); 258 for (i = 0; i < NEV; i++) { 259 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) { 260 ERROR "not enough room for word buffers" WARN; 261 done2(1); 262 } 263 env[i]._word._size = WDSIZE; 264 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) { 265 ERROR "not enough room for line buffers" WARN; 266 done2(1); 267 } 268 env[i]._line._size = LNSIZE; 269 } 270 if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) { 271 ERROR "not enough room for line buffers" WARN; 272 done2(1); 273 } 274 olinep = oline; 275 olnsize = OLNSIZE; 276 blockinit(); 277 } 278 279 void cvtime(void) 280 { 281 time_t tt; 282 struct tm *ltime; 283 284 time(&tt); 285 ltime = localtime(&tt); 286 numtabp[YR].val = ltime->tm_year % 100; 287 numtabp[YR].fmt = 2; 288 numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */ 289 numtabp[DY].val = ltime->tm_mday; 290 numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */ 291 } 292 293 294 295 char errbuf[200]; 296 297 void errprint(void) /* error message printer */ 298 { 299 int savecd = numtabp[CD].val; 300 301 if (!nlflg) 302 numtabp[CD].val++; 303 304 fprintf(stderr, "%s: ", progname); 305 fputs(errbuf, stderr); 306 if (cfname[ifi][0]) 307 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val); 308 fputs("\n", stderr); 309 if (cfname[ifi][0]) 310 stackdump(); 311 numtabp[CD].val = savecd; 312 } 313 314 315 int control(int a, int b) 316 { 317 int j, k; 318 extern Contab *contabp; 319 320 numerr.type = RQERR; 321 numerr.req = a; 322 if (a == 0 || (j = findmn(a)) == -1) 323 return(0); 324 if (contabp[j].f == 0) { 325 if (trace & TRMAC) 326 fprintf(stderr, "invoke macro %s\n", unpair(a)); 327 if (dip != d) 328 for (k = dilev; k; k--) 329 if (d[k].curd == a) { 330 ERROR "diversion %s invokes itself during diversion", 331 unpair(a) WARN; 332 edone(0100); 333 } 334 nxf->nargs = 0; 335 if (b) 336 collect(); 337 flushi(); 338 return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */ 339 } 340 if (b) { 341 if (trace & TRREQ) 342 fprintf(stderr, "invoke request %s\n", unpair(a)); 343 (*contabp[j].f)(); 344 } 345 return(0); 346 } 347 348 void casept(void) 349 { 350 int i; 351 352 noscale++; 353 if (skip()) 354 i = trace1; 355 else { 356 i = max(inumb(&trace), 0); 357 if (nonumb) 358 i = trace1; 359 } 360 trace1 = trace; 361 trace = i; 362 noscale = 0; 363 } 364 365 366 int getrq(void) 367 { 368 int i, j; 369 370 if ((i = getach()) == 0 || (j = getach()) == 0) 371 goto rtn; 372 i = PAIR(i, j); 373 rtn: 374 return(i); 375 } 376 377 /* 378 * table encodes some special characters, to speed up tests 379 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch 380 */ 381 382 char gchtab[NCHARS] = { 383 000,004,000,000,010,000,000,000, /* fc, ldr */ 384 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */ 385 000,000,000,000,000,000,000,000, 386 000,001,000,001,000,000,000,000, /* FLSS, ESC */ 387 000,000,000,000,000,000,000,000, 388 000,000,000,000,000,000,000,000, 389 000,000,000,000,000,000,000,000, 390 000,000,000,000,000,000,000,000, 391 000,000,000,000,000,000,000,000, 392 000,000,000,000,000,000,000,000, 393 000,000,000,000,000,000,000,000, 394 000,000,000,000,000,000,000,000, 395 000,000,000,000,000,000,001,000, /* f */ 396 000,000,000,000,000,000,000,000, 397 000,000,000,000,000,000,000,000, 398 000,000,000,000,000,000,000,000 399 }; 400 401 int realcbits(Tchar c) /* return character bits, or MOTCH if motion */ 402 { 403 if (ismot(c)) 404 return MOTCH; 405 else 406 return c & 0xFFFF; 407 } 408 409 Tchar getch(void) 410 { 411 int k; 412 Tchar i, j; 413 414 g0: 415 if (ch) { 416 i = ch; 417 if (cbits(i) == '\n') 418 nlflg++; 419 ch = 0; 420 return(i); 421 } 422 423 if (nlflg) 424 return('\n'); 425 i = getch0(); 426 if (ismot(i)) 427 return(i); 428 k = cbits(i); 429 if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */ 430 return(i); 431 if (k != ESC) { 432 if (k == '\n') { 433 nlflg++; 434 if (ip == 0) 435 numtabp[CD].val++; /* line number */ 436 return(k); 437 } 438 if (k == FLSS) { 439 copyf++; 440 raw++; 441 i = getch0(); 442 if (!fi) 443 flss = i; 444 copyf--; 445 raw--; 446 goto g0; 447 } 448 if (k == RPT) { 449 setrpt(); 450 goto g0; 451 } 452 if (!copyf) { 453 if (k == 'f' && lg && !lgf) { 454 i = getlg(i); 455 return(i); 456 } 457 if (k == fc || k == tabch || k == ldrch) { 458 if ((i = setfield(k)) == 0) 459 goto g0; 460 else 461 return(i); 462 } 463 if (k == '\b') { 464 i = makem(-width(' ' | chbits)); 465 return(i); 466 } 467 } 468 return(i); 469 } 470 471 k = cbits(j = getch0()); 472 if (ismot(j)) 473 return(j); 474 475 switch (k) { 476 case 'n': /* number register */ 477 setn(); 478 goto g0; 479 case '$': /* argument indicator */ 480 seta(); 481 goto g0; 482 case '*': /* string indicator */ 483 setstr(); 484 goto g0; 485 case '{': /* LEFT */ 486 i = LEFT; 487 goto gx; 488 case '}': /* RIGHT */ 489 i = RIGHT; 490 goto gx; 491 case '"': /* comment */ 492 while (cbits(i = getch0()) != '\n') 493 ; 494 if (ip == 0) 495 numtabp[CD].val++; /* line number */ 496 nlflg++; 497 return(i); 498 499 /* experiment: put it here instead of copy mode */ 500 case '(': /* special char name \(xx */ 501 case 'C': /* \C'...' */ 502 if ((i = setch(k)) == 0) 503 goto g0; 504 goto gx; 505 506 case ESC: /* double backslash */ 507 i = eschar; 508 goto gx; 509 case 'e': /* printable version of current eschar */ 510 i = PRESC; 511 goto gx; 512 case '\n': /* concealed newline */ 513 numtabp[CD].val++; 514 goto g0; 515 case ' ': /* unpaddable space */ 516 i = UNPAD; 517 goto gx; 518 case '\'': /* \(aa */ 519 i = ACUTE; 520 goto gx; 521 case '`': /* \(ga */ 522 i = GRAVE; 523 goto gx; 524 case '_': /* \(ul */ 525 i = UNDERLINE; 526 goto gx; 527 case '-': /* current font minus */ 528 i = MINUS; 529 goto gx; 530 case '&': /* filler */ 531 i = FILLER; 532 goto gx; 533 case 'c': /* to be continued */ 534 i = CONT; 535 goto gx; 536 case '!': /* transparent indicator */ 537 i = XPAR; 538 goto gx; 539 case 't': /* tab */ 540 i = '\t'; 541 return(i); 542 case 'a': /* leader (SOH) */ 543 /* old: *pbp++ = LEADER; goto g0; */ 544 i = LEADER; 545 return i; 546 case '%': /* ohc */ 547 i = OHC; 548 return(i); 549 case 'g': /* return format of a number register */ 550 setaf(); /* should this really be in copy mode??? */ 551 goto g0; 552 case '.': /* . */ 553 i = '.'; 554 gx: 555 setsfbits(i, sfbits(j)); 556 return(i); 557 } 558 if (copyf) { 559 *pbp++ = j; 560 return(eschar); 561 } 562 switch (k) { 563 564 case 'f': /* font indicator */ 565 setfont(0); 566 goto g0; 567 case 's': /* size indicator */ 568 setps(); 569 goto g0; 570 case 'v': /* vert mot */ 571 numerr.type = numerr.escarg = 0; numerr.esc = k; 572 if (i = vmot()) { 573 return(i); 574 } 575 goto g0; 576 case 'h': /* horiz mot */ 577 numerr.type = numerr.escarg = 0; numerr.esc = k; 578 if (i = hmot()) 579 return(i); 580 goto g0; 581 case '|': /* narrow space */ 582 if (NROFF) 583 goto g0; 584 return(makem((int)(EM)/6)); 585 case '^': /* half narrow space */ 586 if (NROFF) 587 goto g0; 588 return(makem((int)(EM)/12)); 589 case 'w': /* width function */ 590 setwd(); 591 goto g0; 592 case 'p': /* spread */ 593 spread++; 594 goto g0; 595 case 'N': /* absolute character number */ 596 numerr.type = numerr.escarg = 0; numerr.esc = k; 597 if ((i = setabs()) == 0) 598 goto g0; 599 return i; 600 case 'H': /* character height */ 601 numerr.type = numerr.escarg = 0; numerr.esc = k; 602 return(setht()); 603 case 'S': /* slant */ 604 numerr.type = numerr.escarg = 0; numerr.esc = k; 605 return(setslant()); 606 case 'z': /* zero with char */ 607 return(setz()); 608 case 'l': /* hor line */ 609 numerr.type = numerr.escarg = 0; numerr.esc = k; 610 setline(); 611 goto g0; 612 case 'L': /* vert line */ 613 numerr.type = numerr.escarg = 0; numerr.esc = k; 614 setvline(); 615 goto g0; 616 case 'D': /* drawing function */ 617 numerr.type = numerr.escarg = 0; numerr.esc = k; 618 setdraw(); 619 goto g0; 620 case 'X': /* \X'...' for copy through */ 621 setxon(); 622 goto g0; 623 case 'b': /* bracket */ 624 setbra(); 625 goto g0; 626 case 'o': /* overstrike */ 627 setov(); 628 goto g0; 629 case 'k': /* mark hor place */ 630 if ((k = findr(getsn())) != -1) { 631 numtabp[k].val = numtabp[HP].val; 632 } 633 goto g0; 634 case '0': /* number space */ 635 return(makem(width('0' | chbits))); 636 case 'x': /* extra line space */ 637 numerr.type = numerr.escarg = 0; numerr.esc = k; 638 if (i = xlss()) 639 return(i); 640 goto g0; 641 case 'u': /* half em up */ 642 case 'r': /* full em up */ 643 case 'd': /* half em down */ 644 return(sethl(k)); 645 default: 646 return(j); 647 } 648 /* NOTREACHED */ 649 } 650 651 void setxon(void) /* \X'...' for copy through */ 652 { 653 Tchar xbuf[NC]; 654 Tchar *i; 655 Tchar c; 656 int delim, k; 657 658 if (ismot(c = getch())) 659 return; 660 delim = cbits(c); 661 i = xbuf; 662 *i++ = XON | chbits; 663 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) { 664 if (k == ' ') 665 setcbits(c, WORDSP); 666 *i++ = c | ZBIT; 667 } 668 *i++ = XOFF | chbits; 669 *i = 0; 670 pushback(xbuf); 671 } 672 673 674 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 }; 675 676 Tchar getch0(void) 677 { 678 Tchar i; 679 680 again: 681 if (pbp > lastpbp) 682 i = *--pbp; 683 else if (ip) { 684 /* i = rbf(); */ 685 i = rbf0(ip); 686 if (i == 0) 687 i = rbf(); 688 else { 689 ++ip; 690 if (pastend(ip)) { 691 --ip; 692 rbf(); 693 } 694 } 695 } else { 696 if (donef || ndone) 697 done(0); 698 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */ 699 if (nfo < 0) 700 ERROR "in getch0, nfo = %d", nfo WARN; 701 if (nfo == 0) { 702 g0: 703 if (nextfile()) { 704 if (ip) 705 goto again; 706 } 707 } 708 nx = 0; 709 #ifdef UNICODE 710 if (MB_CUR_MAX > 1) 711 i = get1ch(ifile); 712 else 713 #endif /*UNICODE*/ 714 i = getc(ifile); 715 if (i == EOF) 716 goto g0; 717 if (ip) 718 goto again; 719 } 720 /*g2: */ 721 if (i >= 040) /* zapped: && i < 0177 */ 722 goto g4; 723 i = ifilt[i]; 724 } 725 if (cbits(i) == IMP && !raw) 726 goto again; 727 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */ 728 goto again; 729 } 730 g4: 731 if (ismot(i)) 732 return i; 733 if (copyf == 0 && sfbits(i) == 0) 734 i |= chbits; 735 if (cbits(i) == eschar && !raw) 736 setcbits(i, ESC); 737 return(i); 738 } 739 740 741 #ifdef UNICODE 742 Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */ 743 { 744 wchar_t wc; 745 char buf[100], *p; 746 int i, n, c; 747 748 for (i = 0, p = buf; i < MB_CUR_MAX; i++) { 749 if ((c = getc(fp)) == EOF) 750 return c; 751 *p++ = c; 752 if ((n = mbtowc(&wc, buf, p-buf)) >= 0) 753 break; 754 } 755 756 if (n == 1) /* real ascii, presumably */ 757 return wc; 758 if (n == 0) 759 return p[-1]; /* illegal, but what else to do? */ 760 if (c == EOF) 761 return EOF; 762 *p = 0; 763 return chadd(buf, MBchar, Install); /* add name even if haven't seen it */ 764 } 765 #endif /*UNICODE*/ 766 767 void pushback(Tchar *b) 768 { 769 Tchar *ob = b; 770 771 while (*b++) 772 ; 773 b--; 774 while (b > ob && pbp < &pbbuf[NC-3]) 775 *pbp++ = *--b; 776 if (pbp >= &pbbuf[NC-3]) { 777 ERROR "pushback overflow" WARN; 778 done(2); 779 } 780 } 781 782 void cpushback(char *b) 783 { 784 char *ob = b; 785 786 while (*b++) 787 ; 788 b--; 789 while (b > ob && pbp < &pbbuf[NC-3]) 790 *pbp++ = *--b; 791 if (pbp >= &pbbuf[NC-3]) { 792 ERROR "cpushback overflow" WARN; 793 done(2); 794 } 795 } 796 797 int nextfile(void) 798 { 799 char *p; 800 801 n0: 802 if (ifile != stdin) 803 fclose(ifile); 804 if (ifi > 0 && !nx) { 805 if (popf()) 806 goto n0; /* popf error */ 807 return(1); /* popf ok */ 808 } 809 if (nx || nmfi < mflg) { 810 p = mfiles[nmfi++]; 811 if (*p != 0) 812 goto n1; 813 } 814 if (rargc-- <= 0) { 815 if ((nfo -= mflg) && !stdi) { 816 done(0); 817 } 818 nfo++; 819 numtabp[CD].val = stdi = mflg = 0; 820 ifile = stdin; 821 strcpy(cfname[ifi], "stdin"); 822 return(0); 823 } 824 p = (argp++)[0]; 825 if (rargc >= 0) 826 cfname[ifi][0] = 0; 827 n1: 828 numtabp[CD].val = 0; 829 if (p[0] == '-' && p[1] == 0) { 830 ifile = stdin; 831 strcpy(cfname[ifi], "stdin"); 832 } else if ((ifile = fopen(unsharp(p), "r")) == NULL) { 833 ERROR "cannot open file %s", p WARN; 834 nfo -= mflg; 835 done(02); 836 } else 837 strcpy(cfname[ifi],p); 838 nfo++; 839 return(0); 840 } 841 842 int 843 popf(void) 844 { 845 --ifi; 846 if (ifi < 0) { 847 ERROR "popf went negative" WARN; 848 return 1; 849 } 850 numtabp[CD].val = cfline[ifi]; /* restore line counter */ 851 ip = ipl[ifi]; /* input pointer */ 852 ifile = ifl[ifi]; /* input FILE * */ 853 return(0); 854 } 855 856 857 void flushi(void) 858 { 859 if (nflush) 860 return; 861 ch = 0; 862 copyf++; 863 while (!nlflg) { 864 if (donef && frame == stk) 865 break; 866 getch(); 867 } 868 copyf--; 869 } 870 871 /* 872 * return 16-bit, ascii/alphabetic character, ignore chars with more bits, 873 * (internal names), spaces and special cookies (below 040). 874 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff. 875 */ 876 int 877 getach(void) 878 { 879 Tchar i; 880 int j; 881 882 lgf++; 883 j = cbits(i = getch()); 884 if (ismot(i) 885 || j > SHORTMASK 886 || (j <= 040 && j != 002 /*STX*/ 887 && j != 003 /*ETX*/ 888 && j != 005 /*ENQ*/ 889 && j != 006 /*ACK*/ 890 && j != 007)) { /*BELL*/ 891 ch = i; 892 j = 0; 893 } 894 lgf--; 895 return j; 896 } 897 898 899 void casenx(void) 900 { 901 lgf++; 902 skip(); 903 getname(); 904 nx++; 905 if (nmfi > 0) 906 nmfi--; 907 strcpy(mfiles[nmfi], nextf); 908 nextfile(); 909 nlflg++; 910 ip = 0; 911 pendt = 0; 912 frame = stk; 913 nxf = frame + 1; 914 } 915 916 int 917 getname(void) 918 { 919 int j, k; 920 921 lgf++; 922 for (k = 0; k < NS - 1; k++) { 923 j = getach(); 924 if (!j) 925 break; 926 nextf[k] = j; 927 } 928 nextf[k] = 0; 929 lgf--; 930 return(nextf[0]); 931 } 932 933 934 void caseso(void) 935 { 936 FILE *fp = 0; 937 938 lgf++; 939 nextf[0] = 0; 940 if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) { 941 ERROR "can't open file %s", nextf WARN; 942 done(02); 943 } 944 strcpy(cfname[ifi+1], nextf); 945 cfline[ifi] = numtabp[CD].val; /*hold line counter*/ 946 numtabp[CD].val = 0; 947 flushi(); 948 ifl[ifi] = ifile; 949 ifile = fp; 950 ipl[ifi] = ip; 951 ip = 0; 952 nx++; 953 nflush++; 954 ifi++; 955 } 956 957 void caself(void) /* set line number and file */ 958 { 959 int n; 960 961 if (skip()) 962 return; 963 n = atoi0(); 964 if (!nonumb) 965 cfline[ifi] = numtabp[CD].val = n - 1; 966 if (!skip()) 967 if (getname()) { /* eats '\n' ? */ 968 strcpy(cfname[ifi], nextf); 969 if (!nonumb) 970 numtabp[CD].val--; 971 } 972 } 973 974 void cpout(FILE *fin, char *token) 975 { 976 int n; 977 char buf[1024]; 978 979 if (token) { /* BUG: There should be no NULL bytes in input */ 980 char *newl = buf; 981 while ((fgets(buf, sizeof buf, fin)) != NULL) { 982 if (newl) { 983 numtabp[CD].val++; /* line number */ 984 if (strcmp(token, buf) == 0) 985 return; 986 } 987 newl = strchr(buf, '\n'); 988 fputs(buf, ptid); 989 } 990 } else { 991 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0) 992 fwrite(buf, n, 1, ptid); 993 fclose(fin); 994 } 995 } 996 997 void casecf(void) 998 { /* copy file without change */ 999 FILE *fd; 1000 char *eof, *p; 1001 extern int hpos, esc, po; 1002 1003 /* this may not make much sense in nroff... */ 1004 1005 lgf++; 1006 nextf[0] = 0; 1007 if (!skip() && getname()) { 1008 if (strncmp("<<", nextf, 2) != 0) { 1009 if ((fd = fopen(unsharp(nextf), "r")) == NULL) { 1010 ERROR "can't open file %s", nextf WARN; 1011 done(02); 1012 } 1013 eof = (char *) NULL; 1014 } else { /* current file */ 1015 if (pbp > lastpbp || ip) { 1016 ERROR "casecf: not reading from file" WARN; 1017 done(02); 1018 } 1019 eof = &nextf[2]; 1020 if (!*eof) { 1021 ERROR "casecf: missing end of input token" WARN; 1022 done(02); 1023 } 1024 p = eof; 1025 while(*++p) 1026 ; 1027 *p++ = '\n'; 1028 *p = 0; 1029 fd = ifile; 1030 } 1031 } else { 1032 ERROR "casecf: no argument" WARN; 1033 lgf--; 1034 return; 1035 } 1036 lgf--; 1037 1038 /* make it into a clean state, be sure that everything is out */ 1039 tbreak(); 1040 hpos = po; 1041 esc = 0; 1042 ptesc(); /* to left margin */ 1043 esc = un; 1044 ptesc(); 1045 ptlead(); 1046 ptps(); 1047 ptfont(); 1048 flusho(); 1049 cpout(fd, eof); 1050 ptps(); 1051 ptfont(); 1052 } 1053 1054 void getline(char *s, int n) /* get rest of input line into s */ 1055 { 1056 int i; 1057 1058 lgf++; 1059 copyf++; 1060 skip(); 1061 for (i = 0; i < n-1; i++) 1062 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT) 1063 break; 1064 s[i] = 0; 1065 copyf--; 1066 lgf--; 1067 } 1068 1069 void casesy(void) /* call system */ 1070 { 1071 char sybuf[NTM]; 1072 1073 getline(sybuf, NTM); 1074 system(sybuf); 1075 } 1076 1077 1078 void getpn(char *a) 1079 { 1080 int n, neg; 1081 1082 if (*a == 0) 1083 return; 1084 neg = 0; 1085 for ( ; *a; a++) 1086 switch (*a) { 1087 case '+': 1088 case ',': 1089 continue; 1090 case '-': 1091 neg = 1; 1092 continue; 1093 default: 1094 n = 0; 1095 if (isdigit((uchar)*a)) { 1096 do 1097 n = 10 * n + *a++ - '0'; 1098 while (isdigit((uchar)*a)); 1099 a--; 1100 } else 1101 n = 9999; 1102 *pnp++ = neg ? -n : n; 1103 neg = 0; 1104 if (pnp >= &pnlist[NPN-2]) { 1105 ERROR "too many page numbers" WARN; 1106 done3(-3); 1107 } 1108 } 1109 if (neg) 1110 *pnp++ = -9999; 1111 *pnp = -INT_MAX; 1112 print = 0; 1113 pnp = pnlist; 1114 if (*pnp != -INT_MAX) 1115 chkpn(); 1116 } 1117 1118 1119 void setrpt(void) 1120 { 1121 Tchar i, j; 1122 1123 copyf++; 1124 raw++; 1125 i = getch0(); 1126 copyf--; 1127 raw--; 1128 if ((long) i < 0 || cbits(j = getch0()) == RPT) 1129 return; 1130 while (i > 0 && pbp < &pbbuf[NC-3]) { 1131 i--; 1132 *pbp++ = j; 1133 } 1134 }