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