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