Blob
1 /*2 * troff4.c3 *4 * number registers, conversion, arithmetic5 */7 #include "tdef.h"8 #include "fns.h"9 #include "ext.h"12 int regcnt = NNAMES;13 int falsef = 0; /* on if inside false branch of if */15 #define NHASHSIZE 128 /* must be 2**n */16 #define NHASH(i) ((i>>6)^i) & (NHASHSIZE-1)17 Numtab *nhash[NHASHSIZE];19 Numtab *numtabp = NULL;20 #define NDELTA 40021 int ncnt = 0;23 void setn(void)24 {25 int i, j, f;26 Tchar ii;27 Uchar *p;28 char buf[NTM]; /* for \n(.S */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 else90 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 else151 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 }171 Tchar numbuf[25];172 Tchar *numbufp;174 int wrc(Tchar i)175 {176 if (numbufp >= &numbuf[24])177 return(0);178 *numbufp++ = i;179 return(1);180 }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 }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 else203 fprintf(stderr, "slot %d empty\n", i);204 else205 fprintf(stderr, "slot %d empty\n", i);206 }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 }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 }238 void nrehash(void)239 {240 Numtab *p;241 int i;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 }256 void nunhash(Numtab *rp)257 {258 Numtab *p;259 Numtab **lp;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 }276 int findr(int i)277 {278 Numtab *p;279 int h = NHASH(i);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 }300 int usedr(int i) /* returns -1 if nr i has never been used */301 {302 Numtab *p;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 }313 int fnumb(int i, int (*f)(Tchar))314 {315 int j;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 }337 int decml(int i, int (*f)(Tchar))338 {339 int j, k;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 }349 int roman(int i, int (*f)(Tchar))350 {352 if (!i)353 return((*f)('0' | nrbits));354 if (nform == 'i')355 return(roman0(i, f, "ixcmz", "vldw"));356 else357 return(roman0(i, f, "IXCMZ", "VLDW"));358 }361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)362 {363 int q, rem, k;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 else375 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 }386 int abc(int i, int (*f)(Tchar))387 {388 if (!i)389 return((*f)('0' | nrbits));390 else391 return(abc0(i - 1, f));392 }395 int abc0(int i, int (*f)(Tchar))396 {397 int j, k;399 k = 0;400 if (j = i / 26)401 k = abc0(j - 1, f);402 return(k + (*f)((i % 26 + nform) | nrbits));403 }405 long atoi0(void)406 {407 int c, k, cnt;408 Tchar ii;409 long i, acc;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 } else450 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 else465 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 else474 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 else487 acc = 0;488 goto a0;489 case '>':490 k = 0;491 if (cbits(ii = getch()) == '=')492 k++;493 else494 ch = ii;495 i = ckph();496 if (nonumb) {497 acc = 0;498 break;499 }500 if (acc > (i - k))501 acc = 1;502 else503 acc = 0;504 goto a0;505 case '<':506 k = 0;507 if (cbits(ii = getch()) == '=')508 k++;509 else510 ch = ii;511 i = ckph();512 if (nonumb) {513 acc = 0;514 break;515 }516 if (acc < (i + k))517 acc = 1;518 else519 acc = 0;520 goto a0;521 case ')':522 break;523 case '(':524 acc = atoi0();525 goto a0;526 }527 return(acc);528 }531 long ckph(void)532 {533 Tchar i;534 long j;536 if (cbits(i = getch()) == '(')537 j = atoi0();538 else {539 j = atoi1(i);540 }541 return(j);542 }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;554 if (numerr.type == RQERR)555 sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),556 unpair(numerr.req), warn);557 else558 sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,559 warn);560 if (frame != stk) /* uncertainty correction */561 numtabp[CD].val--;562 ERROR err_buf WARN;563 numtabp[CD].val = savcd;564 }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;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 else633 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 else669 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 }687 void caserr(void)688 {689 int i, j;690 Numtab *p;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 }704 /*705 * .nr request; if tracing, don't check optional706 * 2nd argument because tbl generates .in 1.5n707 */708 void casenr(void)709 {710 int i, j;711 int savtr = trace;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 }733 void caseaf(void)734 {735 int i, k;736 Tchar j;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 }753 void setaf(void) /* return format of number register */754 {755 int i, j;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 else763 for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)764 *pbp++ = '0';765 }768 int vnumb(int *i)769 {770 vflag++;771 dfact = lss;772 res = VERT;773 return(inumb(i));774 }777 int hnumb(int *i)778 {779 dfact = EM;780 res = HOR;781 return(inumb(i));782 }785 int inumb(int *n)786 {787 int i, j, f;788 Tchar ii;790 f = 0;791 if (n) {792 if ((j = cbits(ii = getch())) == '+')793 f = 1;794 else if (j == '-')795 f = -1;796 else797 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 }811 int quant(int n, int m)812 {813 int i, neg;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 }