n3.c (16259B)
1 /* 2 * troff3.c 3 * 4 * macro and string routines, storage allocation 5 */ 6 7 #include "tdef.h" 8 #include "fns.h" 9 #include "ext.h" 10 11 Tchar *argtop; 12 int pagech = '%'; 13 int strflg; 14 15 #define MHASHSIZE 128 /* must be 2**n */ 16 #define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1) 17 Contab *mhash[MHASHSIZE]; 18 19 20 Blockp *blist; /* allocated blocks for macros and strings */ 21 int nblist; /* how many there are */ 22 int bfree = -1; /* first (possible) free block in the list */ 23 24 Contab *contabp = NULL; 25 #define MDELTA 500 26 int nm = 0; 27 28 int savname; /* name of macro/string being defined */ 29 int savslot; /* place in Contab of savname */ 30 int freeslot = -1; /* first (possible) free slot in contab */ 31 32 void prcontab(Contab *p) 33 { 34 int i; 35 for (i = 0; i < nm; i++) 36 if (p) 37 if (p[i].rq != 0) 38 fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq)); 39 else 40 fprintf(stderr, "slot %d empty\n", i); 41 else 42 fprintf(stderr, "slot %d empty\n", i); 43 } 44 45 46 void blockinit(void) 47 { 48 blist = (Blockp *) calloc(NBLIST, sizeof(Blockp)); 49 if (blist == NULL) { 50 ERROR "not enough room for %d blocks", NBLIST WARN; 51 done2(1); 52 } 53 nblist = NBLIST; 54 blist[0].nextoff = blist[1].nextoff = -1; 55 blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); 56 blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); 57 /* -1 prevents blist[0] from being used; temporary fix */ 58 /* for a design botch: offset==0 is overloaded. */ 59 /* blist[1] reserved for .rd indicator -- also unused. */ 60 /* but someone unwittingly looks at these, so allocate something */ 61 bfree = 2; 62 } 63 64 65 char *grow(char *ptr, int num, int size) /* make array bigger */ 66 { 67 char *p; 68 69 if (ptr == NULL) 70 p = (char *) calloc(num, size); 71 else 72 p = (char *) realloc(ptr, num * size); 73 return p; 74 } 75 76 void mnspace(void) 77 { 78 nm = sizeof(contab)/sizeof(Contab) + MDELTA; 79 freeslot = sizeof(contab)/sizeof(Contab) + 1; 80 contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab)); 81 if (contabp == NULL) { 82 ERROR "not enough memory for namespace of %d marcos", nm WARN; 83 exit(1); 84 } 85 contabp = (Contab *) memcpy((char *) contabp, (char *)contab, 86 sizeof(contab)); 87 if (contabp == NULL) { 88 ERROR "Cannot reinitialize macro/request name list" WARN; 89 exit(1); 90 } 91 92 } 93 94 void caseig(void) 95 { 96 int i; 97 Offset oldoff = offset; 98 99 offset = 0; 100 i = copyb(); 101 offset = oldoff; 102 if (i != '.') 103 control(i, 1); 104 } 105 106 107 void casern(void) 108 { 109 int i, j, k; 110 111 lgf++; 112 skip(); 113 if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0) 114 return; 115 skip(); 116 clrmn(findmn(j = getrq())); 117 if (j) { 118 munhash(&contabp[oldmn]); 119 contabp[oldmn].rq = j; 120 maddhash(&contabp[oldmn]); 121 if (dip != d ) 122 for (k = dilev; k; k--) 123 if (d[k].curd == i) 124 d[k].curd = j; 125 } 126 } 127 128 void maddhash(Contab *rp) 129 { 130 Contab **hp; 131 132 if (rp->rq == 0) 133 return; 134 hp = &mhash[MHASH(rp->rq)]; 135 rp->link = *hp; 136 *hp = rp; 137 } 138 139 void munhash(Contab *mp) 140 { 141 Contab *p; 142 Contab **lp; 143 144 if (mp->rq == 0) 145 return; 146 lp = &mhash[MHASH(mp->rq)]; 147 p = *lp; 148 while (p) { 149 if (p == mp) { 150 *lp = p->link; 151 p->link = 0; 152 return; 153 } 154 lp = &p->link; 155 p = p->link; 156 } 157 } 158 159 void mrehash(void) 160 { 161 Contab *p; 162 int i; 163 164 for (i=0; i < MHASHSIZE; i++) 165 mhash[i] = 0; 166 for (p=contabp; p < &contabp[nm]; p++) 167 p->link = 0; 168 for (p=contabp; p < &contabp[nm]; p++) { 169 if (p->rq == 0) 170 continue; 171 i = MHASH(p->rq); 172 p->link = mhash[i]; 173 mhash[i] = p; 174 } 175 } 176 177 void caserm(void) 178 { 179 int j; 180 int k = 0; 181 182 lgf++; 183 g0: 184 while (!skip() && (j = getrq()) != 0) { 185 if (dip != d) 186 for (k = dilev; k; k--) 187 if (d[k].curd == j) { 188 ERROR "cannot remove diversion %s during definition", 189 unpair(j) WARN; 190 goto g0; 191 } 192 clrmn(findmn(j)); 193 } 194 lgf--; 195 } 196 197 198 void caseas(void) 199 { 200 app++; 201 caseds(); 202 } 203 204 205 void caseds(void) 206 { 207 ds++; 208 casede(); 209 } 210 211 212 void caseam(void) 213 { 214 app++; 215 casede(); 216 } 217 218 219 void casede(void) 220 { 221 int i, req; 222 Offset savoff; 223 224 req = '.'; 225 lgf++; 226 skip(); 227 if ((i = getrq()) == 0) 228 goto de1; 229 if ((offset = finds(i)) == 0) 230 goto de1; 231 if (newmn) 232 savslot = newmn; 233 else 234 savslot = findmn(i); 235 savname = i; 236 if (ds) 237 copys(); 238 else 239 req = copyb(); 240 clrmn(oldmn); 241 if (newmn) { 242 if (contabp[newmn].rq) 243 munhash(&contabp[newmn]); 244 contabp[newmn].rq = i; 245 maddhash(&contabp[newmn]); 246 247 } 248 if (apptr) { 249 savoff = offset; 250 offset = apptr; 251 wbf((Tchar) IMP); 252 offset = savoff; 253 } 254 offset = dip->op; 255 if (req != '.') 256 control(req, 1); 257 de1: 258 ds = app = 0; 259 } 260 261 262 int findmn(int i) 263 { 264 Contab *p; 265 266 for (p = mhash[MHASH(i)]; p; p = p->link) 267 if (i == p->rq) 268 return(p - contabp); 269 return(-1); 270 } 271 272 273 void clrmn(int i) 274 { 275 if (i >= 0) { 276 if (contabp[i].mx) 277 ffree(contabp[i].mx); 278 munhash(&contabp[i]); 279 contabp[i].rq = 0; 280 contabp[i].mx = 0; 281 contabp[i].emx = 0; 282 contabp[i].f = 0; 283 if (contabp[i].divsiz != NULL) { 284 free(contabp[i].divsiz); 285 contabp[i].divsiz = NULL; 286 } 287 if (freeslot > i) 288 freeslot = i; 289 } 290 } 291 292 void growcontab(void) 293 { 294 nm += MDELTA; 295 contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab)); 296 if (contabp == NULL) { 297 ERROR "Too many (%d) string/macro names", nm WARN; 298 done2(02); 299 } else { 300 memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab), 301 0, MDELTA * sizeof(Contab)); 302 mrehash(); 303 } 304 } 305 306 307 Offset finds(int mn) 308 { 309 int i; 310 Offset savip; 311 312 oldmn = findmn(mn); 313 newmn = 0; 314 apptr = 0; 315 if (app && oldmn >= 0 && contabp[oldmn].mx) { 316 savip = ip; 317 ip = contabp[oldmn].emx; 318 oldmn = -1; 319 apptr = ip; 320 if (!diflg) 321 ip = incoff(ip); 322 nextb = ip; 323 ip = savip; 324 } else { 325 for (i = freeslot; i < nm; i++) { 326 if (contabp[i].rq == 0) 327 break; 328 } 329 if (i == nm) 330 growcontab(); 331 freeslot = i + 1; 332 if ((nextb = alloc()) == -1) { 333 app = 0; 334 if (macerr++ > 1) 335 done2(02); 336 if (nextb == 0) 337 ERROR "Not enough space for string/macro names" WARN; 338 edone(04); 339 return(offset = 0); 340 } 341 contabp[i].mx = nextb; 342 if (!diflg) { 343 newmn = i; 344 if (oldmn == -1) 345 contabp[i].rq = -1; 346 } else { 347 contabp[i].rq = mn; 348 maddhash(&contabp[i]); 349 } 350 } 351 app = 0; 352 return(offset = nextb); 353 } 354 355 int skip(void) 356 { 357 Tchar i; 358 359 while (cbits(i = getch()) == ' ' || ismot(i)) 360 ; 361 ch = i; 362 return(nlflg); 363 } 364 365 366 int copyb(void) 367 { 368 int i, j, state; 369 Tchar ii; 370 int req, k; 371 Offset savoff; 372 Uchar *p; 373 374 savoff = 0; 375 if (skip() || !(j = getrq())) 376 j = '.'; 377 req = j; 378 p = unpair(j); 379 /* was: k = j >> BYTE; j &= BYTEMASK; */ 380 j = p[0]; 381 k = p[1]; 382 copyf++; 383 flushi(); 384 nlflg = 0; 385 state = 1; 386 387 /* state 0 eat up 388 * state 1 look for . 389 * state 2 look for first char of end macro 390 * state 3 look for second char of end macro 391 */ 392 393 while (1) { 394 i = cbits(ii = getch()); 395 if (state == 3) { 396 if (i == k) 397 break; 398 if (!k) { 399 ch = ii; 400 i = getach(); 401 ch = ii; 402 if (!i) 403 break; 404 } 405 state = 0; 406 goto c0; 407 } 408 if (i == '\n') { 409 state = 1; 410 nlflg = 0; 411 goto c0; 412 } 413 if (state == 1 && i == '.') { 414 state++; 415 savoff = offset; 416 goto c0; 417 } 418 if (state == 2 && i == j) { 419 state++; 420 goto c0; 421 } 422 state = 0; 423 c0: 424 if (offset) 425 wbf(ii); 426 } 427 if (offset) { 428 offset = savoff; 429 wbf((Tchar)0); 430 } 431 copyf--; 432 return(req); 433 } 434 435 436 void copys(void) 437 { 438 Tchar i; 439 440 copyf++; 441 if (skip()) 442 goto c0; 443 if (cbits(i = getch()) != '"') 444 wbf(i); 445 while (cbits(i = getch()) != '\n') 446 wbf(i); 447 c0: 448 wbf((Tchar)0); 449 copyf--; 450 } 451 452 453 Offset alloc(void) /* return free Offset in nextb */ 454 { 455 int i, j; 456 457 for (i = bfree; i < nblist; i++) 458 if (blist[i].nextoff == 0) 459 break; 460 if (i == nblist) { 461 blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp)); 462 if (blist == NULL) { 463 ERROR "can't grow blist for string/macro defns" WARN; 464 done2(2); 465 } 466 nblist *= 2; 467 for (j = i; j < nblist; j++) { 468 blist[j].nextoff = 0; 469 blist[j].bp = 0; 470 } 471 } 472 blist[i].nextoff = -1; /* this block is the end */ 473 bfree = i + 1; 474 if (blist[i].bp == 0) 475 blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar)); 476 if (blist[i].bp == NULL) { 477 ERROR "can't allocate memory for string/macro definitions" WARN; 478 done2(2); 479 } 480 nextb = (Offset) i * BLK; 481 return nextb; 482 } 483 484 485 void ffree(Offset i) /* free list of blocks starting at blist(o) */ 486 { /* (doesn't actually free the blocks, just the pointers) */ 487 int j; 488 489 for ( ; blist[j = bindex(i)].nextoff != -1; ) { 490 if (bfree > j) 491 bfree = j; 492 i = blist[j].nextoff; 493 blist[j].nextoff = 0; 494 } 495 blist[j].nextoff = 0; 496 } 497 498 499 void wbf(Tchar i) /* store i into offset, get ready for next one */ 500 { 501 int j, off; 502 503 if (!offset) 504 return; 505 j = bindex(offset); 506 if (i == 0) 507 contabp[savslot].emx = offset; 508 off = boffset(offset); 509 blist[j].bp[off++] = i; 510 offset++; 511 if (pastend(offset)) { /* off the end of this block */ 512 if (blist[j].nextoff == -1) { 513 if ((nextb = alloc()) == -1) { 514 ERROR "Out of temp file space" WARN; 515 done2(01); 516 } 517 blist[j].nextoff = nextb; 518 } 519 offset = blist[j].nextoff; 520 } 521 } 522 523 524 Tchar rbf(void) /* return next char from blist[] block */ 525 { 526 Tchar i, j; 527 528 if (ip == RD_OFFSET) { /* for rdtty */ 529 if (j = rdtty()) 530 return(j); 531 else 532 return(popi()); 533 } 534 535 i = rbf0(ip); 536 if (i == 0) { 537 if (!app) 538 i = popi(); 539 return(i); 540 } 541 ip = incoff(ip); 542 return(i); 543 } 544 545 546 Offset xxxincoff(Offset p) /* get next blist[] block */ 547 { 548 p++; 549 if (pastend(p)) { /* off the end of this block */ 550 if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and nothing was allocated after it */ 551 ERROR "Bad storage allocation" WARN; 552 done2(-5); 553 } 554 } 555 return(p); 556 } 557 558 559 Tchar popi(void) 560 { 561 Stack *p; 562 563 if (frame == stk) 564 return(0); 565 if (strflg) 566 strflg--; 567 p = nxf = frame; 568 p->nargs = 0; 569 frame = p->pframe; 570 ip = p->pip; 571 pendt = p->ppendt; 572 lastpbp = p->lastpbp; 573 return(p->pch); 574 } 575 576 /* 577 * test that the end of the allocation is above a certain location 578 * in memory 579 */ 580 #define SPACETEST(base, size) \ 581 if ((char*)base + size >= (char*)stk+STACKSIZE) \ 582 ERROR "Stacksize overflow in n3" WARN 583 584 Offset pushi(Offset newip, int mname) 585 { 586 Stack *p; 587 588 SPACETEST(nxf, sizeof(Stack)); 589 p = nxf; 590 p->pframe = frame; 591 p->pip = ip; 592 p->ppendt = pendt; 593 p->pch = ch; 594 p->lastpbp = lastpbp; 595 p->mname = mname; 596 lastpbp = pbp; 597 pendt = ch = 0; 598 frame = nxf; 599 if (nxf->nargs == 0) 600 nxf += 1; 601 else 602 nxf = (Stack *)argtop; 603 return(ip = newip); 604 } 605 606 607 void *setbrk(int x) 608 { 609 char *i; 610 611 if ((i = (char *) calloc(x, 1)) == 0) { 612 ERROR "Core limit reached" WARN; 613 edone(0100); 614 } 615 return(i); 616 } 617 618 619 int getsn(void) 620 { 621 int i; 622 623 if ((i = getach()) == 0) 624 return(0); 625 if (i == '(') 626 return(getrq()); 627 else 628 return(i); 629 } 630 631 632 Offset setstr(void) 633 { 634 int i, j; 635 636 lgf++; 637 if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) { 638 lgf--; 639 return(0); 640 } else { 641 SPACETEST(nxf, sizeof(Stack)); 642 nxf->nargs = 0; 643 strflg++; 644 lgf--; 645 return pushi(contabp[j].mx, i); 646 } 647 } 648 649 650 651 void collect(void) 652 { 653 int j; 654 Tchar i, *strp, *lim, **argpp, **argppend; 655 int quote; 656 Stack *savnxf; 657 658 copyf++; 659 nxf->nargs = 0; 660 savnxf = nxf; 661 if (skip()) 662 goto rtn; 663 664 { 665 char *memp; 666 memp = (char *)savnxf; 667 /* 668 * 1 s structure for the macro descriptor 669 * APERMAC Tchar *'s for pointers into the strings 670 * space for the Tchar's themselves 671 */ 672 memp += sizeof(Stack); 673 /* 674 * CPERMAC = the total # of characters for ALL arguments 675 */ 676 #define CPERMAC 200 677 #define APERMAC 9 678 memp += APERMAC * sizeof(Tchar *); 679 memp += CPERMAC * sizeof(Tchar); 680 nxf = (Stack *)memp; 681 } 682 lim = (Tchar *)nxf; 683 argpp = (Tchar **)(savnxf + 1); 684 argppend = &argpp[APERMAC]; 685 SPACETEST(argppend, sizeof(Tchar *)); 686 strp = (Tchar *)argppend; 687 /* 688 * Zero out all the string pointers before filling them in. 689 */ 690 for (j = 0; j < APERMAC; j++) 691 argpp[j] = 0; 692 /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x", 693 * savnxf, nxf, argpp, strp, lim WARN; 694 */ 695 strflg = 0; 696 while (argpp != argppend && !skip()) { 697 *argpp++ = strp; 698 quote = 0; 699 if (cbits(i = getch()) == '"') 700 quote++; 701 else 702 ch = i; 703 while (1) { 704 i = getch(); 705 /* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */ 706 if (nlflg || (!quote && argpp != argppend && cbits(i) == ' ')) 707 break; /* collects rest into $9 */ 708 if ( quote 709 && cbits(i) == '"' 710 && cbits(i = getch()) != '"') { 711 ch = i; 712 break; 713 } 714 *strp++ = i; 715 if (strflg && strp >= lim) { 716 /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */ 717 ERROR "Macro argument too long" WARN; 718 copyf--; 719 edone(004); 720 } 721 SPACETEST(strp, 3 * sizeof(Tchar)); 722 } 723 *strp++ = 0; 724 } 725 nxf = savnxf; 726 nxf->nargs = argpp - (Tchar **)(savnxf + 1); 727 argtop = strp; 728 rtn: 729 copyf--; 730 } 731 732 733 void seta(void) 734 { 735 int i; 736 737 i = cbits(getch()) - '0'; 738 if (i > 0 && i <= APERMAC && i <= frame->nargs) 739 pushback(*(((Tchar **)(frame + 1)) + i - 1)); 740 } 741 742 743 void caseda(void) 744 { 745 app++; 746 casedi(); 747 } 748 749 void casegd(void) 750 { 751 int i, j; 752 753 skip(); 754 if ((i = getrq()) == 0) 755 return; 756 if ((j = findmn(i)) >= 0) { 757 if (contabp[j].divsiz != NULL) { 758 numtabp[DN].val = contabp[j].divsiz->dix; 759 numtabp[DL].val = contabp[j].divsiz->diy; 760 } 761 } 762 } 763 764 #define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \ 765 ERROR "lost diversion %s", unpair(dip->curd) WARN 766 767 void casedi(void) 768 { 769 int i, j, *k; 770 771 lgf++; 772 if (skip() || (i = getrq()) == 0) { 773 if (dip != d) { 774 FINDDIV(savslot); 775 wbf((Tchar)0); 776 } 777 if (dilev > 0) { 778 numtabp[DN].val = dip->dnl; 779 numtabp[DL].val = dip->maxl; 780 FINDDIV(j); 781 if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) { 782 ERROR "Cannot alloc diversion size" WARN; 783 done2(1); 784 } else { 785 contabp[j].divsiz->dix = numtabp[DN].val; 786 contabp[j].divsiz->diy = numtabp[DL].val; 787 } 788 dip = &d[--dilev]; 789 offset = dip->op; 790 } 791 goto rtn; 792 } 793 if (++dilev == NDI) { 794 --dilev; 795 ERROR "Diversions nested too deep" WARN; 796 edone(02); 797 } 798 if (dip != d) { 799 FINDDIV(j); 800 savslot = j; 801 wbf((Tchar)0); 802 } 803 diflg++; 804 dip = &d[dilev]; 805 dip->op = finds(i); 806 dip->curd = i; 807 clrmn(oldmn); 808 k = (int *) & dip->dnl; 809 for (j = 0; j < 10; j++) 810 k[j] = 0; /*not op and curd*/ 811 rtn: 812 app = 0; 813 diflg = 0; 814 } 815 816 817 void casedt(void) 818 { 819 lgf++; 820 dip->dimac = dip->ditrap = dip->ditf = 0; 821 skip(); 822 dip->ditrap = vnumb((int *)0); 823 if (nonumb) 824 return; 825 skip(); 826 dip->dimac = getrq(); 827 } 828 829 #define LNSIZE 4000 830 void casetl(void) 831 { 832 int j; 833 int w[3]; 834 Tchar buf[LNSIZE]; 835 Tchar *tp; 836 Tchar i, delim; 837 838 /* 839 * bug fix 840 * 841 * if .tl is the first thing in the file, the p1 842 * doesn't come out, also the pagenumber will be 0 843 * 844 * tends too confuse the device filter (and the user as well) 845 */ 846 if (dip == d && numtabp[NL].val == -1) 847 newline(1); 848 dip->nls = 0; 849 skip(); 850 if (ismot(delim = getch())) { 851 ch = delim; 852 delim = '\''; 853 } else 854 delim = cbits(delim); 855 tp = buf; 856 numtabp[HP].val = 0; 857 w[0] = w[1] = w[2] = 0; 858 j = 0; 859 while (cbits(i = getch()) != '\n') { 860 if (cbits(i) == cbits(delim)) { 861 if (j < 3) 862 w[j] = numtabp[HP].val; 863 numtabp[HP].val = 0; 864 if (w[j] != 0) 865 *tp++ = WORDSP; 866 j++; 867 *tp++ = 0; 868 } else { 869 if (cbits(i) == pagech) { 870 setn1(numtabp[PN].val, numtabp[findr('%')].fmt, 871 i&SFMASK); 872 continue; 873 } 874 numtabp[HP].val += width(i); 875 if (tp < &buf[LNSIZE-10]) { 876 if (cbits(i) == ' ' && *tp != WORDSP) 877 *tp++ = WORDSP; 878 *tp++ = i; 879 } else { 880 ERROR "Overflow in casetl" WARN; 881 } 882 } 883 } 884 if (j<3) 885 w[j] = numtabp[HP].val; 886 *tp++ = 0; 887 *tp++ = 0; 888 *tp = 0; 889 tp = buf; 890 if (NROFF) 891 horiz(po); 892 while (i = *tp++) 893 pchar(i); 894 if (w[1] || w[2]) 895 horiz(j = quant((lt - w[1]) / 2 - w[0], HOR)); 896 while (i = *tp++) 897 pchar(i); 898 if (w[2]) { 899 horiz(lt - w[0] - w[1] - w[2] - j); 900 while (i = *tp++) 901 pchar(i); 902 } 903 newline(0); 904 if (dip != d) { 905 if (dip->dnl > dip->hnl) 906 dip->hnl = dip->dnl; 907 } else { 908 if (numtabp[NL].val > dip->hnl) 909 dip->hnl = numtabp[NL].val; 910 } 911 } 912 913 914 void casepc(void) 915 { 916 pagech = chget(IMP); 917 } 918 919 920 void casepm(void) 921 { 922 int i, k; 923 int xx, cnt, tcnt, kk, tot; 924 Offset j; 925 926 kk = cnt = tcnt = 0; 927 tot = !skip(); 928 stackdump(); 929 for (i = 0; i < nm; i++) { 930 if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0) 931 continue; 932 tcnt++; 933 j = contabp[i].mx; 934 for (k = 1; (j = blist[bindex(j)].nextoff) != -1; ) 935 k++; 936 cnt++; 937 kk += k; 938 if (!tot) 939 fprintf(stderr, "%-2.2s %d\n", unpair(xx), k); 940 } 941 fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk); 942 } 943 944 void stackdump(void) /* dumps stack of macros in process */ 945 { 946 Stack *p; 947 948 if (frame != stk) { 949 fprintf(stderr, "stack: "); 950 for (p = frame; p != stk; p = p->pframe) 951 fprintf(stderr, "%s ", unpair(p->mname)); 952 fprintf(stderr, "\n"); 953 } 954 }