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