640 number_to_scaled_string is duplicated in several commands
[unleashed.git] / usr / src / cmd / troff / n4.c
blob113d6dcb501cc94ae5e514b3de3e805385eab0c9
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
40 #pragma ident "%Z%%M% %I% %E% SMI"
42 #include <ctype.h>
43 #include "tdef.h"
44 #ifdef NROFF
45 #include "tw.h"
46 #endif
47 #include "ext.h"
49 * troff4.c
51 * number registers, conversion, arithmetic
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 */
60 int
61 setn()
63 int i, j;
64 tchar ii;
65 int f;
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);
176 default:
177 goto s0;
179 else {
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;
188 setn1(i, nform, (tchar) 0);
190 return (0);
193 tchar numbuf[17];
194 tchar *numbufp;
197 wrc(i)
198 tchar i;
200 if (numbufp >= &numbuf[16])
201 return(0);
202 *numbufp++ = i;
203 return(1);
208 /* insert into input number i, in format form, with size-font bits bits */
210 setn1(i, form, bits)
211 int i;
212 tchar bits;
214 extern int wrc();
216 numbufp = numbuf;
217 nrbits = bits;
218 nform = form;
219 fnumb(i, wrc);
220 *numbufp = 0;
221 pushback(numbuf);
223 return (0);
228 nrehash()
230 struct numtab *p;
231 int i;
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;
245 return (0);
249 nunhash(rp)
250 struct numtab *rp;
252 struct numtab *p;
253 struct numtab **lp;
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);
265 lp = &p->link;
266 p = p->link;
268 return (0);
272 findr(i)
273 int i;
275 struct numtab *p;
276 int h = NHASH(i);
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);
292 errprint(gettext("too many number registers (%d)."), NN);
293 done2(04);
294 /* NOTREACHED */
296 return (0);
300 usedr(i) /* returns -1 if nr i has never been used */
301 int i;
303 struct numtab *p;
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;
315 fnumb(i, f)
316 int i, (*f)();
318 int j;
320 j = 0;
321 if (i < 0) {
322 j = (*f)('-' | nrbits);
323 i = -i;
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;
341 return (0);
346 decml(i, f)
347 int i, (*f)();
349 int j, k;
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));
360 roman(i, f)
361 int i, (*f)();
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"));
374 roman0(i, f, onesp, fivesp)
375 int i, (*f)();
376 char *onesp, *fivesp;
378 int q, rem, k;
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));
394 if (q)
395 k += (*f)(*fivesp | nrbits);
396 while (--rem >= 0)
397 k += (*f)(*onesp | nrbits);
398 return(k);
403 abc(i, f)
404 int i, (*f)();
406 if (!i)
407 return((*f)('0' | nrbits));
408 else
409 return(abc0(i - 1, f));
414 abc0(i, f)
415 int i, (*f)();
417 int j, k;
419 k = 0;
420 if (j = i / 26)
421 k = abc0(j - 1, f);
422 return(k + (*f)((i % 26 + nform) | nrbits));
425 long atoi0()
427 int c, k, cnt;
428 tchar ii;
429 long i, acc;
430 extern long ckph();
432 i = 0;
433 acc = 0;
434 nonumb = 0;
435 cnt = -1;
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;
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;
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;
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;
549 return(acc);
553 long ckph()
555 tchar i;
556 long j;
557 extern long atoi0();
558 extern long atoi1();
560 if (cbits(i = getch()) == '(')
561 j = atoi0();
562 else {
563 j = atoi1(i);
565 return(j);
569 long atoi1(ii)
570 tchar ii;
572 int i, j, digits;
573 long acc;
574 int neg, abs, field;
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;
596 break;
599 while (i >= '0' && i <= '9') {
600 field++;
601 digits++;
602 acc = 10 * acc + i - '0';
603 ii = getch();
604 i = cbits(ii);
606 if (i == '.') {
607 field++;
608 digits = 0;
609 ii = getch();
610 i = cbits(ii);
611 goto a1;
613 if (!field) {
614 ch = ii;
615 goto a2;
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;
660 if (neg)
661 acc = -acc;
662 if (!noscale) {
663 acc = (acc * j) / i;
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;
676 if (abs == 2)
677 j = -j;
678 acc -= j;
681 nonumb = !field;
682 return(acc);
687 caserr()
689 int i, j;
690 struct numtab *p;
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--;
703 return (0);
708 casenr()
710 int i, j;
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);
732 caseaf()
734 int i, k;
735 tchar j, jj;
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++;
747 if (!k)
748 k = j;
749 numtab[findr(i)].fmt = k & BYTEMASK;
751 return (0);
755 setaf() /* return format of number register */
757 int i, j;
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';
768 return (0);
773 vnumb(i)
774 int *i;
776 vflag++;
777 dfact = lss;
778 res = VERT;
779 return(inumb(i));
784 hnumb(i)
785 int *i;
787 dfact = EM;
788 res = HOR;
789 return(inumb(i));
794 inumb(n)
795 int *n;
797 int i, j, f;
798 tchar ii;
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;
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);
822 quant(n, m)
823 int n, m;
825 int i, neg;
827 neg = 0;
828 if (n < 0) {
829 neg++;
830 n = -n;
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);