diff options
Diffstat (limited to 'src/cmd/troff/n3.c')
-rw-r--r-- | src/cmd/troff/n3.c | 954 |
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"); + } +} |