1 #ifndef lint 2 static char sccsid[] = "@(#)n3.c 4.4 06/25/87"; 3 #endif lint 4 5 #include "tdef.h" 6 extern 7 #include "d.h" 8 extern 9 #include "v.h" 10 #ifdef NROFF 11 extern 12 #include "tw.h" 13 #endif 14 #include "sdef.h" 15 16 /* 17 troff3.c 18 19 macro and string routines, storage allocation 20 */ 21 22 unsigned blist[NBLIST]; 23 extern struct s *frame, *stk, *nxf; 24 extern filep ip; 25 extern filep offset; 26 extern filep nextb; 27 extern char *enda; 28 29 extern int ch; 30 extern int ibf; 31 extern int lgf; 32 extern int copyf; 33 extern int ch0; 34 extern int app; 35 extern int ds; 36 extern int nlflg; 37 extern int *argtop; 38 extern int *ap; 39 extern int nchar; 40 extern int pendt; 41 extern int rchar; 42 extern int dilev; 43 extern int nonumb; 44 extern int lt; 45 extern int nrbits; 46 extern int nform; 47 extern int fmt[]; 48 extern int oldmn; 49 extern int newmn; 50 extern int macerr; 51 extern filep apptr; 52 extern int diflg; 53 extern filep woff; 54 extern filep roff; 55 extern int wbfi; 56 extern int po; 57 extern int *cp; 58 extern int xxx; 59 int pagech = '%'; 60 int strflg; 61 extern struct contab { 62 int rq; 63 union { 64 int (*f)(); 65 unsigned mx; 66 }x; 67 }contab[NM]; 68 #ifndef VMUNIX 69 int wbuf[BLK]; 70 int rbuf[BLK]; 71 #else 72 int *wbuf; 73 int *rbuf; 74 int Buf[NBLIST*BLK + NEV*EVS]; 75 #endif 76 77 caseig(){ 78 register i; 79 80 offset = 0; 81 if((i = copyb()) != '.')control(i,1); 82 } 83 casern(){ 84 register i,j; 85 86 lgf++; 87 skip(); 88 if(((i=getrq())==0) || ((oldmn=findmn(i)) < 0))return; 89 skip(); 90 clrmn(findmn(j=getrq())); 91 if(j)contab[oldmn].rq = (contab[oldmn].rq & MMASK) | j; 92 } 93 caserm(){ 94 lgf++; 95 while(!skip()){ 96 clrmn(findmn(getrq())); 97 } 98 } 99 caseas(){ 100 app++; 101 caseds(); 102 } 103 caseds(){ 104 ds++; 105 casede(); 106 } 107 caseam(){ 108 app++; 109 casede(); 110 } 111 casede(){ 112 register i, req; 113 register filep savoff; 114 extern filep finds(); 115 116 if(dip != d)wbfl(); 117 req = '.'; 118 lgf++; 119 skip(); 120 if((i=getrq())==0)goto de1; 121 if((offset=finds(i)) == 0)goto de1; 122 if(ds)copys(); 123 else req = copyb(); 124 wbfl(); 125 clrmn(oldmn); 126 if(newmn)contab[newmn].rq = i | MMASK; 127 if(apptr){ 128 savoff = offset; 129 offset = apptr; 130 wbt(IMP); 131 offset = savoff; 132 } 133 offset = dip->op; 134 if(req != '.')control(req,1); 135 de1: 136 ds = app = 0; 137 return; 138 } 139 findmn(i) 140 int i; 141 { 142 register j; 143 144 for(j=0;j<NM;j++){ 145 if(i == (contab[j].rq & ~MMASK))break; 146 } 147 if(j==NM)j = -1; 148 return(j); 149 } 150 clrmn(i) 151 int i; 152 { 153 extern filep boff(); 154 if(i >= 0){ 155 if(contab[i].rq & MMASK)ffree(((filep)contab[i].x.mx)<<BLKBITS); 156 contab[i].rq = 0; 157 contab[i].x.mx = 0; 158 } 159 } 160 filep finds(mn) 161 int mn; 162 { 163 register i; 164 extern filep boff(); 165 register filep savip; 166 extern filep alloc(); 167 extern filep incoff(); 168 169 oldmn = findmn(mn); 170 newmn = 0; 171 apptr = (filep)0; 172 if(app && (oldmn >= 0) && (contab[oldmn].rq & MMASK)){ 173 savip = ip; 174 ip = (((filep)contab[oldmn].x.mx)<<BLKBITS); 175 oldmn = -1; 176 while((i=rbf()) != 0); 177 apptr = ip; 178 if(!diflg)ip = incoff(ip); 179 nextb = ip; 180 ip = savip; 181 }else{ 182 for(i=0;i<NM;i++){ 183 if(contab[i].rq == 0)break; 184 } 185 if((i==NM) || 186 (nextb = alloc()) == 0){ 187 app = 0; 188 if(macerr++ > 1)done2(02); 189 prstr("Too many string/macro names.\n"); 190 edone(04); 191 return(offset = 0); 192 } 193 contab[i].x.mx = (unsigned)(nextb>>BLKBITS); 194 if(!diflg){ 195 newmn = i; 196 if(oldmn == -1)contab[i].rq = -1; 197 }else{ 198 contab[i].rq = mn | MMASK; 199 } 200 } 201 202 app = 0; 203 return(offset = nextb); 204 } 205 skip(){ 206 register i; 207 208 while(((i=getch()) & CMASK) == ' '); 209 ch=i; 210 return(nlflg); 211 } 212 copyb() 213 { 214 register i, j, k; 215 int ii, req, state; 216 filep savoff; 217 218 if(skip() || !(j=getrq()))j = '.'; 219 req = j; 220 k = j>>BYTE; 221 j &= BMASK; 222 copyf++; 223 flushi(); 224 nlflg = 0; 225 state = 1; 226 while(1){ 227 i = (ii = getch()) & CMASK; 228 if(state == 3){ 229 if(i == k)break; 230 if(!k){ 231 ch = ii; 232 i = getach(); 233 ch = ii; 234 if(!i)break; 235 } 236 state = 0; 237 goto c0; 238 } 239 if(i == '\n'){ 240 state = 1; 241 nlflg = 0; 242 goto c0; 243 } 244 if((state == 1) && (i == '.')){ 245 state++; 246 savoff = offset; 247 goto c0; 248 } 249 if((state == 2) && (i == j)){ 250 state++; 251 goto c0; 252 } 253 state = 0; 254 c0: 255 if(offset)wbf(ii); 256 } 257 if(offset){ 258 wbfl(); 259 offset = savoff; 260 wbt(0); 261 } 262 copyf--; 263 return(req); 264 } 265 copys() 266 { 267 register i; 268 269 copyf++; 270 if(skip())goto c0; 271 if(((i=getch()) & CMASK) != '"')wbf(i); 272 while(((i=getch()) & CMASK) != '\n')wbf(i); 273 c0: 274 wbt(0); 275 copyf--; 276 } 277 filep alloc() 278 { 279 register i; 280 extern filep boff(); 281 filep j; 282 283 for(i=0;i<NBLIST;i++){ 284 if(blist[i] == 0)break; 285 } 286 if(i==NBLIST){ 287 j = 0; 288 }else{ 289 blist[i] = -1; 290 if((j = boff(i)) < NEV*EVS)j = 0; 291 } 292 return(nextb = j); 293 } 294 ffree(i) 295 filep i; 296 { 297 register j; 298 299 while((blist[j = blisti(i)]) != -1){ 300 i = ((filep)blist[j])<<BLKBITS; 301 blist[j] = 0; 302 } 303 blist[j] = 0; 304 } 305 filep boff(i) 306 int i; 307 { 308 return(((filep)i)*BLK + NEV*EVS); 309 } 310 wbt(i) 311 int i; 312 { 313 wbf(i); 314 wbfl(); 315 } 316 wbf(i) 317 int i; 318 { 319 register j; 320 321 if(!offset)return; 322 if(!woff){ 323 woff = offset; 324 #ifdef VMUNIX 325 wbuf = &Buf[woff]; 326 #endif 327 wbfi = 0; 328 } 329 wbuf[wbfi++] = i; 330 if(!((++offset) & (BLK-1))){ 331 wbfl(); 332 if(blist[j = blisti(--offset)] == -1){ 333 if(alloc() == 0){ 334 prstr("Out of temp file space.\n"); 335 done2(01); 336 } 337 blist[j] = (unsigned)(nextb>>BLKBITS); 338 } 339 offset = ((filep)blist[j])<<BLKBITS; 340 } 341 if(wbfi >= BLK)wbfl(); 342 } 343 wbfl(){ 344 if(woff == 0)return; 345 #ifndef VMUNIX 346 lseek(ibf, ((long)woff) * sizeof(int), 0); 347 write(ibf, (char *)wbuf, wbfi * sizeof(int)); 348 #endif 349 if((woff & (~(BLK-1))) == (roff & (~(BLK-1))))roff = -1; 350 woff = 0; 351 } 352 blisti(i) 353 filep i; 354 { 355 return((i-NEV*EVS)/(BLK)); 356 } 357 rbf(){ 358 register i; 359 extern filep incoff(); 360 361 if((i=rbf0(ip)) == 0){ 362 if(!app)i = popi(); 363 }else{ 364 ip = incoff(ip); 365 } 366 return(i); 367 } 368 rbf0(p) 369 filep p; 370 { 371 register filep i; 372 373 if((i = (p & (~(BLK-1)))) != roff){ 374 roff = i; 375 #ifndef VMUNIX 376 lseek(ibf, ((long)roff) * sizeof(int), 0); 377 if(read(ibf, (char *)rbuf, BLK * sizeof(int)) == 0)return(0); 378 #else 379 rbuf = &Buf[roff]; 380 #endif 381 } 382 return(rbuf[p & (BLK-1)]); 383 } 384 filep incoff(p) 385 filep p; 386 { 387 register i; 388 register filep j; 389 if(!((j = (++p)) & (BLK-1))){ 390 if((i = blist[blisti(--p)]) == -1){ 391 prstr("Bad storage allocation.\n"); 392 done2(-5); 393 } 394 j = ((filep)i)<<BLKBITS; 395 } 396 return(j); 397 } 398 popi(){ 399 register struct s *p; 400 401 if(frame == stk)return(0); 402 if(strflg)strflg--; 403 p = nxf = frame; 404 p->nargs = 0; 405 frame = p->pframe; 406 ip = p->pip; 407 nchar = p->pnchar; 408 rchar = p->prchar; 409 pendt = p->ppendt; 410 ap = p->pap; 411 cp = p->pcp; 412 ch0 = p->pch0; 413 return(p->pch); 414 } 415 416 /* 417 * test that the end of the allocation is above a certain location 418 * in memory 419 */ 420 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);} 421 422 pushi(newip) 423 filep newip; 424 { 425 register struct s *p; 426 extern char *setbrk(); 427 428 SPACETEST(nxf, sizeof(struct s)); 429 p = nxf; 430 p->pframe = frame; 431 p->pip = ip; 432 p->pnchar = nchar; 433 p->prchar = rchar; 434 p->ppendt = pendt; 435 p->pap = ap; 436 p->pcp = cp; 437 p->pch0 = ch0; 438 p->pch = ch; 439 cp = ap = 0; 440 nchar = rchar = pendt = ch0 = ch = 0; 441 frame = nxf; 442 if (nxf->nargs == 0) 443 nxf += 1; 444 else 445 nxf = (struct s *)argtop; 446 return(ip = newip); 447 } 448 449 450 char *setbrk(x) 451 int x; 452 { 453 register char *i; 454 char *sbrk(); 455 456 x += sizeof(int) - 1; 457 x &= ~(sizeof(int) - 1); 458 if ((u_int)(i = sbrk(x)) == -1) { 459 prstrfl("Core limit reached.\n"); 460 edone(0100); 461 } else { 462 enda = i + x; 463 } 464 return(i); 465 } 466 467 468 getsn() 469 { 470 register i; 471 472 if ((i = getach()) == 0) 473 return(0); 474 if (i == '(') 475 return(getrq()); 476 else 477 return(i); 478 } 479 480 481 setstr() 482 { 483 register i; 484 485 lgf++; 486 if ( ((i = getsn()) == 0) 487 || ((i = findmn(i)) == -1) 488 || !(contab[i].rq & MMASK)) { 489 lgf--; 490 return(0); 491 } else { 492 SPACETEST(nxf, sizeof(struct s)); 493 nxf->nargs = 0; 494 strflg++; 495 lgf--; 496 return(pushi(((filep)contab[i].x.mx)<<BLKBITS)); 497 } 498 } 499 500 typedef int tchar; 501 #define cbits(x) ((x) & CMASK) 502 503 collect() 504 { 505 register j; 506 tchar i; 507 register tchar *strp; 508 tchar * lim; 509 tchar * *argpp, **argppend; 510 int quote; 511 struct s *savnxf; 512 513 copyf++; 514 nxf->nargs = 0; 515 savnxf = nxf; 516 if (skip()) 517 goto rtn; 518 519 { 520 char *memp; 521 memp = (char *)savnxf; 522 /* 523 * 1 s structure for the macro descriptor 524 * APERMAC tchar *'s for pointers into the strings 525 * space for the tchar's themselves 526 */ 527 memp += sizeof(struct s); 528 /* 529 * CPERMAC (the total # of characters for ALL arguments) 530 * to a macros, has been carefully chosen 531 * so that the distance between stack frames is < DELTA 532 */ 533 #define CPERMAC 200 534 #define APERMAC 9 535 memp += APERMAC * sizeof(tchar *); 536 memp += CPERMAC * sizeof(tchar); 537 nxf = (struct s*)memp; 538 } 539 lim = (tchar *)nxf; 540 argpp = (tchar **)(savnxf + 1); 541 argppend = &argpp[APERMAC]; 542 SPACETEST(argppend, sizeof(tchar *)); 543 strp = (tchar *)argppend; 544 /* 545 * Zero out all the string pointers before filling them in. 546 */ 547 for (j = 0; j < APERMAC; j++){ 548 argpp[j] = (tchar *)0; 549 } 550 #if 0 551 fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n", 552 savnxf, nxf, argpp, strp, lim, enda); 553 #endif 0 554 strflg = 0; 555 while ((argpp != argppend) && (!skip())) { 556 *argpp++ = strp; 557 quote = 0; 558 if (cbits(i = getch()) == '"') 559 quote++; 560 else 561 ch = i; 562 while (1) { 563 i = getch(); 564 if ( nlflg || (!quote && cbits(i) == ' ')) 565 break; 566 if ( quote 567 && (cbits(i) == '"') 568 && (cbits(i = getch()) != '"')) { 569 ch = i; 570 break; 571 } 572 *strp++ = i; 573 if (strflg && (strp >= lim)) { 574 #if 0 575 fprintf(stderr, "strp=0x%x, lim = 0x%x\n", 576 strp, lim); 577 #endif 0 578 prstrfl("Macro argument too long.\n"); 579 copyf--; 580 edone(004); 581 } 582 SPACETEST(strp, 3 * sizeof(tchar)); 583 } 584 *strp++ = 0; 585 } 586 nxf = savnxf; 587 nxf->nargs = argpp - (tchar **)(savnxf + 1); 588 argtop = strp; 589 rtn: 590 copyf--; 591 } 592 593 594 seta() 595 { 596 register i; 597 598 if(((i = (getch() & CMASK) - '0') > 0) && 599 (i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **))); 600 } 601 caseda(){ 602 app++; 603 casedi(); 604 } 605 casedi(){ 606 register i, j; 607 register *k; 608 609 lgf++; 610 if(skip() || ((i=getrq()) == 0)){ 611 if(dip != d)wbt(0); 612 if(dilev > 0){ 613 v.dn = dip->dnl; 614 v.dl = dip->maxl; 615 dip = &d[--dilev]; 616 offset = dip->op; 617 } 618 goto rtn; 619 } 620 if(++dilev == NDI){ 621 --dilev; 622 prstr("Cannot divert.\n"); 623 edone(02); 624 } 625 if(dip != d)wbt(0); 626 diflg++; 627 dip = &d[dilev]; 628 dip->op = finds(i); 629 dip->curd = i; 630 clrmn(oldmn); 631 k = (int *)&dip->dnl; 632 for(j=0; j<10; j++)k[j] = 0; /*not op and curd*/ 633 rtn: 634 app = 0; 635 diflg = 0; 636 } 637 casedt(){ 638 lgf++; 639 dip->dimac = dip->ditrap = dip->ditf = 0; 640 skip(); 641 dip->ditrap = vnumb((int *)0); 642 if(nonumb)return; 643 skip(); 644 dip->dimac = getrq(); 645 } 646 casetl(){ 647 register i, j; 648 int w1, w2, w3, delim; 649 filep begin; 650 extern width(), pchar(); 651 652 dip->nls = 0; 653 skip(); 654 if(dip != d)wbfl(); 655 if((offset = begin = alloc()) == 0)return; 656 if((delim = getch()) & MOT){ 657 ch = delim; 658 delim = '\''; 659 }else delim &= CMASK; 660 if(!nlflg) 661 while(((i = getch()) & CMASK) != '\n'){ 662 if((i & CMASK) == delim)i = IMP; 663 wbf(i); 664 } 665 wbf(IMP);wbf(IMP);wbt(0); 666 667 w1 = hseg(width,begin); 668 w2 = hseg(width,(filep)0); 669 w3 = hseg(width,(filep)0); 670 offset = dip->op; 671 #ifdef NROFF 672 if(!offset)horiz(po); 673 #endif 674 hseg(pchar,begin); 675 if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR)); 676 hseg(pchar,(filep)0); 677 if(w3){ 678 horiz(lt-w1-w2-w3-j); 679 hseg(pchar,(filep)0); 680 } 681 newline(0); 682 if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;} 683 else{if(v.nl > dip->hnl)dip->hnl = v.nl;} 684 ffree(begin); 685 } 686 casepc(){ 687 pagech = chget(IMP); 688 } 689 hseg(f,p) 690 int (*f)(); 691 filep p; 692 { 693 register acc, i; 694 static filep q; 695 696 acc = 0; 697 if(p)q = p; 698 while(1){ 699 i = rbf0(q); 700 q = incoff(q); 701 if(!i || (i == IMP))return(acc); 702 if((i & CMASK) == pagech){ 703 nrbits = i & ~CMASK; 704 nform = fmt[findr('%')]; 705 acc += fnumb(v.pn,f); 706 }else acc += (*f)(i); 707 } 708 } 709 casepm(){ 710 register i, k; 711 register char *p; 712 int xx, cnt, kk, tot; 713 filep j; 714 char *kvt(); 715 char pmline[10]; 716 717 kk = cnt = 0; 718 tot = !skip(); 719 for(i = 0; i<NM; i++){ 720 if(!((xx = contab[i].rq) & MMASK))continue; 721 p = pmline; 722 j = (((filep)contab[i].x.mx)<<BLKBITS); 723 k = 1; 724 while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;} 725 cnt++; 726 kk += k; 727 if(!tot){ 728 *p++ = xx & 0177; 729 if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' '; 730 *p++ = ' '; 731 kvt(k,p); 732 prstr(pmline); 733 } 734 } 735 if(tot || (cnt > 1)){ 736 kvt(kk,pmline); 737 prstr(pmline); 738 } 739 } 740 char *kvt(k,p) 741 int k; 742 char *p; 743 { 744 if(k>=100)*p++ = k/100 + '0'; 745 if(k>=10)*p++ = (k%100)/10 + '0'; 746 *p++ = k%10 + '0'; 747 *p++ = '\n'; 748 *p = 0; 749 return(p); 750 } 751 dummy(){} 752