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