mkdev: remove devutf/C*
[troff.git] / troff / n4.c
blob2a1b0b9e6f0556b483ae4fdfa6c5557417a42954
1 /*
2 * troff4.c
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)
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], "%d", 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 {
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);
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;
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);
540 return j;
545 * print error about illegal numeric argument;
547 void prnumerr(void)
549 char err_buf[40];
550 static char warn[] = "Numeric argument expected";
551 int savcd = numtabp[CD].val;
553 if (numerr.type == RQERR)
554 sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
555 unpair(numerr.req), warn);
556 else
557 sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
558 warn);
559 if (frame != stk) /* uncertainty correction */
560 numtabp[CD].val--;
561 ERROR err_buf WARN;
562 numtabp[CD].val = savcd;
566 long atoi1(Tchar ii)
568 int i, j, digits;
569 double acc; /* this is the only double in troff! */
570 int neg, abs, field, decpnt;
571 extern int ifnum;
574 neg = abs = field = decpnt = digits = 0;
575 acc = 0;
576 for (;;) {
577 i = cbits(ii);
578 switch (i) {
579 default:
580 break;
581 case '+':
582 ii = getch();
583 continue;
584 case '-':
585 neg = 1;
586 ii = getch();
587 continue;
588 case '|':
589 abs = 1 + neg;
590 neg = 0;
591 ii = getch();
592 continue;
594 break;
597 while (i >= '0' && i <= '9') {
598 field++;
599 digits++;
600 acc = 10 * acc + i - '0';
601 ii = getch();
602 i = cbits(ii);
604 if (i == '.' && !decpnt++) {
605 field++;
606 digits = 0;
607 ii = getch();
608 i = cbits(ii);
609 goto a1;
611 if (!field) {
612 ch = ii;
613 goto a2;
615 switch (i) {
616 case 'u':
617 i = j = 1; /* should this be related to HOR?? */
618 break;
619 case 'v': /*VSs - vert spacing*/
620 j = lss;
621 i = 1;
622 break;
623 case 'm': /*Ems*/
624 j = EM;
625 i = 1;
626 break;
627 case 'n': /*Ens*/
628 j = EM;
629 if (TROFF)
630 i = 2;
631 else
632 i = 1; /*Same as Ems in NROFF*/
633 break;
634 case 'p': /*Points*/
635 j = INCH;
636 i = 72;
637 break;
638 case 'i': /*Inches*/
639 j = INCH;
640 i = 1;
641 break;
642 case 'c': /*Centimeters*/
643 /* if INCH is too big, this will overflow */
644 j = INCH * 50;
645 i = 127;
646 break;
647 case 'P': /*Picas*/
648 j = INCH;
649 i = 6;
650 break;
651 default:
652 j = dfact;
653 ch = ii;
654 i = dfactd;
656 if (neg)
657 acc = -acc;
658 if (!noscale)
659 acc = (acc * j) / i;
660 if (field != digits && digits > 0)
661 while (digits--)
662 acc /= 10;
663 if (abs) {
664 if (dip != d)
665 j = dip->dnl;
666 else
667 j = numtabp[NL].val;
668 if (!vflag) {
669 j = numtabp[HP].val;
671 if (abs == 2)
672 j = -j;
673 acc -= j;
676 nonumb = (!field || field == decpnt);
677 if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
678 if (cbits(ii) != RIGHT ) /* Too painful to do right */
679 prnumerr();
681 return acc;
685 void caserr(void)
687 int i, j;
688 Numtab *p;
690 lgf++;
691 while (!skip() && (i = getrq()) ) {
692 j = usedr(i);
693 if (j < 0)
694 continue;
695 p = &numtabp[j];
696 nunhash(p);
697 p->r = p->val = p->inc = p->fmt = 0;
698 regcnt--;
703 * .nr request; if tracing, don't check optional
704 * 2nd argument because tbl generates .in 1.5n
706 void casenr(void)
708 int i, j;
709 int savtr = trace;
711 lgf++;
712 skip();
713 if ((i = findr(getrq())) == -1)
714 goto rtn;
715 skip();
716 j = inumb(&numtabp[i].val);
717 if (nonumb)
718 goto rtn;
719 numtabp[i].val = j;
720 skip();
721 trace = 0;
722 j = atoi0(); /* BUG??? */
723 trace = savtr;
724 if (nonumb)
725 goto rtn;
726 numtabp[i].inc = j;
727 rtn:
728 return;
731 void caseaf(void)
733 int i, k;
734 Tchar j;
736 lgf++;
737 if (skip() || !(i = getrq()) || skip())
738 return;
739 k = 0;
740 j = getch();
741 if (!isalpha(cbits(j))) {
742 ch = j;
743 while ((j = cbits(getch())) >= '0' && j <= '9')
744 k++;
746 if (!k)
747 k = j;
748 numtabp[findr(i)].fmt = k; /* was k & BYTEMASK */
751 void setaf(void) /* return format of number register */
753 int i, j;
755 i = usedr(getsn());
756 if (i == -1)
757 return;
758 if (numtabp[i].fmt > 20) /* it was probably a, A, i or I */
759 *pbp++ = numtabp[i].fmt;
760 else
761 for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
762 *pbp++ = '0';
766 int vnumb(int *i)
768 vflag++;
769 dfact = lss;
770 res = VERT;
771 return(inumb(i));
775 int hnumb(int *i)
777 dfact = EM;
778 res = HOR;
779 return(inumb(i));
783 int inumb(int *n)
785 int i, j, f;
786 Tchar ii;
788 f = 0;
789 if (n) {
790 if ((j = cbits(ii = getch())) == '+')
791 f = 1;
792 else if (j == '-')
793 f = -1;
794 else
795 ch = ii;
797 i = atoi0();
798 if (n && f)
799 i = *n + f * i;
800 i = quant(i, res);
801 vflag = 0;
802 res = dfactd = dfact = 1;
803 if (nonumb)
804 i = 0;
805 return(i);
809 int quant(int n, int m)
811 int i, neg;
813 neg = 0;
814 if (n < 0) {
815 neg++;
816 n = -n;
818 /* better as i = ((n + m/2)/m)*m */
819 i = n / m;
820 if (n - m * i > m / 2)
821 i += 1;
822 i *= m;
823 if (neg)
824 i = -i;
825 return(i);