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
prcontab(Contab * p)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
blockinit(void)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
grow(char * ptr,int num,int size)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
mnspace(void)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
caseig(void)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
casern(void)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
maddhash(Contab * rp)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
munhash(Contab * mp)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
mrehash(void)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
caserm(void)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
caseas(void)198 void caseas(void)
199 {
200 app++;
201 caseds();
202 }
203
204
caseds(void)205 void caseds(void)
206 {
207 ds++;
208 casede();
209 }
210
211
caseam(void)212 void caseam(void)
213 {
214 app++;
215 casede();
216 }
217
218
casede(void)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
findmn(int i)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
clrmn(int i)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
growcontab(void)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
finds(int mn)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
skip(void)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
copyb(void)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
copys(void)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
alloc(void)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
ffree(Offset i)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
wbf(Tchar i)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
rbf(void)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
xxxincoff(Offset p)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
popi(void)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
pushi(Offset newip,int mname)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
setbrk(int x)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
getsn(void)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
setstr(void)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
collect(void)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
seta(void)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
caseda(void)743 void caseda(void)
744 {
745 app++;
746 casedi();
747 }
748
casegd(void)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
casedi(void)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
casedt(void)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
casetl(void)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
casepc(void)914 void casepc(void)
915 {
916 pagech = chget(IMP);
917 }
918
919
casepm(void)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
stackdump(void)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 }
955