n1.c (20409B)
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 '~': /* Heirloom/groff/neatroff: unbreakable space */ 516 ; /* fall through */ 517 case ' ': /* unpaddable space */ 518 i = UNPAD; 519 goto gx; 520 case '\'': /* \(aa */ 521 i = ACUTE; 522 goto gx; 523 case '`': /* \(ga */ 524 i = GRAVE; 525 goto gx; 526 case '_': /* \(ul */ 527 i = UNDERLINE; 528 goto gx; 529 case '-': /* current font minus */ 530 i = MINUS; 531 goto gx; 532 case '&': /* filler */ 533 i = FILLER; 534 goto gx; 535 case 'c': /* to be continued */ 536 i = CONT; 537 goto gx; 538 case '!': /* transparent indicator */ 539 i = XPAR; 540 goto gx; 541 case 't': /* tab */ 542 i = '\t'; 543 return(i); 544 case 'a': /* leader (SOH) */ 545 /* old: *pbp++ = LEADER; goto g0; */ 546 i = LEADER; 547 return i; 548 case '%': /* ohc */ 549 i = OHC; 550 return(i); 551 case 'g': /* return format of a number register */ 552 setaf(); /* should this really be in copy mode??? */ 553 goto g0; 554 case '.': /* . */ 555 i = '.'; 556 gx: 557 setsfbits(i, sfbits(j)); 558 return(i); 559 } 560 if (copyf) { 561 *pbp++ = j; 562 return(eschar); 563 } 564 switch (k) { 565 566 case 'f': /* font indicator */ 567 setfont(0); 568 goto g0; 569 case 's': /* size indicator */ 570 setps(); 571 goto g0; 572 case 'v': /* vert mot */ 573 numerr.type = numerr.escarg = 0; numerr.esc = k; 574 if (i = vmot()) { 575 return(i); 576 } 577 goto g0; 578 case 'h': /* horiz mot */ 579 numerr.type = numerr.escarg = 0; numerr.esc = k; 580 if (i = hmot()) 581 return(i); 582 goto g0; 583 case '|': /* narrow space */ 584 if (NROFF) 585 goto g0; 586 return(makem((int)(EM)/6)); 587 case '^': /* half narrow space */ 588 if (NROFF) 589 goto g0; 590 return(makem((int)(EM)/12)); 591 case 'w': /* width function */ 592 setwd(); 593 goto g0; 594 case 'p': /* spread */ 595 spread++; 596 goto g0; 597 case 'N': /* absolute character number */ 598 numerr.type = numerr.escarg = 0; numerr.esc = k; 599 if ((i = setabs()) == 0) 600 goto g0; 601 return i; 602 case 'H': /* character height */ 603 numerr.type = numerr.escarg = 0; numerr.esc = k; 604 return(setht()); 605 case 'S': /* slant */ 606 numerr.type = numerr.escarg = 0; numerr.esc = k; 607 return(setslant()); 608 case 'z': /* zero with char */ 609 return(setz()); 610 case 'l': /* hor line */ 611 numerr.type = numerr.escarg = 0; numerr.esc = k; 612 setline(); 613 goto g0; 614 case 'L': /* vert line */ 615 numerr.type = numerr.escarg = 0; numerr.esc = k; 616 setvline(); 617 goto g0; 618 case 'D': /* drawing function */ 619 numerr.type = numerr.escarg = 0; numerr.esc = k; 620 setdraw(); 621 goto g0; 622 case 'X': /* \X'...' for copy through */ 623 setxon(); 624 goto g0; 625 case 'b': /* bracket */ 626 setbra(); 627 goto g0; 628 case 'o': /* overstrike */ 629 setov(); 630 goto g0; 631 case 'k': /* mark hor place */ 632 if ((k = findr(getsn())) != -1) { 633 numtabp[k].val = numtabp[HP].val; 634 } 635 goto g0; 636 case '0': /* number space */ 637 return(makem(width('0' | chbits))); 638 case 'x': /* extra line space */ 639 numerr.type = numerr.escarg = 0; numerr.esc = k; 640 if (i = xlss()) 641 return(i); 642 goto g0; 643 case 'u': /* half em up */ 644 case 'r': /* full em up */ 645 case 'd': /* half em down */ 646 return(sethl(k)); 647 default: 648 return(j); 649 } 650 /* NOTREACHED */ 651 } 652 653 void setxon(void) /* \X'...' for copy through */ 654 { 655 Tchar xbuf[NC]; 656 Tchar *i; 657 Tchar c; 658 int delim, k; 659 660 if (ismot(c = getch())) 661 return; 662 delim = cbits(c); 663 i = xbuf; 664 *i++ = XON | chbits; 665 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) { 666 if (k == ' ') 667 setcbits(c, WORDSP); 668 *i++ = c | ZBIT; 669 } 670 *i++ = XOFF | chbits; 671 *i = 0; 672 pushback(xbuf); 673 } 674 675 676 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 }; 677 678 Tchar getch0(void) 679 { 680 Tchar i; 681 682 again: 683 if (pbp > lastpbp) 684 i = *--pbp; 685 else if (ip) { 686 /* i = rbf(); */ 687 i = rbf0(ip); 688 if (i == 0) 689 i = rbf(); 690 else { 691 ++ip; 692 if (pastend(ip)) { 693 --ip; 694 rbf(); 695 } 696 } 697 } else { 698 if (donef || ndone) 699 done(0); 700 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */ 701 if (nfo < 0) 702 ERROR "in getch0, nfo = %d", nfo WARN; 703 if (nfo == 0) { 704 g0: 705 if (nextfile()) { 706 if (ip) 707 goto again; 708 } 709 } 710 nx = 0; 711 #ifdef UNICODE 712 if (MB_CUR_MAX > 1) 713 i = get1ch(ifile); 714 else 715 #endif /*UNICODE*/ 716 i = getc(ifile); 717 if (i == EOF) 718 goto g0; 719 if (ip) 720 goto again; 721 } 722 /*g2: */ 723 if (i >= 040) /* zapped: && i < 0177 */ 724 goto g4; 725 i = ifilt[i]; 726 } 727 if (cbits(i) == IMP && !raw) 728 goto again; 729 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */ 730 goto again; 731 } 732 g4: 733 if (ismot(i)) 734 return i; 735 if (copyf == 0 && sfbits(i) == 0) 736 i |= chbits; 737 if (cbits(i) == eschar && !raw) 738 setcbits(i, ESC); 739 return(i); 740 } 741 742 743 #ifdef UNICODE 744 Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */ 745 { 746 wchar_t wc; 747 char buf[100], *p; 748 int i, n, c; 749 750 for (i = 0, p = buf; i < MB_CUR_MAX; i++) { 751 if ((c = getc(fp)) == EOF) 752 return c; 753 *p++ = c; 754 if ((n = mbtowc(&wc, buf, p-buf)) >= 0) 755 break; 756 } 757 758 if (n == 1) /* real ascii, presumably */ 759 return wc; 760 if (n == 0) 761 return p[-1]; /* illegal, but what else to do? */ 762 if (c == EOF) 763 return EOF; 764 *p = 0; 765 return chadd(buf, MBchar, Install); /* add name even if haven't seen it */ 766 } 767 #endif /*UNICODE*/ 768 769 void pushback(Tchar *b) 770 { 771 Tchar *ob = b; 772 773 while (*b++) 774 ; 775 b--; 776 while (b > ob && pbp < &pbbuf[NC-3]) 777 *pbp++ = *--b; 778 if (pbp >= &pbbuf[NC-3]) { 779 ERROR "pushback overflow" WARN; 780 done(2); 781 } 782 } 783 784 void cpushback(char *b) 785 { 786 char *ob = b; 787 788 while (*b++) 789 ; 790 b--; 791 while (b > ob && pbp < &pbbuf[NC-3]) 792 *pbp++ = *--b; 793 if (pbp >= &pbbuf[NC-3]) { 794 ERROR "cpushback overflow" WARN; 795 done(2); 796 } 797 } 798 799 int nextfile(void) 800 { 801 char *p; 802 803 n0: 804 if (ifile != stdin) 805 fclose(ifile); 806 if (ifi > 0 && !nx) { 807 if (popf()) 808 goto n0; /* popf error */ 809 return(1); /* popf ok */ 810 } 811 if (nx || nmfi < mflg) { 812 p = mfiles[nmfi++]; 813 if (*p != 0) 814 goto n1; 815 } 816 if (rargc-- <= 0) { 817 if ((nfo -= mflg) && !stdi) { 818 done(0); 819 } 820 nfo++; 821 numtabp[CD].val = stdi = mflg = 0; 822 ifile = stdin; 823 strcpy(cfname[ifi], "stdin"); 824 return(0); 825 } 826 p = (argp++)[0]; 827 if (rargc >= 0) 828 cfname[ifi][0] = 0; 829 n1: 830 numtabp[CD].val = 0; 831 if (p[0] == '-' && p[1] == 0) { 832 ifile = stdin; 833 strcpy(cfname[ifi], "stdin"); 834 } else if ((ifile = fopen(unsharp(p), "r")) == NULL) { 835 ERROR "cannot open file %s", p WARN; 836 nfo -= mflg; 837 done(02); 838 } else 839 strcpy(cfname[ifi],p); 840 nfo++; 841 return(0); 842 } 843 844 int 845 popf(void) 846 { 847 --ifi; 848 if (ifi < 0) { 849 ERROR "popf went negative" WARN; 850 return 1; 851 } 852 numtabp[CD].val = cfline[ifi]; /* restore line counter */ 853 ip = ipl[ifi]; /* input pointer */ 854 ifile = ifl[ifi]; /* input FILE * */ 855 return(0); 856 } 857 858 859 void flushi(void) 860 { 861 if (nflush) 862 return; 863 ch = 0; 864 copyf++; 865 while (!nlflg) { 866 if (donef && frame == stk) 867 break; 868 getch(); 869 } 870 copyf--; 871 } 872 873 /* 874 * return 16-bit, ascii/alphabetic character, ignore chars with more bits, 875 * (internal names), spaces and special cookies (below 040). 876 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff. 877 */ 878 int 879 getach(void) 880 { 881 Tchar i; 882 int j; 883 884 lgf++; 885 j = cbits(i = getch()); 886 if (ismot(i) 887 || j > SHORTMASK 888 || (j <= 040 && j != 002 /*STX*/ 889 && j != 003 /*ETX*/ 890 && j != 005 /*ENQ*/ 891 && j != 006 /*ACK*/ 892 && j != 007)) { /*BELL*/ 893 ch = i; 894 j = 0; 895 } 896 lgf--; 897 return j; 898 } 899 900 901 void casenx(void) 902 { 903 lgf++; 904 skip(); 905 getname(); 906 nx++; 907 if (nmfi > 0) 908 nmfi--; 909 strcpy(mfiles[nmfi], nextf); 910 nextfile(); 911 nlflg++; 912 ip = 0; 913 pendt = 0; 914 frame = stk; 915 nxf = frame + 1; 916 } 917 918 int 919 getname(void) 920 { 921 int j, k; 922 923 lgf++; 924 for (k = 0; k < NS - 1; k++) { 925 j = getach(); 926 if (!j) 927 break; 928 nextf[k] = j; 929 } 930 nextf[k] = 0; 931 lgf--; 932 return(nextf[0]); 933 } 934 935 936 void caseso(void) 937 { 938 FILE *fp = 0; 939 940 lgf++; 941 nextf[0] = 0; 942 if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) { 943 ERROR "can't open file %s", nextf WARN; 944 done(02); 945 } 946 strcpy(cfname[ifi+1], nextf); 947 cfline[ifi] = numtabp[CD].val; /*hold line counter*/ 948 numtabp[CD].val = 0; 949 flushi(); 950 ifl[ifi] = ifile; 951 ifile = fp; 952 ipl[ifi] = ip; 953 ip = 0; 954 nx++; 955 nflush++; 956 ifi++; 957 } 958 959 void caself(void) /* set line number and file */ 960 { 961 int n; 962 963 if (skip()) 964 return; 965 n = atoi0(); 966 if (!nonumb) 967 cfline[ifi] = numtabp[CD].val = n - 1; 968 if (!skip()) 969 if (getname()) { /* eats '\n' ? */ 970 strcpy(cfname[ifi], nextf); 971 if (!nonumb) 972 numtabp[CD].val--; 973 } 974 } 975 976 void cpout(FILE *fin, char *token) 977 { 978 int n; 979 char buf[1024]; 980 981 if (token) { /* BUG: There should be no NULL bytes in input */ 982 char *newl = buf; 983 while ((fgets(buf, sizeof buf, fin)) != NULL) { 984 if (newl) { 985 numtabp[CD].val++; /* line number */ 986 if (strcmp(token, buf) == 0) 987 return; 988 } 989 newl = strchr(buf, '\n'); 990 fputs(buf, ptid); 991 } 992 } else { 993 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0) 994 fwrite(buf, n, 1, ptid); 995 fclose(fin); 996 } 997 } 998 999 void casecf(void) 1000 { /* copy file without change */ 1001 FILE *fd; 1002 char *eof, *p; 1003 extern int hpos, esc, po; 1004 1005 /* this may not make much sense in nroff... */ 1006 1007 lgf++; 1008 nextf[0] = 0; 1009 if (!skip() && getname()) { 1010 if (strncmp("<<", nextf, 2) != 0) { 1011 if ((fd = fopen(unsharp(nextf), "r")) == NULL) { 1012 ERROR "can't open file %s", nextf WARN; 1013 done(02); 1014 } 1015 eof = (char *) NULL; 1016 } else { /* current file */ 1017 if (pbp > lastpbp || ip) { 1018 ERROR "casecf: not reading from file" WARN; 1019 done(02); 1020 } 1021 eof = &nextf[2]; 1022 if (!*eof) { 1023 ERROR "casecf: missing end of input token" WARN; 1024 done(02); 1025 } 1026 p = eof; 1027 while(*++p) 1028 ; 1029 *p++ = '\n'; 1030 *p = 0; 1031 fd = ifile; 1032 } 1033 } else { 1034 ERROR "casecf: no argument" WARN; 1035 lgf--; 1036 return; 1037 } 1038 lgf--; 1039 1040 /* make it into a clean state, be sure that everything is out */ 1041 tbreak(); 1042 hpos = po; 1043 esc = 0; 1044 ptesc(); /* to left margin */ 1045 esc = un; 1046 ptesc(); 1047 ptlead(); 1048 ptps(); 1049 ptfont(); 1050 flusho(); 1051 cpout(fd, eof); 1052 ptps(); 1053 ptfont(); 1054 } 1055 1056 void getline(char *s, int n) /* get rest of input line into s */ 1057 { 1058 int i; 1059 1060 lgf++; 1061 copyf++; 1062 skip(); 1063 for (i = 0; i < n-1; i++) 1064 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT) 1065 break; 1066 s[i] = 0; 1067 copyf--; 1068 lgf--; 1069 } 1070 1071 void casesy(void) /* call system */ 1072 { 1073 char sybuf[NTM]; 1074 1075 getline(sybuf, NTM); 1076 system(sybuf); 1077 } 1078 1079 1080 void getpn(char *a) 1081 { 1082 int n, neg; 1083 1084 if (*a == 0) 1085 return; 1086 neg = 0; 1087 for ( ; *a; a++) 1088 switch (*a) { 1089 case '+': 1090 case ',': 1091 continue; 1092 case '-': 1093 neg = 1; 1094 continue; 1095 default: 1096 n = 0; 1097 if (isdigit((uchar)*a)) { 1098 do 1099 n = 10 * n + *a++ - '0'; 1100 while (isdigit((uchar)*a)); 1101 a--; 1102 } else 1103 n = 9999; 1104 *pnp++ = neg ? -n : n; 1105 neg = 0; 1106 if (pnp >= &pnlist[NPN-2]) { 1107 ERROR "too many page numbers" WARN; 1108 done3(-3); 1109 } 1110 } 1111 if (neg) 1112 *pnp++ = -9999; 1113 *pnp = -INT_MAX; 1114 print = 0; 1115 pnp = pnlist; 1116 if (*pnp != -INT_MAX) 1117 chkpn(); 1118 } 1119 1120 1121 void setrpt(void) 1122 { 1123 Tchar i, j; 1124 1125 copyf++; 1126 raw++; 1127 i = getch0(); 1128 copyf--; 1129 raw--; 1130 if ((long) i < 0 || cbits(j = getch0()) == RPT) 1131 return; 1132 while (i > 0 && pbp < &pbbuf[NC-3]) { 1133 i--; 1134 *pbp++ = j; 1135 } 1136 }