diff options
Diffstat (limited to 'src/cmd/troff/n4.c')
-rw-r--r-- | src/cmd/troff/n4.c | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/src/cmd/troff/n4.c b/src/cmd/troff/n4.c new file mode 100644 index 00000000..3b3698e4 --- /dev/null +++ b/src/cmd/troff/n4.c @@ -0,0 +1,828 @@ +/* + * troff4.c + * + * number registers, conversion, arithmetic + */ + +#include "tdef.h" +#include "fns.h" +#include "ext.h" + + +int regcnt = NNAMES; +int falsef = 0; /* on if inside false branch of if */ + +#define NHASHSIZE 128 /* must be 2**n */ +#define NHASH(i) ((i>>6)^i) & (NHASHSIZE-1) +Numtab *nhash[NHASHSIZE]; + +Numtab *numtabp = NULL; +#define NDELTA 400 +int ncnt = 0; + +void setn(void) +{ + int i, j, f; + Tchar ii; + Uchar *p; + char buf[NTM]; /* for \n(.S */ + + f = nform = 0; + if ((i = cbits(ii = getach())) == '+') + f = 1; + else if (i == '-') + f = -1; + else if (ii) /* don't put it back if it's already back (thanks to jaap) */ + ch = ii; + if (falsef) + f = 0; + if ((i = getsn()) == 0) + return; + p = unpair(i); + if (p[0] == '.') + switch (p[1]) { + case 's': + i = pts; + break; + case 'v': + i = lss; + break; + case 'f': + i = font; + break; + case 'p': + i = pl; + break; + case 't': + i = findt1(); + break; + case 'o': + i = po; + break; + case 'l': + i = ll; + break; + case 'i': + i = in; + break; + case '$': + i = frame->nargs; + break; + case 'A': + i = ascii; + break; + case 'c': + i = numtabp[CD].val; + break; + case 'n': + i = lastl; + break; + case 'a': + i = ralss; + break; + case 'h': + i = dip->hnl; + break; + case 'd': + if (dip != d) + i = dip->dnl; + else + i = numtabp[NL].val; + break; + case 'u': + i = fi; + break; + case 'j': + i = ad + 2 * admod; + break; + case 'w': + i = widthp; + break; + case 'x': + i = nel; + break; + case 'y': + i = un; + break; + case 'T': + i = dotT; + break; /* -Tterm used in nroff */ + case 'V': + i = VERT; + break; + case 'H': + i = HOR; + break; + case 'k': + i = ne; + break; + case 'P': + i = print; + break; + case 'L': + i = ls; + break; + case 'R': /* maximal # of regs that can be addressed */ + i = 255*256 - regcnt; + break; + case 'z': + p = unpair(dip->curd); + *pbp++ = p[1]; /* watch order */ + *pbp++ = p[0]; + return; + case 'b': + i = bdtab[font]; + break; + case 'F': + cpushback(cfname[ifi]); + return; + case 'S': + buf[0] = j = 0; + for( i = 0; tabtab[i] != 0 && i < NTAB; i++) { + if (i > 0) + buf[j++] = ' '; + sprintf(&buf[j], "%d", tabtab[i] & TABMASK); + j = strlen(buf); + if ( tabtab[i] & RTAB) + sprintf(&buf[j], "uR"); + else if (tabtab[i] & CTAB) + sprintf(&buf[j], "uC"); + else + sprintf(&buf[j], "uL"); + j += 2; + } + cpushback(buf); + return; + default: + goto s0; + } + else { +s0: + if ((j = findr(i)) == -1) + i = 0; + else { + i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f; + nform = numtabp[j].fmt; + } + } + setn1(i, nform, (Tchar) 0); +} + +Tchar numbuf[25]; +Tchar *numbufp; + +int wrc(Tchar i) +{ + if (numbufp >= &numbuf[24]) + return(0); + *numbufp++ = i; + return(1); +} + + + +/* insert into input number i, in format form, with size-font bits bits */ +void setn1(int i, int form, Tchar bits) +{ + numbufp = numbuf; + nrbits = bits; + nform = form; + fnumb(i, wrc); + *numbufp = 0; + pushback(numbuf); +} + +void prnumtab(Numtab *p) +{ + int i; + for (i = 0; i < ncnt; i++) + if (p) + if (p[i].r != 0) + fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val); + else + fprintf(stderr, "slot %d empty\n", i); + else + fprintf(stderr, "slot %d empty\n", i); +} + +void nnspace(void) +{ + ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA; + numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab)); + if (numtabp == NULL) { + ERROR "not enough memory for registers (%d)", ncnt WARN; + exit(1); + } + numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab, + sizeof(numtab)); + if (numtabp == NULL) { + ERROR "Cannot initialize registers" WARN; + exit(1); + } +} + +void grownumtab(void) +{ + ncnt += NDELTA; + numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab)); + if (numtabp == NULL) { + ERROR "Too many number registers (%d)", ncnt WARN; + done2(04); + } else { + memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab), + 0, NDELTA * sizeof(Numtab)); + nrehash(); + } +} + +void nrehash(void) +{ + Numtab *p; + int i; + + for (i=0; i<NHASHSIZE; i++) + nhash[i] = 0; + for (p=numtabp; p < &numtabp[ncnt]; p++) + p->link = 0; + for (p=numtabp; p < &numtabp[ncnt]; p++) { + if (p->r == 0) + continue; + i = NHASH(p->r); + p->link = nhash[i]; + nhash[i] = p; + } +} + +void nunhash(Numtab *rp) +{ + Numtab *p; + Numtab **lp; + + if (rp->r == 0) + return; + lp = &nhash[NHASH(rp->r)]; + p = *lp; + while (p) { + if (p == rp) { + *lp = p->link; + p->link = 0; + return; + } + lp = &p->link; + p = p->link; + } +} + +int findr(int i) +{ + Numtab *p; + int h = NHASH(i); + + if (i == 0) + return(-1); +a0: + for (p = nhash[h]; p; p = p->link) + if (i == p->r) + return(p - numtabp); + for (p = numtabp; p < &numtabp[ncnt]; p++) { + if (p->r == 0) { + p->r = i; + p->link = nhash[h]; + nhash[h] = p; + regcnt++; + return(p - numtabp); + } + } + grownumtab(); + goto a0; +} + +int usedr(int i) /* returns -1 if nr i has never been used */ +{ + Numtab *p; + + if (i == 0) + return(-1); + for (p = nhash[NHASH(i)]; p; p = p->link) + if (i == p->r) + return(p - numtabp); + return -1; +} + + +int fnumb(int i, int (*f)(Tchar)) +{ + int j; + + j = 0; + if (i < 0) { + j = (*f)('-' | nrbits); + i = -i; + } + switch (nform) { + default: + case '1': + case 0: + return decml(i, f) + j; + case 'i': + case 'I': + return roman(i, f) + j; + case 'a': + case 'A': + return abc(i, f) + j; + } +} + + +int decml(int i, int (*f)(Tchar)) +{ + int j, k; + + k = 0; + nform--; + if ((j = i / 10) || (nform > 0)) + k = decml(j, f); + return(k + (*f)((i % 10 + '0') | nrbits)); +} + + +int roman(int i, int (*f)(Tchar)) +{ + + if (!i) + return((*f)('0' | nrbits)); + if (nform == 'i') + return(roman0(i, f, "ixcmz", "vldw")); + else + return(roman0(i, f, "IXCMZ", "VLDW")); +} + + +int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp) +{ + int q, rem, k; + + if (!i) + return(0); + k = roman0(i / 10, f, onesp + 1, fivesp + 1); + q = (i = i % 10) / 5; + rem = i % 5; + if (rem == 4) { + k += (*f)(*onesp | nrbits); + if (q) + i = *(onesp + 1); + else + i = *fivesp; + return(k += (*f)(i | nrbits)); + } + if (q) + k += (*f)(*fivesp | nrbits); + while (--rem >= 0) + k += (*f)(*onesp | nrbits); + return(k); +} + + +int abc(int i, int (*f)(Tchar)) +{ + if (!i) + return((*f)('0' | nrbits)); + else + return(abc0(i - 1, f)); +} + + +int abc0(int i, int (*f)(Tchar)) +{ + int j, k; + + k = 0; + if (j = i / 26) + k = abc0(j - 1, f); + return(k + (*f)((i % 26 + nform) | nrbits)); +} + +long atoi0(void) +{ + int c, k, cnt; + Tchar ii; + long i, acc; + + acc = 0; + nonumb = 0; + cnt = -1; +a0: + cnt++; + ii = getch(); + c = cbits(ii); + switch (c) { + default: + ch = ii; + if (cnt) + break; + case '+': + i = ckph(); + if (nonumb) + break; + acc += i; + goto a0; + case '-': + i = ckph(); + if (nonumb) + break; + acc -= i; + goto a0; + case '*': + i = ckph(); + if (nonumb) + break; + acc *= i; + goto a0; + case '/': + i = ckph(); + if (nonumb) + break; + if (i == 0) { + flusho(); + ERROR "divide by zero." WARN; + acc = 0; + } else + acc /= i; + goto a0; + case '%': + i = ckph(); + if (nonumb) + break; + acc %= i; + goto a0; + case '&': /*and*/ + i = ckph(); + if (nonumb) + break; + if ((acc > 0) && (i > 0)) + acc = 1; + else + acc = 0; + goto a0; + case ':': /*or*/ + i = ckph(); + if (nonumb) + break; + if ((acc > 0) || (i > 0)) + acc = 1; + else + acc = 0; + goto a0; + case '=': + if (cbits(ii = getch()) != '=') + ch = ii; + i = ckph(); + if (nonumb) { + acc = 0; + break; + } + if (i == acc) + acc = 1; + else + acc = 0; + goto a0; + case '>': + k = 0; + if (cbits(ii = getch()) == '=') + k++; + else + ch = ii; + i = ckph(); + if (nonumb) { + acc = 0; + break; + } + if (acc > (i - k)) + acc = 1; + else + acc = 0; + goto a0; + case '<': + k = 0; + if (cbits(ii = getch()) == '=') + k++; + else + ch = ii; + i = ckph(); + if (nonumb) { + acc = 0; + break; + } + if (acc < (i + k)) + acc = 1; + else + acc = 0; + goto a0; + case ')': + break; + case '(': + acc = atoi0(); + goto a0; + } + return(acc); +} + + +long ckph(void) +{ + Tchar i; + long j; + + if (cbits(i = getch()) == '(') + j = atoi0(); + else { + j = atoi1(i); + } + return(j); +} + + +/* + * print error about illegal numeric argument; + */ +void prnumerr(void) +{ + char err_buf[40]; + static char warn[] = "Numeric argument expected"; + int savcd = numtabp[CD].val; + + if (numerr.type == RQERR) + sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc), + unpair(numerr.req), warn); + else + sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg, + warn); + if (frame != stk) /* uncertainty correction */ + numtabp[CD].val--; + ERROR err_buf WARN; + numtabp[CD].val = savcd; +} + + +long atoi1(Tchar ii) +{ + int i, j, digits; + double acc; /* this is the only double in troff! */ + int neg, abs, field, decpnt; + extern int ifnum; + + + neg = abs = field = decpnt = digits = 0; + acc = 0; + for (;;) { + i = cbits(ii); + switch (i) { + default: + break; + case '+': + ii = getch(); + continue; + case '-': + neg = 1; + ii = getch(); + continue; + case '|': + abs = 1 + neg; + neg = 0; + ii = getch(); + continue; + } + break; + } +a1: + while (i >= '0' && i <= '9') { + field++; + digits++; + acc = 10 * acc + i - '0'; + ii = getch(); + i = cbits(ii); + } + if (i == '.' && !decpnt++) { + field++; + digits = 0; + ii = getch(); + i = cbits(ii); + goto a1; + } + if (!field) { + ch = ii; + goto a2; + } + switch (i) { + case 'u': + i = j = 1; /* should this be related to HOR?? */ + break; + case 'v': /*VSs - vert spacing*/ + j = lss; + i = 1; + break; + case 'm': /*Ems*/ + j = EM; + i = 1; + break; + case 'n': /*Ens*/ + j = EM; + if (TROFF) + i = 2; + else + i = 1; /*Same as Ems in NROFF*/ + break; + case 'p': /*Points*/ + j = INCH; + i = 72; + break; + case 'i': /*Inches*/ + j = INCH; + i = 1; + break; + case 'c': /*Centimeters*/ + /* if INCH is too big, this will overflow */ + j = INCH * 50; + i = 127; + break; + case 'P': /*Picas*/ + j = INCH; + i = 6; + break; + default: + j = dfact; + ch = ii; + i = dfactd; + } + if (neg) + acc = -acc; + if (!noscale) { + acc = (acc * j) / i; + } + if (field != digits && digits > 0) + while (digits--) + acc /= 10; + if (abs) { + if (dip != d) + j = dip->dnl; + else + j = numtabp[NL].val; + if (!vflag) { + j = numtabp[HP].val; + } + if (abs == 2) + j = -j; + acc -= j; + } +a2: + nonumb = (!field || field == decpnt); + if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) { + if (cbits(ii) != RIGHT ) /* Too painful to do right */ + prnumerr(); + } + return(acc); +} + + +void caserr(void) +{ + int i, j; + Numtab *p; + + lgf++; + while (!skip() && (i = getrq()) ) { + j = usedr(i); + if (j < 0) + continue; + p = &numtabp[j]; + nunhash(p); + p->r = p->val = p->inc = p->fmt = 0; + regcnt--; + } +} + +/* + * .nr request; if tracing, don't check optional + * 2nd argument because tbl generates .in 1.5n + */ +void casenr(void) +{ + int i, j; + int savtr = trace; + + lgf++; + skip(); + if ((i = findr(getrq())) == -1) + goto rtn; + skip(); + j = inumb(&numtabp[i].val); + if (nonumb) + goto rtn; + numtabp[i].val = j; + skip(); + trace = 0; + j = atoi0(); /* BUG??? */ + trace = savtr; + if (nonumb) + goto rtn; + numtabp[i].inc = j; +rtn: + return; +} + +void caseaf(void) +{ + int i, k; + Tchar j; + + lgf++; + if (skip() || !(i = getrq()) || skip()) + return; + k = 0; + j = getch(); + if (!isalpha(cbits(j))) { + ch = j; + while ((j = cbits(getch())) >= '0' && j <= '9') + k++; + } + if (!k) + k = j; + numtabp[findr(i)].fmt = k; /* was k & BYTEMASK */ +} + +void setaf(void) /* return format of number register */ +{ + int i, j; + + i = usedr(getsn()); + if (i == -1) + return; + if (numtabp[i].fmt > 20) /* it was probably a, A, i or I */ + *pbp++ = numtabp[i].fmt; + else + for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--) + *pbp++ = '0'; +} + + +int vnumb(int *i) +{ + vflag++; + dfact = lss; + res = VERT; + return(inumb(i)); +} + + +int hnumb(int *i) +{ + dfact = EM; + res = HOR; + return(inumb(i)); +} + + +int inumb(int *n) +{ + int i, j, f; + Tchar ii; + + f = 0; + if (n) { + if ((j = cbits(ii = getch())) == '+') + f = 1; + else if (j == '-') + f = -1; + else + ch = ii; + } + i = atoi0(); + if (n && f) + i = *n + f * i; + i = quant(i, res); + vflag = 0; + res = dfactd = dfact = 1; + if (nonumb) + i = 0; + return(i); +} + + +int quant(int n, int m) +{ + int i, neg; + + neg = 0; + if (n < 0) { + neg++; + n = -n; + } + /* better as i = ((n + m/2)/m)*m */ + i = n / m; + if (n - m * i > m / 2) + i += 1; + i *= m; + if (neg) + i = -i; + return(i); +} |