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