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