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