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