Blob


1 /*
2 * troff4.c
3 *
4 * number registers, conversion, arithmetic
5 */
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 400
21 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 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;
154 cpushback(buf);
155 return;
156 default:
157 goto s0;
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;
168 setn1(i, nform, (Tchar) 0);
171 Tchar numbuf[25];
172 Tchar *numbufp;
174 int wrc(Tchar i)
176 if (numbufp >= &numbuf[24])
177 return(0);
178 *numbufp++ = i;
179 return(1);
184 /* insert into input number i, in format form, with size-font bits bits */
185 void setn1(int i, int form, Tchar bits)
187 numbufp = numbuf;
188 nrbits = bits;
189 nform = form;
190 fnumb(i, wrc);
191 *numbufp = 0;
192 pushback(numbuf);
195 void prnumtab(Numtab *p)
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);
208 void nnspace(void)
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);
216 numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
217 sizeof(numtab));
218 if (numtabp == NULL) {
219 ERROR "Cannot initialize registers" WARN;
220 exit(1);
224 void grownumtab(void)
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();
238 void nrehash(void)
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;
256 void nunhash(Numtab *rp)
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;
271 lp = &p->link;
272 p = p->link;
276 int findr(int i)
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);
296 grownumtab();
297 goto a0;
300 int usedr(int i) /* returns -1 if nr i has never been used */
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;
313 int fnumb(int i, int (*f)(Tchar))
315 int j;
317 j = 0;
318 if (i < 0) {
319 j = (*f)('-' | nrbits);
320 i = -i;
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;
337 int decml(int i, int (*f)(Tchar))
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));
349 int roman(int i, int (*f)(Tchar))
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"));
361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
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 else
375 i = *fivesp;
376 return(k += (*f)(i | nrbits));
378 if (q)
379 k += (*f)(*fivesp | nrbits);
380 while (--rem >= 0)
381 k += (*f)(*onesp | nrbits);
382 return(k);
386 int abc(int i, int (*f)(Tchar))
388 if (!i)
389 return((*f)('0' | nrbits));
390 else
391 return(abc0(i - 1, f));
395 int abc0(int i, int (*f)(Tchar))
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));
405 long atoi0(void)
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 } 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;
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;
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;
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;
527 return(acc);
531 long ckph(void)
533 Tchar i;
534 long j;
536 if (cbits(i = getch()) == '(')
537 j = atoi0();
538 else {
539 j = atoi1(i);
541 return(j);
545 /*
546 * print error about illegal numeric argument;
547 */
548 void prnumerr(void)
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 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 err_buf WARN;
563 numtabp[CD].val = savcd;
567 long atoi1(Tchar ii)
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;
595 break;
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);
605 if (i == '.' && !decpnt++) {
606 field++;
607 digits = 0;
608 ii = getch();
609 i = cbits(ii);
610 goto a1;
612 if (!field) {
613 ch = ii;
614 goto a2;
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;
657 if (neg)
658 acc = -acc;
659 if (!noscale) {
660 acc = (acc * j) / i;
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;
673 if (abs == 2)
674 j = -j;
675 acc -= j;
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();
683 return(acc);
687 void caserr(void)
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--;
704 /*
705 * .nr request; if tracing, don't check optional
706 * 2nd argument because tbl generates .in 1.5n
707 */
708 void casenr(void)
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;
733 void caseaf(void)
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++;
748 if (!k)
749 k = j;
750 numtabp[findr(i)].fmt = k; /* was k & BYTEMASK */
753 void setaf(void) /* return format of number register */
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 else
763 for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
764 *pbp++ = '0';
768 int vnumb(int *i)
770 vflag++;
771 dfact = lss;
772 res = VERT;
773 return(inumb(i));
777 int hnumb(int *i)
779 dfact = EM;
780 res = HOR;
781 return(inumb(i));
785 int inumb(int *n)
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 else
797 ch = ii;
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);
811 int quant(int n, int m)
813 int i, neg;
815 neg = 0;
816 if (n < 0) {
817 neg++;
818 n = -n;
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);