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
caseig()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
casern()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
maddhash(rp)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
munhash(mp)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
mrehash()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
caserm()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
caseas()180 caseas()
181 {
182 app++;
183 caseds();
184
185 return (0);
186 }
187
188
189 int
caseds()190 caseds()
191 {
192 ds++;
193 casede();
194
195 return (0);
196 }
197
198
199 int
caseam()200 caseam()
201 {
202 app++;
203 casede();
204
205 return (0);
206 }
207
208
209 int
casede()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
findmn(i)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
clrmn(i)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
finds(mn)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
skip()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
copyb()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
copys()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
alloc()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
ffree(i)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
wbt(i)482 wbt(i)
483 tchar i;
484 {
485 wbf(i);
486 wbfl();
487
488 return (0);
489 }
490
491
492 int
wbf(i)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
wbfl()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
rbf()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
rbf0(p)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
incoff(p)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
popi()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
pushi(newip,mname)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
setbrk(x)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
getsn()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
setstr()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
collect()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
seta()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
caseda()855 caseda()
856 {
857 app++;
858 casedi();
859
860 return (0);
861 }
862
863
864 int
casedi()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
casedt()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
casetl()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
casepc()993 casepc()
994 {
995 pagech = chget(IMP);
996
997 return (0);
998 }
999
1000
1001 int
casepm()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
stackdump()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