1 #ifndef lint 2 static char sccsid[] = "@(#)n3.c 4.3 04/30/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 /* ought to be rounded up by sizeof(int) */ 457 if (x % 2 == 1) 458 x++; 459 if ( (i = sbrk(x)) >= (char *)-1) { 460 prstrfl("Core limit reached.\n"); 461 edone(0100); 462 } else { 463 enda = i + x; 464 } 465 return(i); 466 } 467 468 469 getsn() 470 { 471 register i; 472 473 if ((i = getach()) == 0) 474 return(0); 475 if (i == '(') 476 return(getrq()); 477 else 478 return(i); 479 } 480 481 482 setstr() 483 { 484 register i; 485 486 lgf++; 487 if ( ((i = getsn()) == 0) 488 || ((i = findmn(i)) == -1) 489 || !(contab[i].rq & MMASK)) { 490 lgf--; 491 return(0); 492 } else { 493 SPACETEST(nxf, sizeof(struct s)); 494 nxf->nargs = 0; 495 strflg++; 496 lgf--; 497 return(pushi(((filep)contab[i].x.mx)<<BLKBITS)); 498 } 499 } 500 501 typedef int tchar; 502 #define cbits(x) ((x) & CMASK) 503 504 collect() 505 { 506 register j; 507 tchar i; 508 register tchar *strp; 509 tchar * lim; 510 tchar * *argpp, **argppend; 511 int quote; 512 struct s *savnxf; 513 514 copyf++; 515 nxf->nargs = 0; 516 savnxf = nxf; 517 if (skip()) 518 goto rtn; 519 520 { 521 char *memp; 522 memp = (char *)savnxf; 523 /* 524 * 1 s structure for the macro descriptor 525 * APERMAC tchar *'s for pointers into the strings 526 * space for the tchar's themselves 527 */ 528 memp += sizeof(struct s); 529 /* 530 * CPERMAC (the total # of characters for ALL arguments) 531 * to a macros, has been carefully chosen 532 * so that the distance between stack frames is < DELTA 533 */ 534 #define CPERMAC 200 535 #define APERMAC 9 536 memp += APERMAC * sizeof(tchar *); 537 memp += CPERMAC * sizeof(tchar); 538 nxf = (struct s*)memp; 539 } 540 lim = (tchar *)nxf; 541 argpp = (tchar **)(savnxf + 1); 542 argppend = &argpp[APERMAC]; 543 SPACETEST(argppend, sizeof(tchar *)); 544 strp = (tchar *)argppend; 545 /* 546 * Zero out all the string pointers before filling them in. 547 */ 548 for (j = 0; j < APERMAC; j++){ 549 argpp[j] = (tchar *)0; 550 } 551 #if 0 552 fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n", 553 savnxf, nxf, argpp, strp, lim, enda); 554 #endif 0 555 strflg = 0; 556 while ((argpp != argppend) && (!skip())) { 557 *argpp++ = strp; 558 quote = 0; 559 if (cbits(i = getch()) == '"') 560 quote++; 561 else 562 ch = i; 563 while (1) { 564 i = getch(); 565 if ( nlflg || (!quote && cbits(i) == ' ')) 566 break; 567 if ( quote 568 && (cbits(i) == '"') 569 && (cbits(i = getch()) != '"')) { 570 ch = i; 571 break; 572 } 573 *strp++ = i; 574 if (strflg && (strp >= lim)) { 575 #if 0 576 fprintf(stderr, "strp=0x%x, lim = 0x%x\n", 577 strp, lim); 578 #endif 0 579 prstrfl("Macro argument too long.\n"); 580 copyf--; 581 edone(004); 582 } 583 SPACETEST(strp, 3 * sizeof(tchar)); 584 } 585 *strp++ = 0; 586 } 587 nxf = savnxf; 588 nxf->nargs = argpp - (tchar **)(savnxf + 1); 589 argtop = strp; 590 rtn: 591 copyf--; 592 } 593 594 595 seta() 596 { 597 register i; 598 599 if(((i = (getch() & CMASK) - '0') > 0) && 600 (i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **))); 601 } 602 caseda(){ 603 app++; 604 casedi(); 605 } 606 casedi(){ 607 register i, j; 608 register *k; 609 610 lgf++; 611 if(skip() || ((i=getrq()) == 0)){ 612 if(dip != d)wbt(0); 613 if(dilev > 0){ 614 v.dn = dip->dnl; 615 v.dl = dip->maxl; 616 dip = &d[--dilev]; 617 offset = dip->op; 618 } 619 goto rtn; 620 } 621 if(++dilev == NDI){ 622 --dilev; 623 prstr("Cannot divert.\n"); 624 edone(02); 625 } 626 if(dip != d)wbt(0); 627 diflg++; 628 dip = &d[dilev]; 629 dip->op = finds(i); 630 dip->curd = i; 631 clrmn(oldmn); 632 k = (int *)&dip->dnl; 633 for(j=0; j<10; j++)k[j] = 0; /*not op and curd*/ 634 rtn: 635 app = 0; 636 diflg = 0; 637 } 638 casedt(){ 639 lgf++; 640 dip->dimac = dip->ditrap = dip->ditf = 0; 641 skip(); 642 dip->ditrap = vnumb((int *)0); 643 if(nonumb)return; 644 skip(); 645 dip->dimac = getrq(); 646 } 647 casetl(){ 648 register i, j; 649 int w1, w2, w3, delim; 650 filep begin; 651 extern width(), pchar(); 652 653 dip->nls = 0; 654 skip(); 655 if(dip != d)wbfl(); 656 if((offset = begin = alloc()) == 0)return; 657 if((delim = getch()) & MOT){ 658 ch = delim; 659 delim = '\''; 660 }else delim &= CMASK; 661 if(!nlflg) 662 while(((i = getch()) & CMASK) != '\n'){ 663 if((i & CMASK) == delim)i = IMP; 664 wbf(i); 665 } 666 wbf(IMP);wbf(IMP);wbt(0); 667 668 w1 = hseg(width,begin); 669 w2 = hseg(width,(filep)0); 670 w3 = hseg(width,(filep)0); 671 offset = dip->op; 672 #ifdef NROFF 673 if(!offset)horiz(po); 674 #endif 675 hseg(pchar,begin); 676 if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR)); 677 hseg(pchar,(filep)0); 678 if(w3){ 679 horiz(lt-w1-w2-w3-j); 680 hseg(pchar,(filep)0); 681 } 682 newline(0); 683 if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;} 684 else{if(v.nl > dip->hnl)dip->hnl = v.nl;} 685 ffree(begin); 686 } 687 casepc(){ 688 pagech = chget(IMP); 689 } 690 hseg(f,p) 691 int (*f)(); 692 filep p; 693 { 694 register acc, i; 695 static filep q; 696 697 acc = 0; 698 if(p)q = p; 699 while(1){ 700 i = rbf0(q); 701 q = incoff(q); 702 if(!i || (i == IMP))return(acc); 703 if((i & CMASK) == pagech){ 704 nrbits = i & ~CMASK; 705 nform = fmt[findr('%')]; 706 acc += fnumb(v.pn,f); 707 }else acc += (*f)(i); 708 } 709 } 710 casepm(){ 711 register i, k; 712 register char *p; 713 int xx, cnt, kk, tot; 714 filep j; 715 char *kvt(); 716 char pmline[10]; 717 718 kk = cnt = 0; 719 tot = !skip(); 720 for(i = 0; i<NM; i++){ 721 if(!((xx = contab[i].rq) & MMASK))continue; 722 p = pmline; 723 j = (((filep)contab[i].x.mx)<<BLKBITS); 724 k = 1; 725 while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;} 726 cnt++; 727 kk += k; 728 if(!tot){ 729 *p++ = xx & 0177; 730 if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' '; 731 *p++ = ' '; 732 kvt(k,p); 733 prstr(pmline); 734 } 735 } 736 if(tot || (cnt > 1)){ 737 kvt(kk,pmline); 738 prstr(pmline); 739 } 740 } 741 char *kvt(k,p) 742 int k; 743 char *p; 744 { 745 if(k>=100)*p++ = k/100 + '0'; 746 if(k>=10)*p++ = (k%100)/10 + '0'; 747 *p++ = k%10 + '0'; 748 *p++ = '\n'; 749 *p = 0; 750 return(p); 751 } 752 dummy(){} 753