+#include "tdef.h"
+extern
+#include "d.h"
+extern
+#include "v.h"
+#ifdef NROFF
+extern
+#include "tw.h"
+#endif
+#include "s.h"
+/*
+troff4.c
+
+number registers, conversion, arithmetic
+*/
+
+extern int inchar[LNSIZE], *pinchar; /* XXX */
+extern struct s *frame;
+
+extern int ascii;
+extern int cbuf[NC];
+extern int *cp;
+extern int r[NN];
+extern int *vlist;
+extern int inc[NN];
+extern int fmt[NN];
+extern int ch;
+extern int lgf;
+extern int pl;
+extern int lastl;
+extern int ralss;
+extern int totout;
+extern int nrbits;
+extern int nonumb;
+extern int vflag;
+extern int noscale;
+extern int dfact;
+extern int dfactd;
+extern int po;
+extern int nform;
+extern int ll;
+extern int in;
+extern int font;
+extern int bdtab[];
+extern int lss;
+extern int pts;
+extern int fi;
+extern int res;
+extern int cwidth;
+extern int dotT;
+extern int ev;
+extern int ne;
+extern int ad, admod;
+extern int print;
+extern int ls;
+extern int nel, un;
+extern int xxx;
+int regcnt = NNAMES;
+
+setn()
+{
+ register i,j;
+ int f;
+
+ f = nform = 0;
+ if((i=getch() & CMASK) == '+')f = 1;
+ else if(i == '-')f = -1;
+ else ch = i;
+ if((i=getsn()) == 0)return;
+ if((i & 0177) == '.')switch(i>>BYTE){
+ case 's': i = pts & 077; break;
+ case 'v': i = lss; break;
+ case 'f': i = font + 1; 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 = v.cd; 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 = v.nl;
+ break;
+ case 'u': i = fi; break;
+ case 'j': i = ad + 2*admod; break;
+ case 'w': i = width(*(pinchar-1)); break; /* XXX */
+ 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': i = NN - regcnt; break;
+ case 'z': i = dip->curd;
+ cbuf[0] = i & BMASK;
+ cbuf[1] = (i >> BYTE) & BMASK;
+ cbuf[2] = 0;
+ cp = cbuf;
+ return;
+#ifndef NROFF
+ case 'b': i = bdtab[font]; break;
+#endif
+
+ default:
+ goto s0;
+ }
+ else{
+s0:
+ if((j=findr(i)) == -1)i = 0;
+ else{
+ i = (vlist[j] = (vlist[j] + inc[j]*f));
+ nform = fmt[j];
+ }
+ }
+ setn1(i);
+ cp = cbuf;
+}
+setn1(i)
+int i;
+{
+ extern int wrc();
+
+ cp = cbuf;
+ nrbits = 0;
+ fnumb(i,wrc);
+ *cp = 0;
+ cp = cbuf;
+}
+findr(i)
+int i;
+{
+ register j;
+ static int numerr;
+
+ if(i == 0)return(-1);
+ for(j=0;j<NN;j++){
+ if(i == r[j])break;
+ }
+ if(j != NN)return(j);
+ for(j=0; j<NN; j++){
+ if(r[j] == 0){
+ r[j] = i;
+ regcnt++;
+ break;
+ }
+ }
+ if(j==NN){
+ if(!numerr)prstrfl("Too many number registers.\n");
+ if(++numerr > 1)done2(04); else edone(04);
+ }
+ return(j);
+}
+fnumb(i,f)
+int i, (*f)();
+{
+ register 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);
+ }
+}
+decml(i,f)
+int i, (*f)();
+{
+ register j,k;
+
+ k = 0;
+ nform--;
+ if((j=i/10) || (nform > 0))k = decml(j,f);
+ return(k + (*f)((i%10 + '0') | nrbits));
+}
+roman(i,f)
+int i, (*f)();
+{
+
+ if(!i)return((*f)('0' | nrbits));
+ if(nform == 'i')return(roman0(i,f,"ixcmz","vldw"));
+ else return(roman0(i,f,"IXCMZ","VLDW"));
+}
+roman0(i,f,onesp,fivesp)
+int i, (*f)();
+char *onesp, *fivesp;
+{
+ register q, rem, k;
+
+ k = 0;
+ 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);
+}
+abc(i,f)
+int i, (*f)();
+{
+ if(!i)return((*f)('0' | nrbits));
+ else return(abc0(i-1,f));
+}
+abc0(i,f)
+int i, (*f)();
+{
+ register j, k;
+
+ k = 0;
+ if(j=i/26)k = abc0(j-1,f);
+ return(k + (*f)((i%26 + nform) | nrbits));
+}
+wrc(i)
+int i;
+{
+ if(cp >= &cbuf[NC])return(0);
+ *cp++ = i;
+ return(1);
+}
+atoi(){
+ extern long atoi0();
+
+ return((int)atoi0());
+}
+long atoi0()
+{
+ register ii, k, cnt;
+ long i, acc;
+ extern long ckph();
+
+ i = 0; acc = 0;
+ nonumb = 0;
+ cnt = -1;
+a0:
+ cnt++;
+ switch((ii=getch()) & CMASK){
+ 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){
+ prstrfl("Divide by zero.\n");
+ 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(((ii=getch()) & CMASK) != '=')ch = ii;
+ i = ckph();
+ if(nonumb){acc = 0; break;}
+ if(i == acc)acc = 1;
+ else acc = 0;
+ goto a0;
+ case '>':
+ k = 0;
+ if(((ii=getch()) & CMASK) == '=')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(((ii=getch()) & CMASK) == '=')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(){
+ register i;
+ long j;
+ extern long atoi0();
+ extern long atoi1();
+
+ if(((i = getch()) & CMASK) == '(')j = atoi0();
+ else{
+ ch = i;
+ j = atoi1();
+ }
+ return(j);
+}
+long atoi1()
+{
+ register i, j, digits;
+ long acc;
+ int neg, abs, field;
+
+ neg = abs = field = digits = 0;
+ acc = 0;
+a0:
+ switch((i = getch()) & CMASK){
+ default:
+ ch = i;
+ break;
+ case '+':
+ goto a0;
+ case '-':
+ neg = 1;
+ goto a0;
+ case '|':
+ abs = 1 + neg;
+ neg = 0;
+ goto a0;
+ }
+a1:
+ while(((j = ((i = getch()) & CMASK) - '0') >= 0) && (j <= 9)){
+ field++;
+ digits++;
+ acc = 10*acc + j;
+ }
+ if((i & CMASK) == '.'){
+ field++;
+ digits = 0;
+ goto a1;
+ }
+ ch = i;
+ if(!field)goto a2;
+ switch((i = getch()) & CMASK){
+ case 'u':
+ i = j = 1;
+ break;
+ case 'v': /*VSs - vert spacing*/
+ j = lss;
+ i = 1;
+ break;
+ case 'm': /*Ems*/
+ j = EM;
+ i = 1;
+ break;
+ case 'n': /*Ens*/
+ j = EM;
+#ifndef NROFF
+ i = 2;
+#endif
+#ifdef NROFF
+ i = 1; /*Same as Ems in NROFF*/
+#endif
+ break;
+ case 'p': /*Points*/
+ j = INCH;
+ i = 72;
+ break;
+ case 'i': /*Inches*/
+ j = INCH;
+ i = 1;
+ break;
+ case 'c': /*Centimeters*/
+ j = INCH*50;
+ i = 127;
+ break;
+ case 'P': /*Picas*/
+ j = INCH;
+ i = 6;
+ break;
+ default:
+ j = dfact;
+ ch = i;
+ 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 = v.nl;
+ if(!vflag)j = v.hp = sumhp(); /* XXX */
+ if(abs == 2)j = -j;
+ acc -= j;
+ }
+a2:
+ nonumb = !field;
+ return(acc);
+}
+caserr(){
+ register i,j;
+
+ lgf++;
+ while(!skip() && (i=getrq()) ){
+ for(j=NNAMES; j<NN; j++){ /*NNAMES predefined names*/
+ if(i == r[j])break;
+ }
+ if(j!=NN){
+ r[j]=vlist[j]=inc[j]=fmt[j]=0;
+ regcnt--;
+ }
+ }
+}
+casenr(){
+ register i, j;
+
+ lgf++;
+ skip();
+ if((i = findr(getrq())) == -1)goto rtn;
+ skip();
+ j = inumb(&vlist[i]);
+ if(nonumb)goto rtn;
+ vlist[i] = j;
+ skip();
+ j = atoi();
+ if(nonumb)goto rtn;
+ inc[i] = j;
+rtn:
+ return;
+}
+caseaf(){
+ register i, j, k;
+
+ lgf++;
+ if(skip() || !(i = getrq()) || skip())return;
+ k = 0;
+ if(!alph(j=getch())){
+ ch = j;
+ while(((j = getch() & CMASK) >= '0') &&
+ (j <= '9'))k++;
+ }
+ if(!k)k=j;
+ fmt[findr(i)] = k & BMASK;
+}
+vnumb(i)
+int *i;
+{
+ vflag++;
+ dfact = lss;
+ res = VERT;
+ return(inumb(i));
+}
+hnumb(i)
+int *i;
+{
+ dfact = EM;
+ res = HOR;
+ return(inumb(i));
+}
+inumb(n)
+int *n;
+{
+ register i, j, f;
+
+ f = 0;
+ if(n){
+ if((j = (i = getch()) & CMASK) == '+')f = 1;
+ else if(j == '-')f = -1;
+ else ch = i;
+ }
+ i = atoi();
+ if(n && f)i = *n + f*i;
+ i = quant(i,res);
+ vflag = 0;
+ res = dfactd = dfact = 1;
+ if(nonumb)i = 0;
+ return(i);
+}
+quant(n,m)
+int n, m;
+{
+ register i, neg;
+
+ neg = 0;
+ if(n<0){
+ neg++;
+ n = -n;
+ }
+ i = n/m;
+ if((n - m*i) > (m/2))i += 1;
+ i *= m;
+ if(neg)i = -i;
+ return(i);
+}