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