| /* |
| * 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; |
| |
| 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; |
| 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; |
| |
| savoff = 0; |
| 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"); |
| } |
| } |