xref: /illumos-gate/usr/src/cmd/troff/n4.c (revision e5190c10)
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
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
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
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
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
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
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
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 
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 
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 
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
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
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
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
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
773 vnumb(i)
774 int	*i;
775 {
776 	vflag++;
777 	dfact = lss;
778 	res = VERT;
779 	return(inumb(i));
780 }
781 
782 
783 int
784 hnumb(i)
785 int	*i;
786 {
787 	dfact = EM;
788 	res = HOR;
789 	return(inumb(i));
790 }
791 
792 
793 int
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
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