1 #ifndef lint 2 static char sccsid[] = "@(#)n3.c 2.1 (CWI) 85/07/18"; 3 #endif lint 4 /* @(#)n3.c 1.1 */ 5 /* 6 * troff3.c 7 * 8 * macro and string routines, storage allocation 9 */ 10 11 12 #include "tdef.h" 13 #ifdef NROFF 14 #include "tw.h" 15 #endif 16 #include <sgtty.h> 17 #include "ext.h" 18 19 #define MHASH(x) ((x>>6)^x)&0177 20 struct contab *mhash[128]; /* 128 == the 0177 on line above */ 21 #define blisti(i) (((i)-NEV*(int)sizeof(env))/BLK) 22 filep blist[NBLIST]; 23 tchar *argtop; 24 int pagech = '%'; 25 int strflg; 26 27 #ifdef INCORE 28 tchar *wbuf; 29 tchar corebuf[NEV*sizeof(env)/sizeof(tchar) + NBLIST*BLK+ 1]; 30 #else 31 tchar wbuf[BLK]; 32 tchar rbuf[BLK]; 33 #endif 34 35 caseig() 36 { 37 register i; 38 39 offset = 0; 40 if ((i = copyb()) != '.') 41 control(i, 1); 42 } 43 44 45 casern() 46 { 47 register i, j; 48 49 lgf++; 50 skip(); 51 if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0) 52 return; 53 skip(); 54 clrmn(findmn(j = getrq())); 55 if (j) { 56 munhash(&contab[oldmn]); 57 contab[oldmn].rq = j; 58 maddhash(&contab[oldmn]); 59 } 60 } 61 62 maddhash(rp) 63 register struct contab *rp; 64 { 65 register struct contab **hp; 66 67 if (rp->rq == 0) 68 return; 69 hp = &mhash[MHASH(rp->rq)]; 70 rp->link = *hp; 71 *hp = rp; 72 } 73 74 munhash(mp) 75 register struct contab *mp; 76 { 77 register struct contab *p; 78 register struct contab **lp; 79 80 if (mp->rq == 0) 81 return; 82 lp = &mhash[MHASH(mp->rq)]; 83 p = *lp; 84 while (p) { 85 if (p == mp) { 86 *lp = p->link; 87 p->link = 0; 88 return; 89 } 90 lp = &p->link; 91 p = p->link; 92 } 93 } 94 95 mrehash() 96 { 97 register struct contab *p; 98 register i; 99 100 for (i=0; i<128; i++) 101 mhash[i] = 0; 102 for (p=contab; p < &contab[NM]; p++) 103 p->link = 0; 104 for (p=contab; p < &contab[NM]; p++) { 105 if (p->rq == 0) 106 continue; 107 i = MHASH(p->rq); 108 p->link = mhash[i]; 109 mhash[i] = p; 110 } 111 } 112 113 caserm() 114 { 115 int j; 116 117 lgf++; 118 while (!skip() && (j = getrq()) != 0) 119 clrmn(findmn(j)); 120 lgf--; 121 } 122 123 124 caseas() 125 { 126 app++; 127 caseds(); 128 } 129 130 131 caseds() 132 { 133 ds++; 134 casede(); 135 } 136 137 138 caseam() 139 { 140 app++; 141 casede(); 142 } 143 144 145 casede() 146 { 147 register i, req; 148 register filep savoff; 149 extern filep finds(); 150 151 if (dip != d) 152 wbfl(); 153 req = '.'; 154 lgf++; 155 skip(); 156 if ((i = getrq()) == 0) 157 goto de1; 158 if ((offset = finds(i)) == 0) 159 goto de1; 160 if (ds) 161 copys(); 162 else 163 req = copyb(); 164 wbfl(); 165 clrmn(oldmn); 166 if (newmn) { 167 if (contab[newmn].rq) 168 munhash(&contab[newmn]); 169 contab[newmn].rq = i; 170 maddhash(&contab[newmn]); 171 } 172 if (apptr) { 173 savoff = offset; 174 offset = apptr; 175 wbt((tchar) IMP); 176 offset = savoff; 177 } 178 offset = dip->op; 179 if (req != '.') 180 control(req, 1); 181 de1: 182 ds = app = 0; 183 return; 184 } 185 186 187 findmn(i) 188 register int i; 189 { 190 register struct contab *p; 191 192 for (p = mhash[MHASH(i)]; p; p = p->link) 193 if (i == p->rq) 194 return(p - contab); 195 return(-1); 196 } 197 198 199 clrmn(i) 200 register int i; 201 { 202 if (i >= 0) { 203 if (contab[i].mx) 204 ffree((filep)contab[i].mx); 205 munhash(&contab[i]); 206 contab[i].rq = 0; 207 contab[i].mx = 0; 208 contab[i].f = 0; 209 } 210 } 211 212 213 filep finds(mn) 214 register int mn; 215 { 216 register i; 217 register filep savip; 218 extern filep alloc(); 219 extern filep incoff(); 220 221 oldmn = findmn(mn); 222 newmn = 0; 223 apptr = (filep)0; 224 if (app && oldmn >= 0 && contab[oldmn].mx) { 225 savip = ip; 226 ip = (filep)contab[oldmn].mx; 227 oldmn = -1; 228 while ((i = rbf()) != 0) 229 ; 230 apptr = ip; 231 if (!diflg) 232 ip = incoff(ip); 233 nextb = ip; 234 ip = savip; 235 } else { 236 for (i = 0; i < NM; i++) { 237 if (contab[i].rq == 0) 238 break; 239 } 240 if (i == NM || (nextb = alloc()) == 0) { 241 app = 0; 242 if (macerr++ > 1) 243 done2(02); 244 errprint("Too many (%d) string/macro names", NM); 245 edone(04); 246 return(offset = 0); 247 } 248 contab[i].mx = (unsigned) nextb; 249 if (!diflg) { 250 newmn = i; 251 if (oldmn == -1) 252 contab[i].rq = -1; 253 } else { 254 contab[i].rq = mn; 255 maddhash(&contab[i]); 256 } 257 } 258 app = 0; 259 return(offset = nextb); 260 } 261 262 263 skip() 264 { 265 register tchar i; 266 267 while (cbits(i = getch()) == ' ') 268 ; 269 ch = i; 270 return(nlflg); 271 } 272 273 274 copyb() 275 { 276 register i, j, state; 277 register tchar ii; 278 int req, k; 279 filep savoff; 280 281 if (skip() || !(j = getrq())) 282 j = '.'; 283 req = j; 284 k = j >> BYTE; 285 j &= BYTEMASK; 286 copyf++; 287 flushi(); 288 nlflg = 0; 289 state = 1; 290 while (1) { 291 i = cbits(ii = getch()); 292 if (state == 3) { 293 if (i == k) 294 break; 295 if (!k) { 296 ch = ii; 297 i = getach(); 298 ch = ii; 299 if (!i) 300 break; 301 } 302 state = 0; 303 goto c0; 304 } 305 if (i == '\n') { 306 state = 1; 307 nlflg = 0; 308 goto c0; 309 } 310 if (state == 1 && i == '.') { 311 state++; 312 savoff = offset; 313 goto c0; 314 } 315 if ((state == 2) && (i == j)) { 316 state++; 317 goto c0; 318 } 319 state = 0; 320 c0: 321 if (offset) 322 wbf(ii); 323 } 324 if (offset) { 325 wbfl(); 326 offset = savoff; 327 wbt((tchar)0); 328 } 329 copyf--; 330 return(req); 331 } 332 333 334 copys() 335 { 336 register tchar i; 337 338 copyf++; 339 if (skip()) 340 goto c0; 341 if (cbits(i = getch()) != '"') 342 wbf(i); 343 while (cbits(i = getch()) != '\n') 344 wbf(i); 345 c0: 346 wbt((tchar)0); 347 copyf--; 348 } 349 350 351 filep alloc() 352 { 353 register i; 354 register filep j; 355 356 for (i = 0; i < NBLIST; i++) { 357 if (blist[i] == 0) 358 break; 359 } 360 if (i == NBLIST) { 361 j = 0; 362 } else { 363 blist[i] = -1; 364 if ((j = ((filep)i * BLK + NEV*(int)sizeof(env))) < NEV*(int)sizeof(env)) 365 j = 0; 366 } 367 return(nextb = j); 368 } 369 370 371 ffree(i) 372 filep i; 373 { 374 register j; 375 376 while (blist[j = blisti(i)] != (unsigned) ~0) { 377 i = (filep) blist[j]; 378 blist[j] = 0; 379 } 380 blist[j] = 0; 381 } 382 383 wbt(i) 384 tchar i; 385 { 386 wbf(i); 387 wbfl(); 388 } 389 390 391 wbf(i) 392 register tchar i; 393 { 394 register j; 395 396 if (!offset) 397 return; 398 if (!woff) { 399 woff = offset; 400 #ifdef INCORE 401 wbuf = &corebuf[woff]; /* INCORE only */ 402 #endif 403 wbfi = 0; 404 } 405 wbuf[wbfi++] = i; 406 if (!((++offset) & (BLK - 1))) { 407 wbfl(); 408 j = blisti(--offset); 409 if (j < 0 || j >= NBLIST) { 410 errprint("Out of temp file space"); 411 done2(01); 412 } 413 if (blist[j] == (unsigned) ~0) { 414 if (alloc() == 0) { 415 errprint("Out of temp file space"); 416 done2(01); 417 } 418 blist[j] = (unsigned)(nextb); 419 } 420 offset = ((filep)blist[j]); 421 } 422 if (wbfi >= BLK) 423 wbfl(); 424 } 425 426 427 wbfl() 428 { 429 if (woff == 0) 430 return; 431 #ifndef INCORE 432 lseek(ibf, ((long)woff) * sizeof(tchar), 0); 433 write(ibf, (char *)wbuf, wbfi * sizeof(tchar)); 434 #endif 435 if ((woff & (~(BLK - 1))) == (roff & (~(BLK - 1)))) 436 roff = -1; 437 woff = 0; 438 } 439 440 441 tchar rbf() 442 { 443 register tchar i; 444 register filep j, p; 445 extern filep incoff(); 446 447 if (ip == NBLIST*BLK) { /* for rdtty */ 448 if (j = rdtty()) 449 return(j); 450 else 451 return(popi()); 452 } 453 /* this is an inline expansion of rbf0: dirty! */ 454 #ifndef INCORE 455 j = ip & ~(BLK - 1); 456 if (j != roff) { 457 roff = j; 458 lseek(ibf, (long)j * sizeof(tchar), 0); 459 if (read(ibf, (char *)rbuf, BLK * sizeof(tchar)) <= 0) 460 i = 0; 461 else 462 i = rbuf[ip & (BLK-1)]; 463 } else 464 i = rbuf[ip & (BLK-1)]; 465 #else 466 i = corebuf[ip]; 467 #endif 468 /* end of rbf0 */ 469 if (i == 0) { 470 if (!app) 471 i = popi(); 472 return(i); 473 } 474 /* this is an inline expansion of incoff: also dirty */ 475 p = ++ip; 476 if ((p & (BLK - 1)) == 0) { 477 if ((ip = blist[blisti(p-1)]) == (unsigned) ~0) { 478 ip = 0; 479 errprint("Bad storage allocation"); 480 done2(-5); 481 } 482 /* this was meant to protect against people removing 483 /* the macro they were standing on, but it's too 484 /* sensitive to block boundaries. 485 /* if (ip == 0) { 486 /* errprint("Block removed while in use"); 487 /* done2(-6); 488 /* } 489 */ 490 } 491 return(i); 492 } 493 494 495 tchar rbf0(p) 496 register filep p; 497 { 498 #ifndef INCORE 499 register filep i; 500 501 if ((i = p & ~(BLK - 1)) != roff) { 502 roff = i; 503 lseek(ibf, (long)roff * sizeof(tchar), 0); 504 if (read(ibf, (char *)rbuf, BLK * sizeof(tchar)) == 0) 505 return(0); 506 } 507 return(rbuf[p & (BLK-1)]); 508 #else 509 return(corebuf[p]); 510 #endif 511 } 512 513 514 filep incoff(p) 515 register filep p; 516 { 517 p++; 518 if ((p & (BLK - 1)) == 0) { 519 if ((p = blist[blisti(p-1)]) == (unsigned) ~0) { 520 errprint("Bad storage allocation"); 521 done2(-5); 522 } 523 } 524 return(p); 525 } 526 527 528 tchar popi() 529 { 530 register struct s *p; 531 532 if (frame == stk) 533 return(0); 534 if (strflg) 535 strflg--; 536 p = nxf = frame; 537 p->nargs = 0; 538 frame = p->pframe; 539 ip = p->pip; 540 pendt = p->ppendt; 541 lastpbp = p->lastpbp; 542 return(p->pch); 543 } 544 545 /* 546 * test that the end of the allocation is above a certain location 547 * in memory 548 */ 549 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);} 550 551 pushi(newip, mname) 552 filep newip; 553 int mname; 554 { 555 register struct s *p; 556 extern char *setbrk(); 557 558 SPACETEST(nxf, sizeof(struct s)); 559 p = nxf; 560 p->pframe = frame; 561 p->pip = ip; 562 p->ppendt = pendt; 563 p->pch = ch; 564 p->lastpbp = lastpbp; 565 p->mname = mname; 566 lastpbp = pbp; 567 pendt = ch = 0; 568 frame = nxf; 569 if (nxf->nargs == 0) 570 nxf += 1; 571 else 572 nxf = (struct s *)argtop; 573 return(ip = newip); 574 } 575 576 577 char *setbrk(x) 578 int x; 579 { 580 register char *i; 581 register j; 582 char *sbrk(); 583 584 if (j = x % sizeof(int)) /*allocate only whole words for 3B*/ 585 x += sizeof(int) - j; 586 if ((i = sbrk(x)) == (char *) -1) { 587 errprint("Core limit reached"); 588 edone(0100); 589 } else { 590 if ((unsigned)i % sizeof(int)) { /*check alignment for 3B*/ 591 errprint("alignment problem"); 592 edone(0100); 593 } 594 enda = i + x; 595 } 596 return(i); 597 } 598 599 600 getsn() 601 { 602 register i; 603 604 if ((i = getach()) == 0) 605 return(0); 606 if (i == '(') 607 return(getrq()); 608 else 609 return(i); 610 } 611 612 613 setstr() 614 { 615 register i, j; 616 617 lgf++; 618 if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contab[j].mx) { 619 lgf--; 620 return(0); 621 } else { 622 SPACETEST(nxf, sizeof(struct s)); 623 nxf->nargs = 0; 624 strflg++; 625 lgf--; 626 return pushi((filep)contab[j].mx, i); 627 } 628 } 629 630 631 632 collect() 633 { 634 register j; 635 register tchar i; 636 register tchar *strp; 637 tchar * lim; 638 tchar * *argpp, **argppend; 639 int quote; 640 struct s *savnxf; 641 642 copyf++; 643 nxf->nargs = 0; 644 savnxf = nxf; 645 if (skip()) 646 goto rtn; 647 648 { 649 char *memp; 650 memp = (char *)savnxf; 651 /* 652 * 1 s structure for the macro descriptor 653 * APERMAC tchar *'s for pointers into the strings 654 * space for the tchar's themselves 655 */ 656 memp += sizeof(struct s); 657 /* 658 * CPERMAC (the total # of characters for ALL arguments) 659 * to a macros, has been carefully chosen 660 * so that the distance between stack frames is < DELTA 661 */ 662 #define CPERMAC 200 663 #define APERMAC 9 664 memp += APERMAC * sizeof(tchar *); 665 memp += CPERMAC * sizeof(tchar); 666 nxf = (struct s*)memp; 667 } 668 lim = (tchar *)nxf; 669 argpp = (tchar **)(savnxf + 1); 670 argppend = &argpp[APERMAC]; 671 SPACETEST(argppend, sizeof(tchar *)); 672 strp = (tchar *)argppend; 673 /* 674 * Zero out all the string pointers before filling them in. 675 */ 676 for (j = 0; j < APERMAC; j++){ 677 argpp[j] = (tchar *)0; 678 } 679 #if 0 680 errprint("savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x", 681 savnxf, nxf, argpp, strp, lim, enda); 682 #endif 0 683 strflg = 0; 684 while ((argpp != argppend) && (!skip())) { 685 *argpp++ = strp; 686 quote = 0; 687 if (cbits(i = getch()) == '"') 688 quote++; 689 else 690 ch = i; 691 while (1) { 692 i = getch(); 693 if (nlflg || (!quote && cbits(i) == ' ')) 694 break; 695 if ( quote 696 && (cbits(i) == '"') 697 && (cbits(i = getch()) != '"')) { 698 ch = i; 699 break; 700 } 701 *strp++ = i; 702 if (strflg && strp >= lim) { 703 #if 0 704 errprint("strp=0x%x, lim = 0x%x", 705 strp, lim); 706 #endif 0 707 errprint("Macro argument too long"); 708 copyf--; 709 edone(004); 710 } 711 SPACETEST(strp, 3 * sizeof(tchar)); 712 } 713 *strp++ = 0; 714 } 715 nxf = savnxf; 716 nxf->nargs = argpp - (tchar **)(savnxf + 1); 717 argtop = strp; 718 rtn: 719 copyf--; 720 } 721 722 723 seta() 724 { 725 register i; 726 727 i = cbits(getch()) - '0'; 728 if (i > 0 && i <= APERMAC && i <= frame->nargs) 729 pushback(*(((tchar **)(frame + 1)) + i - 1)); 730 } 731 732 733 caseda() 734 { 735 app++; 736 casedi(); 737 } 738 739 740 casedi() 741 { 742 register i, j; 743 register *k; 744 745 lgf++; 746 if (skip() || (i = getrq()) == 0) { 747 if (dip != d) 748 wbt((tchar)0); 749 if (dilev > 0) { 750 numtab[DN].val = dip->dnl; 751 numtab[DL].val = dip->maxl; 752 dip = &d[--dilev]; 753 offset = dip->op; 754 } 755 goto rtn; 756 } 757 if (++dilev == NDI) { 758 --dilev; 759 errprint("Diversions nested too deep"); 760 edone(02); 761 } 762 if (dip != d) 763 wbt((tchar)0); 764 diflg++; 765 dip = &d[dilev]; 766 dip->op = finds(i); 767 dip->curd = i; 768 clrmn(oldmn); 769 k = (int *) & dip->dnl; 770 for (j = 0; j < 10; j++) 771 k[j] = 0; /*not op and curd*/ 772 rtn: 773 app = 0; 774 diflg = 0; 775 } 776 777 778 casedt() 779 { 780 lgf++; 781 dip->dimac = dip->ditrap = dip->ditf = 0; 782 skip(); 783 dip->ditrap = vnumb((int *)0); 784 if (nonumb) 785 return; 786 skip(); 787 dip->dimac = getrq(); 788 } 789 790 791 casetl() 792 { 793 register j; 794 int w[3]; 795 tchar buf[LNSIZE]; 796 register tchar *tp; 797 tchar i, delim; 798 799 dip->nls = 0; 800 skip(); 801 if (ismot(delim = getch())) { 802 ch = delim; 803 delim = '\''; 804 } else 805 delim = cbits(delim); 806 tp = buf; 807 numtab[HP].val = 0; 808 w[0] = w[1] = w[2] = 0; 809 j = 0; 810 while (cbits(i = getch()) != '\n') { 811 if (cbits(i) == cbits(delim)) { 812 if (j < 3) 813 w[j] = numtab[HP].val; 814 numtab[HP].val = 0; 815 j++; 816 *tp++ = 0; 817 } else { 818 if (cbits(i) == pagech) { 819 setn1(numtab[PN].val, numtab[findr('%')].fmt, 820 i&SFMASK); 821 continue; 822 } 823 numtab[HP].val += width(i); 824 if (tp < &buf[LNSIZE-10]) 825 *tp++ = i; 826 } 827 } 828 if (j<3) 829 w[j] = numtab[HP].val; 830 *tp++ = 0; 831 *tp++ = 0; 832 *tp++ = 0; 833 tp = buf; 834 #ifdef NROFF 835 horiz(po); 836 #endif 837 while (i = *tp++) 838 pchar(i); 839 if (w[1] || w[2]) 840 horiz(j = quant((lt - w[1]) / 2 - w[0], HOR)); 841 while (i = *tp++) 842 pchar(i); 843 if (w[2]) { 844 horiz(lt - w[0] - w[1] - w[2] - j); 845 while (i = *tp++) 846 pchar(i); 847 } 848 newline(0); 849 if (dip != d) { 850 if (dip->dnl > dip->hnl) 851 dip->hnl = dip->dnl; 852 } else { 853 if (numtab[NL].val > dip->hnl) 854 dip->hnl = numtab[NL].val; 855 } 856 } 857 858 859 casepc() 860 { 861 pagech = chget(IMP); 862 } 863 864 865 casepm() 866 { 867 register i, k; 868 register char *p; 869 int xx, cnt, tcnt, kk, tot; 870 filep j; 871 char pmline[10]; 872 873 kk = cnt = tcnt = 0; 874 tot = !skip(); 875 for (i = 0; i < NM; i++) { 876 if (!(xx = contab[i].rq)) 877 continue; 878 tcnt++; 879 p = pmline; 880 j = (filep) contab[i].mx; 881 k = 1; 882 while ((j = blist[blisti(j)]) != (unsigned) ~0) { 883 k++; 884 } 885 cnt++; 886 kk += k; 887 if (!tot) { 888 *p++ = xx & 0177; 889 if (!(*p++ = (xx >> BYTE) & 0177)) 890 *(p - 1) = ' '; 891 *p++ = 0; 892 fdprintf(stderr, "%s %d\n", pmline, k); 893 } 894 } 895 fdprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk); 896 } 897 898 stackdump() /* dumps stack of macros in process */ 899 { 900 struct s *p; 901 902 if (p != stk) { 903 for (p = frame; p != stk; p = p->pframe) 904 fdprintf(stderr, "%c%c ", p->mname&0177, (p->mname>>BYTE)&0177); 905 fdprintf(stderr, "\n"); 906 } 907 } 908