URI: 
       n4.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       n4.c (12317B)
       ---
            1 /*
            2  * troff4.c
            3  *
            4  * number registers, conversion, arithmetic
            5  */
            6 
            7 #include "tdef.h"
            8 #include "fns.h"
            9 #include "ext.h"
           10 
           11 
           12 int        regcnt = NNAMES;
           13 int        falsef        = 0;        /* on if inside false branch of if */
           14 
           15 #define        NHASHSIZE        128        /* must be 2**n */
           16 #define        NHASH(i)        ((i>>6)^i) & (NHASHSIZE-1)
           17 Numtab        *nhash[NHASHSIZE];
           18 
           19 Numtab *numtabp = NULL;
           20 #define NDELTA 400
           21 int ncnt = 0;
           22 
           23 void setn(void)
           24 {
           25         int i, j, f;
           26         Tchar ii;
           27         Uchar *p;
           28         char buf[NTM];                /* for \n(.S */
           29 
           30         f = nform = 0;
           31         if ((i = cbits(ii = getach())) == '+')
           32                 f = 1;
           33         else if (i == '-')
           34                 f = -1;
           35         else if (ii)        /* don't put it back if it's already back (thanks to jaap) */
           36                 ch = ii;
           37         if (falsef)
           38                 f = 0;
           39         if ((i = getsn()) == 0)
           40                 return;
           41         p = unpair(i);
           42         if (p[0] == '.')
           43                 switch (p[1]) {
           44                 case 's':
           45                         i = pts;
           46                         break;
           47                 case 'v':
           48                         i = lss;
           49                         break;
           50                 case 'f':
           51                         i = font;
           52                         break;
           53                 case 'p':
           54                         i = pl;
           55                         break;
           56                 case 't':
           57                         i = findt1();
           58                         break;
           59                 case 'o':
           60                         i = po;
           61                         break;
           62                 case 'l':
           63                         i = ll;
           64                         break;
           65                 case 'i':
           66                         i = in;
           67                         break;
           68                 case '$':
           69                         i = frame->nargs;
           70                         break;
           71                 case 'A':
           72                         i = ascii;
           73                         break;
           74                 case 'c':
           75                         i = numtabp[CD].val;
           76                         break;
           77                 case 'n':
           78                         i = lastl;
           79                         break;
           80                 case 'a':
           81                         i = ralss;
           82                         break;
           83                 case 'h':
           84                         i = dip->hnl;
           85                         break;
           86                 case 'd':
           87                         if (dip != d)
           88                                 i = dip->dnl;
           89                         else
           90                                 i = numtabp[NL].val;
           91                         break;
           92                 case 'u':
           93                         i = fi;
           94                         break;
           95                 case 'j':
           96                         i = ad + 2 * admod;
           97                         break;
           98                 case 'w':
           99                         i = widthp;
          100                         break;
          101                 case 'x':
          102                         i = nel;
          103                         break;
          104                 case 'y':
          105                         i = un;
          106                         break;
          107                 case 'T':
          108                         i = dotT;
          109                         break;         /* -Tterm used in nroff */
          110                 case 'V':
          111                         i = VERT;
          112                         break;
          113                 case 'H':
          114                         i = HOR;
          115                         break;
          116                 case 'k':
          117                         i = ne;
          118                         break;
          119                 case 'P':
          120                         i = print;
          121                         break;
          122                 case 'L':
          123                         i = ls;
          124                         break;
          125                 case 'R':        /* maximal # of regs that can be addressed */
          126                         i = 255*256 - regcnt; 
          127                         break;
          128                 case 'z':
          129                         p = unpair(dip->curd);
          130                         *pbp++ = p[1];        /* watch order */
          131                         *pbp++ = p[0];
          132                         return;
          133                 case 'b':
          134                         i = bdtab[font];
          135                         break;
          136                 case 'F':
          137                         cpushback(cfname[ifi]);
          138                         return;
          139                  case 'S':
          140                          buf[0] = j = 0;        
          141                          for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
          142                                  if (i > 0)
          143                                          buf[j++] = ' ';
          144                                  sprintf(&buf[j], "%ld", tabtab[i] & TABMASK);
          145                                  j = strlen(buf);
          146                                  if ( tabtab[i] & RTAB)
          147                                          sprintf(&buf[j], "uR");
          148                                  else if (tabtab[i] & CTAB)
          149                                          sprintf(&buf[j], "uC");
          150                                  else
          151                                          sprintf(&buf[j], "uL");
          152                                  j += 2;
          153                          }
          154                          cpushback(buf);
          155                          return;
          156                 default:
          157                         goto s0;
          158                 }
          159         else {
          160 s0:
          161                 if ((j = findr(i)) == -1)
          162                         i = 0;
          163                 else {
          164                         i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
          165                         nform = numtabp[j].fmt;
          166                 }
          167         }
          168         setn1(i, nform, (Tchar) 0);
          169 }
          170 
          171 Tchar        numbuf[25];
          172 Tchar        *numbufp;
          173 
          174 int wrc(Tchar i)
          175 {
          176         if (numbufp >= &numbuf[24])
          177                 return(0);
          178         *numbufp++ = i;
          179         return(1);
          180 }
          181 
          182 
          183 
          184 /* insert into input number i, in format form, with size-font bits bits */
          185 void setn1(int i, int form, Tchar bits)
          186 {
          187         numbufp = numbuf;
          188         nrbits = bits;
          189         nform = form;
          190         fnumb(i, wrc);
          191         *numbufp = 0;
          192         pushback(numbuf);
          193 }
          194 
          195 void prnumtab(Numtab *p)
          196 {
          197         int i;
          198         for (i = 0; i < ncnt; i++)
          199                 if (p)
          200                         if (p[i].r != 0)
          201                                 fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
          202                         else
          203                                 fprintf(stderr, "slot %d empty\n", i);
          204                 else
          205                         fprintf(stderr, "slot %d empty\n", i);
          206 }
          207 
          208 void nnspace(void)
          209 {
          210         ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
          211         numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
          212         if (numtabp == NULL) {
          213                 ERROR "not enough memory for registers (%d)", ncnt WARN;
          214                 exit(1);
          215         }
          216         numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
          217                                                         sizeof(numtab));
          218         if (numtabp == NULL) {
          219                 ERROR "Cannot initialize registers" WARN;
          220                 exit(1);
          221         }
          222 }
          223 
          224 void grownumtab(void)
          225 {
          226         ncnt += NDELTA;
          227         numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
          228         if (numtabp == NULL) {
          229                 ERROR "Too many number registers (%d)", ncnt WARN;
          230                 done2(04);
          231         } else {
          232                 memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
          233                                                 0, NDELTA * sizeof(Numtab));
          234                 nrehash();
          235         }
          236 }
          237 
          238 void nrehash(void)
          239 {
          240         Numtab *p;
          241         int i;
          242 
          243         for (i=0; i<NHASHSIZE; i++)
          244                 nhash[i] = 0;
          245         for (p=numtabp; p < &numtabp[ncnt]; p++)
          246                 p->link = 0;
          247         for (p=numtabp; p < &numtabp[ncnt]; p++) {
          248                 if (p->r == 0)
          249                         continue;
          250                 i = NHASH(p->r);
          251                 p->link = nhash[i];
          252                 nhash[i] = p;
          253         }
          254 }
          255 
          256 void nunhash(Numtab *rp)
          257 {
          258         Numtab *p;
          259         Numtab **lp;
          260 
          261         if (rp->r == 0)
          262                 return;
          263         lp = &nhash[NHASH(rp->r)];
          264         p = *lp;
          265         while (p) {
          266                 if (p == rp) {
          267                         *lp = p->link;
          268                         p->link = 0;
          269                         return;
          270                 }
          271                 lp = &p->link;
          272                 p = p->link;
          273         }
          274 }
          275 
          276 int findr(int i)
          277 {
          278         Numtab *p;
          279         int h = NHASH(i);
          280 
          281         if (i == 0)
          282                 return(-1);
          283 a0:
          284         for (p = nhash[h]; p; p = p->link)
          285                 if (i == p->r)
          286                         return(p - numtabp);
          287         for (p = numtabp; p < &numtabp[ncnt]; p++) {
          288                 if (p->r == 0) {
          289                         p->r = i;
          290                         p->link = nhash[h];
          291                         nhash[h] = p;
          292                         regcnt++;
          293                         return(p - numtabp);
          294                 }
          295         }
          296         grownumtab();
          297         goto a0;
          298 }
          299 
          300 int usedr(int i)        /* returns -1 if nr i has never been used */
          301 {
          302         Numtab *p;
          303 
          304         if (i == 0)
          305                 return(-1);
          306         for (p = nhash[NHASH(i)]; p; p = p->link)
          307                 if (i == p->r)
          308                         return(p - numtabp);
          309         return -1;
          310 }
          311 
          312 
          313 int fnumb(int i, int (*f)(Tchar))
          314 {
          315         int j;
          316 
          317         j = 0;
          318         if (i < 0) {
          319                 j = (*f)('-' | nrbits);
          320                 i = -i;
          321         }
          322         switch (nform) {
          323         default:
          324         case '1':
          325         case 0:
          326                 return decml(i, f) + j;
          327         case 'i':
          328         case 'I':
          329                 return roman(i, f) + j;
          330         case 'a':
          331         case 'A':
          332                 return abc(i, f) + j;
          333         }
          334 }
          335 
          336 
          337 int decml(int i, int (*f)(Tchar))
          338 {
          339         int j, k;
          340 
          341         k = 0;
          342         nform--;
          343         if ((j = i / 10) || (nform > 0))
          344                 k = decml(j, f);
          345         return(k + (*f)((i % 10 + '0') | nrbits));
          346 }
          347 
          348 
          349 int roman(int i, int (*f)(Tchar))
          350 {
          351 
          352         if (!i)
          353                 return((*f)('0' | nrbits));
          354         if (nform == 'i')
          355                 return(roman0(i, f, "ixcmz", "vldw"));
          356         else
          357                 return(roman0(i, f, "IXCMZ", "VLDW"));
          358 }
          359 
          360 
          361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
          362 {
          363         int q, rem, k;
          364 
          365         if (!i)
          366                 return(0);
          367         k = roman0(i / 10, f, onesp + 1, fivesp + 1);
          368         q = (i = i % 10) / 5;
          369         rem = i % 5;
          370         if (rem == 4) {
          371                 k += (*f)(*onesp | nrbits);
          372                 if (q)
          373                         i = *(onesp + 1);
          374                 else
          375                         i = *fivesp;
          376                 return(k += (*f)(i | nrbits));
          377         }
          378         if (q)
          379                 k += (*f)(*fivesp | nrbits);
          380         while (--rem >= 0)
          381                 k += (*f)(*onesp | nrbits);
          382         return(k);
          383 }
          384 
          385 
          386 int abc(int i, int (*f)(Tchar))
          387 {
          388         if (!i)
          389                 return((*f)('0' | nrbits));
          390         else
          391                 return(abc0(i - 1, f));
          392 }
          393 
          394 
          395 int abc0(int i, int (*f)(Tchar))
          396 {
          397         int j, k;
          398 
          399         k = 0;
          400         if (j = i / 26)
          401                 k = abc0(j - 1, f);
          402         return(k + (*f)((i % 26 + nform) | nrbits));
          403 }
          404 
          405 long atoi0(void)
          406 {
          407         int c, k, cnt;
          408         Tchar ii;
          409         long i, acc;
          410 
          411         acc = 0;
          412         nonumb = 0;
          413         cnt = -1;
          414 a0:
          415         cnt++;
          416         ii = getch();
          417         c = cbits(ii);
          418         switch (c) {
          419         default:
          420                 ch = ii;
          421                 if (cnt)
          422                         break;
          423         case '+':
          424                 i = ckph();
          425                 if (nonumb)
          426                         break;
          427                 acc += i;
          428                 goto a0;
          429         case '-':
          430                 i = ckph();
          431                 if (nonumb)
          432                         break;
          433                 acc -= i;
          434                 goto a0;
          435         case '*':
          436                 i = ckph();
          437                 if (nonumb)
          438                         break;
          439                 acc *= i;
          440                 goto a0;
          441         case '/':
          442                 i = ckph();
          443                 if (nonumb)
          444                         break;
          445                 if (i == 0) {
          446                         flusho();
          447                         ERROR "divide by zero." WARN;
          448                         acc = 0;
          449                 } else
          450                         acc /= i;
          451                 goto a0;
          452         case '%':
          453                 i = ckph();
          454                 if (nonumb)
          455                         break;
          456                 acc %= i;
          457                 goto a0;
          458         case '&':        /*and*/
          459                 i = ckph();
          460                 if (nonumb)
          461                         break;
          462                 if ((acc > 0) && (i > 0))
          463                         acc = 1;
          464                 else
          465                         acc = 0;
          466                 goto a0;
          467         case ':':        /*or*/
          468                 i = ckph();
          469                 if (nonumb)
          470                         break;
          471                 if ((acc > 0) || (i > 0))
          472                         acc = 1;
          473                 else
          474                         acc = 0;
          475                 goto a0;
          476         case '=':
          477                 if (cbits(ii = getch()) != '=')
          478                         ch = ii;
          479                 i = ckph();
          480                 if (nonumb) {
          481                         acc = 0;
          482                         break;
          483                 }
          484                 if (i == acc)
          485                         acc = 1;
          486                 else
          487                         acc = 0;
          488                 goto a0;
          489         case '>':
          490                 k = 0;
          491                 if (cbits(ii = getch()) == '=')
          492                         k++;
          493                 else
          494                         ch = ii;
          495                 i = ckph();
          496                 if (nonumb) {
          497                         acc = 0;
          498                         break;
          499                 }
          500                 if (acc > (i - k))
          501                         acc = 1;
          502                 else
          503                         acc = 0;
          504                 goto a0;
          505         case '<':
          506                 k = 0;
          507                 if (cbits(ii = getch()) == '=')
          508                         k++;
          509                 else
          510                         ch = ii;
          511                 i = ckph();
          512                 if (nonumb) {
          513                         acc = 0;
          514                         break;
          515                 }
          516                 if (acc < (i + k))
          517                         acc = 1;
          518                 else
          519                         acc = 0;
          520                 goto a0;
          521         case ')':
          522                 break;
          523         case '(':
          524                 acc = atoi0();
          525                 goto a0;
          526         }
          527         return(acc);
          528 }
          529 
          530 
          531 long ckph(void)
          532 {
          533         Tchar i;
          534         long j;
          535 
          536         if (cbits(i = getch()) == '(')
          537                 j = atoi0();
          538         else {
          539                 j = atoi1(i);
          540         }
          541         return(j);
          542 }
          543 
          544 
          545 /*
          546  * print error about illegal numeric argument;
          547  */
          548 void prnumerr(void)
          549 {
          550         char err_buf[40];
          551         static char warn[] = "Numeric argument expected";
          552         int savcd = numtabp[CD].val;
          553 
          554         if (numerr.type == RQERR)
          555                 sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
          556                                                 unpair(numerr.req), warn);
          557         else
          558                 sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
          559                                                                         warn);
          560         if (frame != stk)        /* uncertainty correction */
          561                 numtabp[CD].val--;
          562         ERROR "%s", err_buf WARN;
          563         numtabp[CD].val = savcd;
          564 }
          565 
          566 
          567 long atoi1(Tchar ii)
          568 {
          569         int i, j, digits;
          570         double acc;        /* this is the only double in troff! */
          571         int neg, abs, field, decpnt;
          572         extern int ifnum;
          573 
          574 
          575         neg = abs = field = decpnt = digits = 0;
          576         acc = 0;
          577         for (;;) {
          578                 i = cbits(ii);
          579                 switch (i) {
          580                 default:
          581                         break;
          582                 case '+':
          583                         ii = getch();
          584                         continue;
          585                 case '-':
          586                         neg = 1;
          587                         ii = getch();
          588                         continue;
          589                 case '|':
          590                         abs = 1 + neg;
          591                         neg = 0;
          592                         ii = getch();
          593                         continue;
          594                 }
          595                 break;
          596         }
          597 a1:
          598         while (i >= '0' && i <= '9') {
          599                 field++;
          600                 digits++;
          601                 acc = 10 * acc + i - '0';
          602                 ii = getch();
          603                 i = cbits(ii);
          604         }
          605         if (i == '.' && !decpnt++) {
          606                 field++;
          607                 digits = 0;
          608                 ii = getch();
          609                 i = cbits(ii);
          610                 goto a1;
          611         }
          612         if (!field) {
          613                 ch = ii;
          614                 goto a2;
          615         }
          616         switch (i) {
          617         case 'u':
          618                 i = j = 1;        /* should this be related to HOR?? */
          619                 break;
          620         case 'v':        /*VSs - vert spacing*/
          621                 j = lss;
          622                 i = 1;
          623                 break;
          624         case 'm':        /*Ems*/
          625                 j = EM;
          626                 i = 1;
          627                 break;
          628         case 'n':        /*Ens*/
          629                 j = EM;
          630                 if (TROFF)
          631                         i = 2;
          632                 else
          633                         i = 1;        /*Same as Ems in NROFF*/
          634                 break;
          635         case 'p':        /*Points*/
          636                 j = INCH;
          637                 i = 72;
          638                 break;
          639         case 'i':        /*Inches*/
          640                 j = INCH;
          641                 i = 1;
          642                 break;
          643         case 'c':        /*Centimeters*/
          644                 /* if INCH is too big, this will overflow */
          645                 j = INCH * 50;
          646                 i = 127;
          647                 break;
          648         case 'P':        /*Picas*/
          649                 j = INCH;
          650                 i = 6;
          651                 break;
          652         default:
          653                 j = dfact;
          654                 ch = ii;
          655                 i = dfactd;
          656         }
          657         if (neg)
          658                 acc = -acc;
          659         if (!noscale) {
          660                 acc = (acc * j) / i;
          661         }
          662         if (field != digits && digits > 0)
          663                 while (digits--)
          664                         acc /= 10;
          665         if (abs) {
          666                 if (dip != d)
          667                         j = dip->dnl;
          668                 else
          669                         j = numtabp[NL].val;
          670                 if (!vflag) {
          671                         j = numtabp[HP].val;
          672                 }
          673                 if (abs == 2)
          674                         j = -j;
          675                 acc -= j;
          676         }
          677 a2:
          678         nonumb = (!field || field == decpnt);
          679         if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
          680                 if (cbits(ii) != RIGHT ) /* Too painful to do right */
          681                         prnumerr();
          682         }
          683         return(acc);
          684 }
          685 
          686 
          687 void caserr(void)
          688 {
          689         int i, j;
          690         Numtab *p;
          691 
          692         lgf++;
          693         while (!skip() && (i = getrq()) ) {
          694                 j = usedr(i);
          695                 if (j < 0)
          696                         continue;
          697                 p = &numtabp[j];
          698                 nunhash(p);
          699                 p->r = p->val = p->inc = p->fmt = 0;
          700                 regcnt--;
          701         }
          702 }
          703 
          704 /*
          705  * .nr request; if tracing, don't check optional
          706  * 2nd argument because tbl generates .in 1.5n
          707  */
          708 void casenr(void)
          709 {
          710         int i, j;
          711         int savtr = trace;
          712 
          713         lgf++;
          714         skip();
          715         if ((i = findr(getrq())) == -1)
          716                 goto rtn;
          717         skip();
          718         j = inumb(&numtabp[i].val);
          719         if (nonumb)
          720                 goto rtn;
          721         numtabp[i].val = j;
          722         skip();
          723         trace = 0;
          724         j = atoi0();                /* BUG??? */
          725         trace = savtr;
          726         if (nonumb)
          727                 goto rtn;
          728         numtabp[i].inc = j;
          729 rtn:
          730         return;
          731 }
          732 
          733 void caseaf(void)
          734 {
          735         int i, k;
          736         Tchar j;
          737 
          738         lgf++;
          739         if (skip() || !(i = getrq()) || skip())
          740                 return;
          741         k = 0;
          742         j = getch();
          743         if (!isalpha(cbits(j))) {
          744                 ch = j;
          745                 while ((j = cbits(getch())) >= '0' &&  j <= '9')
          746                         k++;
          747         }
          748         if (!k)
          749                 k = j;
          750         numtabp[findr(i)].fmt = k;        /* was k & BYTEMASK */
          751 }
          752 
          753 void setaf(void)        /* return format of number register */
          754 {
          755         int i, j;
          756 
          757         i = usedr(getsn());
          758         if (i == -1)
          759                 return;
          760         if (numtabp[i].fmt > 20)        /* it was probably a, A, i or I */
          761                 *pbp++ = numtabp[i].fmt;
          762         else
          763                 for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
          764                         *pbp++ = '0';
          765 }
          766 
          767 
          768 int vnumb(int *i)
          769 {
          770         vflag++;
          771         dfact = lss;
          772         res = VERT;
          773         return(inumb(i));
          774 }
          775 
          776 
          777 int hnumb(int *i)
          778 {
          779         dfact = EM;
          780         res = HOR;
          781         return(inumb(i));
          782 }
          783 
          784 
          785 int inumb(int *n)
          786 {
          787         int i, j, f;
          788         Tchar ii;
          789 
          790         f = 0;
          791         if (n) {
          792                 if ((j = cbits(ii = getch())) == '+')
          793                         f = 1;
          794                 else if (j == '-')
          795                         f = -1;
          796                 else
          797                         ch = ii;
          798         }
          799         i = atoi0();
          800         if (n && f)
          801                 i = *n + f * i;
          802         i = quant(i, res);
          803         vflag = 0;
          804         res = dfactd = dfact = 1;
          805         if (nonumb)
          806                 i = 0;
          807         return(i);
          808 }
          809 
          810 
          811 int quant(int n, int m)
          812 {
          813         int i, neg;
          814 
          815         neg = 0;
          816         if (n < 0) {
          817                 neg++;
          818                 n = -n;
          819         }
          820         /* better as i = ((n + m/2)/m)*m */
          821         i = n / m;
          822         if (n - m * i > m / 2)
          823                 i += 1;
          824         i *= m;
          825         if (neg)
          826                 i = -i;
          827         return(i);
          828 }