aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/troff/n3.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/troff/n3.c')
-rw-r--r--src/cmd/troff/n3.c954
1 files changed, 954 insertions, 0 deletions
diff --git a/src/cmd/troff/n3.c b/src/cmd/troff/n3.c
new file mode 100644
index 00000000..6918d06d
--- /dev/null
+++ b/src/cmd/troff/n3.c
@@ -0,0 +1,954 @@
+/*
+ * troff3.c
+ *
+ * macro and string routines, storage allocation
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+
+Tchar *argtop;
+int pagech = '%';
+int strflg;
+
+#define MHASHSIZE 128 /* must be 2**n */
+#define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1)
+Contab *mhash[MHASHSIZE];
+
+
+Blockp *blist; /* allocated blocks for macros and strings */
+int nblist; /* how many there are */
+int bfree = -1; /* first (possible) free block in the list */
+
+Contab *contabp = NULL;
+#define MDELTA 500
+int nm = 0;
+
+int savname; /* name of macro/string being defined */
+int savslot; /* place in Contab of savname */
+int freeslot = -1; /* first (possible) free slot in contab */
+
+void prcontab(Contab *p)
+{
+ int i;
+ for (i = 0; i < nm; i++)
+ if (p)
+ if (p[i].rq != 0)
+ fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+ else
+ fprintf(stderr, "slot %d empty\n", i);
+}
+
+
+void blockinit(void)
+{
+ blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
+ if (blist == NULL) {
+ ERROR "not enough room for %d blocks", NBLIST WARN;
+ done2(1);
+ }
+ nblist = NBLIST;
+ blist[0].nextoff = blist[1].nextoff = -1;
+ blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ /* -1 prevents blist[0] from being used; temporary fix */
+ /* for a design botch: offset==0 is overloaded. */
+ /* blist[1] reserved for .rd indicator -- also unused. */
+ /* but someone unwittingly looks at these, so allocate something */
+ bfree = 2;
+}
+
+
+char *grow(char *ptr, int num, int size) /* make array bigger */
+{
+ char *p, new;
+
+ if (ptr == NULL)
+ p = (char *) calloc(num, size);
+ else
+ p = (char *) realloc(ptr, num * size);
+ return p;
+}
+
+void mnspace(void)
+{
+ nm = sizeof(contab)/sizeof(Contab) + MDELTA;
+ freeslot = sizeof(contab)/sizeof(Contab) + 1;
+ contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
+ if (contabp == NULL) {
+ ERROR "not enough memory for namespace of %d marcos", nm WARN;
+ exit(1);
+ }
+ contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
+ sizeof(contab));
+ if (contabp == NULL) {
+ ERROR "Cannot reinitialize macro/request name list" WARN;
+ exit(1);
+ }
+
+}
+
+void caseig(void)
+{
+ int i;
+ Offset oldoff = offset;
+
+ offset = 0;
+ i = copyb();
+ offset = oldoff;
+ if (i != '.')
+ control(i, 1);
+}
+
+
+void casern(void)
+{
+ int i, j, k;
+
+ lgf++;
+ skip();
+ if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
+ return;
+ skip();
+ clrmn(findmn(j = getrq()));
+ if (j) {
+ munhash(&contabp[oldmn]);
+ contabp[oldmn].rq = j;
+ maddhash(&contabp[oldmn]);
+ if (dip != d )
+ for (k = dilev; k; k--)
+ if (d[k].curd == i)
+ d[k].curd = j;
+ }
+}
+
+void maddhash(Contab *rp)
+{
+ Contab **hp;
+
+ if (rp->rq == 0)
+ return;
+ hp = &mhash[MHASH(rp->rq)];
+ rp->link = *hp;
+ *hp = rp;
+}
+
+void munhash(Contab *mp)
+{
+ Contab *p;
+ Contab **lp;
+
+ if (mp->rq == 0)
+ return;
+ lp = &mhash[MHASH(mp->rq)];
+ p = *lp;
+ while (p) {
+ if (p == mp) {
+ *lp = p->link;
+ p->link = 0;
+ return;
+ }
+ lp = &p->link;
+ p = p->link;
+ }
+}
+
+void mrehash(void)
+{
+ Contab *p;
+ int i;
+
+ for (i=0; i < MHASHSIZE; i++)
+ mhash[i] = 0;
+ for (p=contabp; p < &contabp[nm]; p++)
+ p->link = 0;
+ for (p=contabp; p < &contabp[nm]; p++) {
+ if (p->rq == 0)
+ continue;
+ i = MHASH(p->rq);
+ p->link = mhash[i];
+ mhash[i] = p;
+ }
+}
+
+void caserm(void)
+{
+ int j;
+ int k = 0;
+
+ lgf++;
+g0:
+ while (!skip() && (j = getrq()) != 0) {
+ if (dip != d)
+ for (k = dilev; k; k--)
+ if (d[k].curd == j) {
+ ERROR "cannot remove diversion %s during definition",
+ unpair(j) WARN;
+ goto g0;
+ }
+ clrmn(findmn(j));
+ }
+ lgf--;
+}
+
+
+void caseas(void)
+{
+ app++;
+ caseds();
+}
+
+
+void caseds(void)
+{
+ ds++;
+ casede();
+}
+
+
+void caseam(void)
+{
+ app++;
+ casede();
+}
+
+
+void casede(void)
+{
+ int i, req;
+ Offset savoff;
+
+ req = '.';
+ lgf++;
+ skip();
+ if ((i = getrq()) == 0)
+ goto de1;
+ if ((offset = finds(i)) == 0)
+ goto de1;
+ if (newmn)
+ savslot = newmn;
+ else
+ savslot = findmn(i);
+ savname = i;
+ if (ds)
+ copys();
+ else
+ req = copyb();
+ clrmn(oldmn);
+ if (newmn) {
+ if (contabp[newmn].rq)
+ munhash(&contabp[newmn]);
+ contabp[newmn].rq = i;
+ maddhash(&contabp[newmn]);
+
+ }
+ if (apptr) {
+ savoff = offset;
+ offset = apptr;
+ wbf((Tchar) IMP);
+ offset = savoff;
+ }
+ offset = dip->op;
+ if (req != '.')
+ control(req, 1);
+de1:
+ ds = app = 0;
+}
+
+
+int findmn(int i)
+{
+ Contab *p;
+
+ for (p = mhash[MHASH(i)]; p; p = p->link)
+ if (i == p->rq)
+ return(p - contabp);
+ return(-1);
+}
+
+
+void clrmn(int i)
+{
+ if (i >= 0) {
+ if (contabp[i].mx)
+ ffree(contabp[i].mx);
+ munhash(&contabp[i]);
+ contabp[i].rq = 0;
+ contabp[i].mx = 0;
+ contabp[i].emx = 0;
+ contabp[i].f = 0;
+ if (contabp[i].divsiz != NULL) {
+ free(contabp[i].divsiz);
+ contabp[i].divsiz = NULL;
+ }
+ if (freeslot > i)
+ freeslot = i;
+ }
+}
+
+void growcontab(void)
+{
+ nm += MDELTA;
+ contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
+ if (contabp == NULL) {
+ ERROR "Too many (%d) string/macro names", nm WARN;
+ done2(02);
+ } else {
+ memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
+ 0, MDELTA * sizeof(Contab));
+ mrehash();
+ }
+}
+
+
+Offset finds(int mn)
+{
+ int i;
+ Tchar j = IMP;
+ Offset savip;
+
+ oldmn = findmn(mn);
+ newmn = 0;
+ apptr = 0;
+ if (app && oldmn >= 0 && contabp[oldmn].mx) {
+ savip = ip;
+ ip = contabp[oldmn].emx;
+ oldmn = -1;
+ apptr = ip;
+ if (!diflg)
+ ip = incoff(ip);
+ nextb = ip;
+ ip = savip;
+ } else {
+ for (i = freeslot; i < nm; i++) {
+ if (contabp[i].rq == 0)
+ break;
+ }
+ if (i == nm)
+ growcontab();
+ freeslot = i + 1;
+ if ((nextb = alloc()) == -1) {
+ app = 0;
+ if (macerr++ > 1)
+ done2(02);
+ if (nextb == 0)
+ ERROR "Not enough space for string/macro names" WARN;
+ edone(04);
+ return(offset = 0);
+ }
+ contabp[i].mx = nextb;
+ if (!diflg) {
+ newmn = i;
+ if (oldmn == -1)
+ contabp[i].rq = -1;
+ } else {
+ contabp[i].rq = mn;
+ maddhash(&contabp[i]);
+ }
+ }
+ app = 0;
+ return(offset = nextb);
+}
+
+int skip(void)
+{
+ Tchar i;
+
+ while (cbits(i = getch()) == ' ' || ismot(i))
+ ;
+ ch = i;
+ return(nlflg);
+}
+
+
+int copyb(void)
+{
+ int i, j, state;
+ Tchar ii;
+ int req, k;
+ Offset savoff;
+ Uchar *p;
+
+ if (skip() || !(j = getrq()))
+ j = '.';
+ req = j;
+ p = unpair(j);
+ /* was: k = j >> BYTE; j &= BYTEMASK; */
+ j = p[0];
+ k = p[1];
+ copyf++;
+ flushi();
+ nlflg = 0;
+ state = 1;
+
+/* state 0 eat up
+ * state 1 look for .
+ * state 2 look for first char of end macro
+ * state 3 look for second char of end macro
+ */
+
+ while (1) {
+ i = cbits(ii = getch());
+ if (state == 3) {
+ if (i == k)
+ break;
+ if (!k) {
+ ch = ii;
+ i = getach();
+ ch = ii;
+ if (!i)
+ break;
+ }
+ state = 0;
+ goto c0;
+ }
+ if (i == '\n') {
+ state = 1;
+ nlflg = 0;
+ goto c0;
+ }
+ if (state == 1 && i == '.') {
+ state++;
+ savoff = offset;
+ goto c0;
+ }
+ if (state == 2 && i == j) {
+ state++;
+ goto c0;
+ }
+ state = 0;
+c0:
+ if (offset)
+ wbf(ii);
+ }
+ if (offset) {
+ offset = savoff;
+ wbf((Tchar)0);
+ }
+ copyf--;
+ return(req);
+}
+
+
+void copys(void)
+{
+ Tchar i;
+
+ copyf++;
+ if (skip())
+ goto c0;
+ if (cbits(i = getch()) != '"')
+ wbf(i);
+ while (cbits(i = getch()) != '\n')
+ wbf(i);
+c0:
+ wbf((Tchar)0);
+ copyf--;
+}
+
+
+Offset alloc(void) /* return free Offset in nextb */
+{
+ int i, j;
+
+ for (i = bfree; i < nblist; i++)
+ if (blist[i].nextoff == 0)
+ break;
+ if (i == nblist) {
+ blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
+ if (blist == NULL) {
+ ERROR "can't grow blist for string/macro defns" WARN;
+ done2(2);
+ }
+ nblist *= 2;
+ for (j = i; j < nblist; j++) {
+ blist[j].nextoff = 0;
+ blist[j].bp = 0;
+ }
+ }
+ blist[i].nextoff = -1; /* this block is the end */
+ bfree = i + 1;
+ if (blist[i].bp == 0)
+ blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
+ if (blist[i].bp == NULL) {
+ ERROR "can't allocate memory for string/macro definitions" WARN;
+ done2(2);
+ }
+ nextb = (Offset) i * BLK;
+ return nextb;
+}
+
+
+void ffree(Offset i) /* free list of blocks starting at blist(o) */
+{ /* (doesn't actually free the blocks, just the pointers) */
+ int j;
+
+ for ( ; blist[j = bindex(i)].nextoff != -1; ) {
+ if (bfree > j)
+ bfree = j;
+ i = blist[j].nextoff;
+ blist[j].nextoff = 0;
+ }
+ blist[j].nextoff = 0;
+}
+
+
+void wbf(Tchar i) /* store i into offset, get ready for next one */
+{
+ int j, off;
+
+ if (!offset)
+ return;
+ j = bindex(offset);
+ if (i == 0)
+ contabp[savslot].emx = offset;
+ off = boffset(offset);
+ blist[j].bp[off++] = i;
+ offset++;
+ if (pastend(offset)) { /* off the end of this block */
+ if (blist[j].nextoff == -1) {
+ if ((nextb = alloc()) == -1) {
+ ERROR "Out of temp file space" WARN;
+ done2(01);
+ }
+ blist[j].nextoff = nextb;
+ }
+ offset = blist[j].nextoff;
+ }
+}
+
+
+Tchar rbf(void) /* return next char from blist[] block */
+{
+ Tchar i, j;
+
+ if (ip == RD_OFFSET) { /* for rdtty */
+ if (j = rdtty())
+ return(j);
+ else
+ return(popi());
+ }
+
+ i = rbf0(ip);
+ if (i == 0) {
+ if (!app)
+ i = popi();
+ return(i);
+ }
+ ip = incoff(ip);
+ return(i);
+}
+
+
+Offset xxxincoff(Offset p) /* get next blist[] block */
+{
+ p++;
+ if (pastend(p)) { /* off the end of this block */
+ if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and nothing was allocated after it */
+ ERROR "Bad storage allocation" WARN;
+ done2(-5);
+ }
+ }
+ return(p);
+}
+
+
+Tchar popi(void)
+{
+ Stack *p;
+
+ if (frame == stk)
+ return(0);
+ if (strflg)
+ strflg--;
+ p = nxf = frame;
+ p->nargs = 0;
+ frame = p->pframe;
+ ip = p->pip;
+ pendt = p->ppendt;
+ lastpbp = p->lastpbp;
+ return(p->pch);
+}
+
+/*
+ * test that the end of the allocation is above a certain location
+ * in memory
+ */
+#define SPACETEST(base, size) \
+ if ((char*)base + size >= (char*)stk+STACKSIZE) \
+ ERROR "Stacksize overflow in n3" WARN
+
+Offset pushi(Offset newip, int mname)
+{
+ Stack *p;
+
+ SPACETEST(nxf, sizeof(Stack));
+ p = nxf;
+ p->pframe = frame;
+ p->pip = ip;
+ p->ppendt = pendt;
+ p->pch = ch;
+ p->lastpbp = lastpbp;
+ p->mname = mname;
+ lastpbp = pbp;
+ pendt = ch = 0;
+ frame = nxf;
+ if (nxf->nargs == 0)
+ nxf += 1;
+ else
+ nxf = (Stack *)argtop;
+ return(ip = newip);
+}
+
+
+void *setbrk(int x)
+{
+ char *i;
+
+ if ((i = (char *) calloc(x, 1)) == 0) {
+ ERROR "Core limit reached" WARN;
+ edone(0100);
+ }
+ return(i);
+}
+
+
+int getsn(void)
+{
+ int i;
+
+ if ((i = getach()) == 0)
+ return(0);
+ if (i == '(')
+ return(getrq());
+ else
+ return(i);
+}
+
+
+Offset setstr(void)
+{
+ int i, j;
+
+ lgf++;
+ if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
+ lgf--;
+ return(0);
+ } else {
+ SPACETEST(nxf, sizeof(Stack));
+ nxf->nargs = 0;
+ strflg++;
+ lgf--;
+ return pushi(contabp[j].mx, i);
+ }
+}
+
+
+
+void collect(void)
+{
+ int j;
+ Tchar i, *strp, *lim, **argpp, **argppend;
+ int quote;
+ Stack *savnxf;
+
+ copyf++;
+ nxf->nargs = 0;
+ savnxf = nxf;
+ if (skip())
+ goto rtn;
+
+ {
+ char *memp;
+ memp = (char *)savnxf;
+ /*
+ * 1 s structure for the macro descriptor
+ * APERMAC Tchar *'s for pointers into the strings
+ * space for the Tchar's themselves
+ */
+ memp += sizeof(Stack);
+ /*
+ * CPERMAC = the total # of characters for ALL arguments
+ */
+#define CPERMAC 200
+#define APERMAC 9
+ memp += APERMAC * sizeof(Tchar *);
+ memp += CPERMAC * sizeof(Tchar);
+ nxf = (Stack *)memp;
+ }
+ lim = (Tchar *)nxf;
+ argpp = (Tchar **)(savnxf + 1);
+ argppend = &argpp[APERMAC];
+ SPACETEST(argppend, sizeof(Tchar *));
+ strp = (Tchar *)argppend;
+ /*
+ * Zero out all the string pointers before filling them in.
+ */
+ for (j = 0; j < APERMAC; j++)
+ argpp[j] = 0;
+ /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
+ * savnxf, nxf, argpp, strp, lim WARN;
+ */
+ strflg = 0;
+ while (argpp != argppend && !skip()) {
+ *argpp++ = strp;
+ quote = 0;
+ if (cbits(i = getch()) == '"')
+ quote++;
+ else
+ ch = i;
+ while (1) {
+ i = getch();
+/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
+ if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
+ break; /* collects rest into $9 */
+ if ( quote
+ && cbits(i) == '"'
+ && cbits(i = getch()) != '"') {
+ ch = i;
+ break;
+ }
+ *strp++ = i;
+ if (strflg && strp >= lim) {
+ /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
+ ERROR "Macro argument too long" WARN;
+ copyf--;
+ edone(004);
+ }
+ SPACETEST(strp, 3 * sizeof(Tchar));
+ }
+ *strp++ = 0;
+ }
+ nxf = savnxf;
+ nxf->nargs = argpp - (Tchar **)(savnxf + 1);
+ argtop = strp;
+rtn:
+ copyf--;
+}
+
+
+void seta(void)
+{
+ int i;
+
+ i = cbits(getch()) - '0';
+ if (i > 0 && i <= APERMAC && i <= frame->nargs)
+ pushback(*(((Tchar **)(frame + 1)) + i - 1));
+}
+
+
+void caseda(void)
+{
+ app++;
+ casedi();
+}
+
+void casegd(void)
+{
+ int i, j;
+
+ skip();
+ if ((i = getrq()) == 0)
+ return;
+ if ((j = findmn(i)) >= 0) {
+ if (contabp[j].divsiz != NULL) {
+ numtabp[DN].val = contabp[j].divsiz->dix;
+ numtabp[DL].val = contabp[j].divsiz->diy;
+ }
+ }
+}
+
+#define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \
+ ERROR "lost diversion %s", unpair(dip->curd) WARN
+
+void casedi(void)
+{
+ int i, j, *k;
+
+ lgf++;
+ if (skip() || (i = getrq()) == 0) {
+ if (dip != d) {
+ FINDDIV(savslot);
+ wbf((Tchar)0);
+ }
+ if (dilev > 0) {
+ numtabp[DN].val = dip->dnl;
+ numtabp[DL].val = dip->maxl;
+ FINDDIV(j);
+ if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
+ ERROR "Cannot alloc diversion size" WARN;
+ done2(1);
+ } else {
+ contabp[j].divsiz->dix = numtabp[DN].val;
+ contabp[j].divsiz->diy = numtabp[DL].val;
+ }
+ dip = &d[--dilev];
+ offset = dip->op;
+ }
+ goto rtn;
+ }
+ if (++dilev == NDI) {
+ --dilev;
+ ERROR "Diversions nested too deep" WARN;
+ edone(02);
+ }
+ if (dip != d) {
+ FINDDIV(j);
+ savslot = j;
+ wbf((Tchar)0);
+ }
+ diflg++;
+ dip = &d[dilev];
+ dip->op = finds(i);
+ dip->curd = i;
+ clrmn(oldmn);
+ k = (int *) & dip->dnl;
+ for (j = 0; j < 10; j++)
+ k[j] = 0; /*not op and curd*/
+rtn:
+ app = 0;
+ diflg = 0;
+}
+
+
+void casedt(void)
+{
+ lgf++;
+ dip->dimac = dip->ditrap = dip->ditf = 0;
+ skip();
+ dip->ditrap = vnumb((int *)0);
+ if (nonumb)
+ return;
+ skip();
+ dip->dimac = getrq();
+}
+
+#define LNSIZE 4000
+void casetl(void)
+{
+ int j;
+ int w[3];
+ Tchar buf[LNSIZE];
+ Tchar *tp;
+ Tchar i, delim;
+
+ /*
+ * bug fix
+ *
+ * if .tl is the first thing in the file, the p1
+ * doesn't come out, also the pagenumber will be 0
+ *
+ * tends too confuse the device filter (and the user as well)
+ */
+ if (dip == d && numtabp[NL].val == -1)
+ newline(1);
+ dip->nls = 0;
+ skip();
+ if (ismot(delim = getch())) {
+ ch = delim;
+ delim = '\'';
+ } else
+ delim = cbits(delim);
+ tp = buf;
+ numtabp[HP].val = 0;
+ w[0] = w[1] = w[2] = 0;
+ j = 0;
+ while (cbits(i = getch()) != '\n') {
+ if (cbits(i) == cbits(delim)) {
+ if (j < 3)
+ w[j] = numtabp[HP].val;
+ numtabp[HP].val = 0;
+ if (w[j] != 0)
+ *tp++ = WORDSP;
+ j++;
+ *tp++ = 0;
+ } else {
+ if (cbits(i) == pagech) {
+ setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
+ i&SFMASK);
+ continue;
+ }
+ numtabp[HP].val += width(i);
+ if (tp < &buf[LNSIZE-10]) {
+ if (cbits(i) == ' ' && *tp != WORDSP)
+ *tp++ = WORDSP;
+ *tp++ = i;
+ } else {
+ ERROR "Overflow in casetl" WARN;
+ }
+ }
+ }
+ if (j<3)
+ w[j] = numtabp[HP].val;
+ *tp++ = 0;
+ *tp++ = 0;
+ *tp = 0;
+ tp = buf;
+ if (NROFF)
+ horiz(po);
+ while (i = *tp++)
+ pchar(i);
+ if (w[1] || w[2])
+ horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
+ while (i = *tp++)
+ pchar(i);
+ if (w[2]) {
+ horiz(lt - w[0] - w[1] - w[2] - j);
+ while (i = *tp++)
+ pchar(i);
+ }
+ newline(0);
+ if (dip != d) {
+ if (dip->dnl > dip->hnl)
+ dip->hnl = dip->dnl;
+ } else {
+ if (numtabp[NL].val > dip->hnl)
+ dip->hnl = numtabp[NL].val;
+ }
+}
+
+
+void casepc(void)
+{
+ pagech = chget(IMP);
+}
+
+
+void casepm(void)
+{
+ int i, k;
+ int xx, cnt, tcnt, kk, tot;
+ Offset j;
+
+ kk = cnt = tcnt = 0;
+ tot = !skip();
+ stackdump();
+ for (i = 0; i < nm; i++) {
+ if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
+ continue;
+ tcnt++;
+ j = contabp[i].mx;
+ for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
+ k++;
+ cnt++;
+ kk += k;
+ if (!tot)
+ fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
+ }
+ fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
+}
+
+void stackdump(void) /* dumps stack of macros in process */
+{
+ Stack *p;
+
+ if (frame != stk) {
+ fprintf(stderr, "stack: ");
+ for (p = frame; p != stk; p = p->pframe)
+ fprintf(stderr, "%s ", unpair(p->mname));
+ fprintf(stderr, "\n");
+ }
+}