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