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