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