xref: /illumos-gate/usr/src/cmd/troff/n4.c (revision 59d65d3175825093531e82f44269d948ed510a00)
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
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
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
208 setn1(i, form, bits)
209 int	i;
210 tchar bits;
211 {
212 	extern int	wrc();
213 
214 	numbufp = numbuf;
215 	nrbits = bits;
216 	nform = form;
217 	fnumb(i, wrc);
218 	*numbufp = 0;
219 	pushback(numbuf);
220 
221 	return (0);
222 }
223 
224 
225 int
226 nrehash()
227 {
228 	struct numtab *p;
229 	int	i;
230 
231 	for (i=0; i<128; i++)
232 		nhash[i] = 0;
233 	for (p=numtab; p < &numtab[NN]; p++)
234 		p->link = 0;
235 	for (p=numtab; p < &numtab[NN]; p++) {
236 		if (p->r == 0)
237 			continue;
238 		i = NHASH(p->r);
239 		p->link = nhash[i];
240 		nhash[i] = p;
241 	}
242 
243 	return (0);
244 }
245 
246 int
247 nunhash(rp)
248 struct numtab *rp;
249 {
250 	struct numtab *p;
251 	struct numtab **lp;
252 
253 	if (rp->r == 0)
254 		return (0);
255 	lp = &nhash[NHASH(rp->r)];
256 	p = *lp;
257 	while (p) {
258 		if (p == rp) {
259 			*lp = p->link;
260 			p->link = 0;
261 			return (0);
262 		}
263 		lp = &p->link;
264 		p = p->link;
265 	}
266 	return (0);
267 }
268 
269 int
270 findr(i)
271 int	i;
272 {
273 	struct numtab *p;
274 	int	h = NHASH(i);
275 
276 	if (i == 0)
277 		return(-1);
278 	for (p = nhash[h]; p; p = p->link)
279 		if (i == p->r)
280 			return(p - numtab);
281 	for (p = numtab; p < &numtab[NN]; p++) {
282 		if (p->r == 0) {
283 			p->r = i;
284 			p->link = nhash[h];
285 			nhash[h] = p;
286 			regcnt++;
287 			return(p - numtab);
288 		}
289 	}
290 	errprint(gettext("too many number registers (%d)."), NN);
291 	done2(04);
292 	/* NOTREACHED */
293 
294 	return (0);
295 }
296 
297 int
298 usedr(i)	/* returns -1 if nr i has never been used */
299 int	i;
300 {
301 	struct numtab *p;
302 
303 	if (i == 0)
304 		return(-1);
305 	for (p = nhash[NHASH(i)]; p; p = p->link)
306 		if (i == p->r)
307 			return(p - numtab);
308 	return -1;
309 }
310 
311 
312 int
313 fnumb(i, f)
314 int	i, (*f)();
315 {
316 	int	j;
317 
318 	j = 0;
319 	if (i < 0) {
320 		j = (*f)('-' | nrbits);
321 		i = -i;
322 	}
323 	switch (nform) {
324 	default:
325 	case '1':
326 	case 0:
327 		return decml(i, f) + j;
328 		break;
329 	case 'i':
330 	case 'I':
331 		return roman(i, f) + j;
332 		break;
333 	case 'a':
334 	case 'A':
335 		return abc(i, f) + j;
336 		break;
337 	}
338 
339 	return (0);
340 }
341 
342 
343 int
344 decml(i, f)
345 int	i, (*f)();
346 {
347 	int	j, k;
348 
349 	k = 0;
350 	nform--;
351 	if ((j = i / 10) || (nform > 0))
352 		k = decml(j, f);
353 	return(k + (*f)((i % 10 + '0') | nrbits));
354 }
355 
356 
357 int
358 roman(i, f)
359 int	i, (*f)();
360 {
361 
362 	if (!i)
363 		return((*f)('0' | nrbits));
364 	if (nform == 'i')
365 		return(roman0(i, f, "ixcmz", "vldw"));
366 	else
367 		return(roman0(i, f, "IXCMZ", "VLDW"));
368 }
369 
370 
371 int
372 roman0(i, f, onesp, fivesp)
373 int	i, (*f)();
374 char	*onesp, *fivesp;
375 {
376 	int	q, rem, k;
377 
378 	k = 0;
379 	if (!i)
380 		return(0);
381 	k = roman0(i / 10, f, onesp + 1, fivesp + 1);
382 	q = (i = i % 10) / 5;
383 	rem = i % 5;
384 	if (rem == 4) {
385 		k += (*f)(*onesp | nrbits);
386 		if (q)
387 			i = *(onesp + 1);
388 		else
389 			i = *fivesp;
390 		return(k += (*f)(i | nrbits));
391 	}
392 	if (q)
393 		k += (*f)(*fivesp | nrbits);
394 	while (--rem >= 0)
395 		k += (*f)(*onesp | nrbits);
396 	return(k);
397 }
398 
399 
400 int
401 abc(i, f)
402 int	i, (*f)();
403 {
404 	if (!i)
405 		return((*f)('0' | nrbits));
406 	else
407 		return(abc0(i - 1, f));
408 }
409 
410 
411 int
412 abc0(i, f)
413 int	i, (*f)();
414 {
415 	int	j, k;
416 
417 	k = 0;
418 	if (j = i / 26)
419 		k = abc0(j - 1, f);
420 	return(k + (*f)((i % 26 + nform) | nrbits));
421 }
422 
423 long	atoi0()
424 {
425 	int	c, k, cnt;
426 	tchar ii;
427 	long	i, acc;
428 	extern long	ckph();
429 
430 	i = 0;
431 	acc = 0;
432 	nonumb = 0;
433 	cnt = -1;
434 a0:
435 	cnt++;
436 	ii = getch();
437 	c = cbits(ii);
438 	switch (c) {
439 	default:
440 		ch = ii;
441 		if (cnt)
442 			break;
443 	case '+':
444 		i = ckph();
445 		if (nonumb)
446 			break;
447 		acc += i;
448 		goto a0;
449 	case '-':
450 		i = ckph();
451 		if (nonumb)
452 			break;
453 		acc -= i;
454 		goto a0;
455 	case '*':
456 		i = ckph();
457 		if (nonumb)
458 			break;
459 		acc *= i;
460 		goto a0;
461 	case '/':
462 		i = ckph();
463 		if (nonumb)
464 			break;
465 		if (i == 0) {
466 			flusho();
467 			errprint(gettext("divide by zero."));
468 			acc = 0;
469 		} else
470 			acc /= i;
471 		goto a0;
472 	case '%':
473 		i = ckph();
474 		if (nonumb)
475 			break;
476 		acc %= i;
477 		goto a0;
478 	case '&':	/*and*/
479 		i = ckph();
480 		if (nonumb)
481 			break;
482 		if ((acc > 0) && (i > 0))
483 			acc = 1;
484 		else
485 			acc = 0;
486 		goto a0;
487 	case ':':	/*or*/
488 		i = ckph();
489 		if (nonumb)
490 			break;
491 		if ((acc > 0) || (i > 0))
492 			acc = 1;
493 		else
494 			acc = 0;
495 		goto a0;
496 	case '=':
497 		if (cbits(ii = getch()) != '=')
498 			ch = ii;
499 		i = ckph();
500 		if (nonumb) {
501 			acc = 0;
502 			break;
503 		}
504 		if (i == acc)
505 			acc = 1;
506 		else
507 			acc = 0;
508 		goto a0;
509 	case '>':
510 		k = 0;
511 		if (cbits(ii = getch()) == '=')
512 			k++;
513 		else
514 			ch = ii;
515 		i = ckph();
516 		if (nonumb) {
517 			acc = 0;
518 			break;
519 		}
520 		if (acc > (i - k))
521 			acc = 1;
522 		else
523 			acc = 0;
524 		goto a0;
525 	case '<':
526 		k = 0;
527 		if (cbits(ii = getch()) == '=')
528 			k++;
529 		else
530 			ch = ii;
531 		i = ckph();
532 		if (nonumb) {
533 			acc = 0;
534 			break;
535 		}
536 		if (acc < (i + k))
537 			acc = 1;
538 		else
539 			acc = 0;
540 		goto a0;
541 	case ')':
542 		break;
543 	case '(':
544 		acc = atoi0();
545 		goto a0;
546 	}
547 	return(acc);
548 }
549 
550 
551 long	ckph()
552 {
553 	tchar i;
554 	long	j;
555 	extern long	atoi0();
556 	extern long	atoi1();
557 
558 	if (cbits(i = getch()) == '(')
559 		j = atoi0();
560 	else {
561 		j = atoi1(i);
562 	}
563 	return(j);
564 }
565 
566 
567 long	atoi1(ii)
568 tchar ii;
569 {
570 	int	i, j, digits;
571 	long	acc;
572 	int	neg, abs, field;
573 
574 	neg = abs = field = digits = 0;
575 	acc = 0;
576 	for (;;) {
577 		i = cbits(ii);
578 		switch (i) {
579 		default:
580 			break;
581 		case '+':
582 			ii = getch();
583 			continue;
584 		case '-':
585 			neg = 1;
586 			ii = getch();
587 			continue;
588 		case '|':
589 			abs = 1 + neg;
590 			neg = 0;
591 			ii = getch();
592 			continue;
593 		}
594 		break;
595 	}
596 a1:
597 	while (i >= '0' && i <= '9') {
598 		field++;
599 		digits++;
600 		acc = 10 * acc + i - '0';
601 		ii = getch();
602 		i = cbits(ii);
603 	}
604 	if (i == '.') {
605 		field++;
606 		digits = 0;
607 		ii = getch();
608 		i = cbits(ii);
609 		goto a1;
610 	}
611 	if (!field) {
612 		ch = ii;
613 		goto a2;
614 	}
615 	switch (i) {
616 	case 'u':
617 		i = j = 1;	/* should this be related to HOR?? */
618 		break;
619 	case 'v':	/*VSs - vert spacing*/
620 		j = lss;
621 		i = 1;
622 		break;
623 	case 'm':	/*Ems*/
624 		j = EM;
625 		i = 1;
626 		break;
627 	case 'n':	/*Ens*/
628 		j = EM;
629 #ifndef NROFF
630 		i = 2;
631 #endif
632 #ifdef NROFF
633 		i = 1;	/*Same as Ems in NROFF*/
634 #endif
635 		break;
636 	case 'p':	/*Points*/
637 		j = INCH;
638 		i = 72;
639 		break;
640 	case 'i':	/*Inches*/
641 		j = INCH;
642 		i = 1;
643 		break;
644 	case 'c':	/*Centimeters*/
645 		/* if INCH is too big, this will overflow */
646 		j = INCH * 50;
647 		i = 127;
648 		break;
649 	case 'P':	/*Picas*/
650 		j = INCH;
651 		i = 6;
652 		break;
653 	default:
654 		j = dfact;
655 		ch = ii;
656 		i = dfactd;
657 	}
658 	if (neg)
659 		acc = -acc;
660 	if (!noscale) {
661 		acc = (acc * j) / i;
662 	}
663 	if ((field != digits) && (digits > 0))
664 		while (digits--)
665 			acc /= 10;
666 	if (abs) {
667 		if (dip != d)
668 			j = dip->dnl;
669 		else
670 			j = numtab[NL].val;
671 		if (!vflag) {
672 			j = numtab[HP].val;
673 		}
674 		if (abs == 2)
675 			j = -j;
676 		acc -= j;
677 	}
678 a2:
679 	nonumb = !field;
680 	return(acc);
681 }
682 
683 
684 int
685 caserr()
686 {
687 	int	i, j;
688 	struct numtab *p;
689 
690 	lgf++;
691 	while (!skip() && (i = getrq()) ) {
692 		j = usedr(i);
693 		if (j < 0)
694 			continue;
695 		p = &numtab[j];
696 		nunhash(p);
697 		p->r = p->val = p->inc = p->fmt = 0;
698 		regcnt--;
699 	}
700 
701 	return (0);
702 }
703 
704 
705 int
706 casenr()
707 {
708 	int	i, j;
709 
710 	lgf++;
711 	skip();
712 	if ((i = findr(getrq())) == -1)
713 		goto rtn;
714 	skip();
715 	j = inumb(&numtab[i].val);
716 	if (nonumb)
717 		goto rtn;
718 	numtab[i].val = j;
719 	skip();
720 	j = atoi();
721 	if (nonumb)
722 		goto rtn;
723 	numtab[i].inc = j;
724 rtn:
725 	return (0);
726 }
727 
728 
729 int
730 caseaf()
731 {
732 	int	i, k;
733 	tchar j, jj;
734 
735 	lgf++;
736 	if (skip() || !(i = getrq()) || skip())
737 		return (0);
738 	k = 0;
739 	j = getch();
740 	if (!ischar(jj = cbits(j)) || !isalpha(jj)) {
741 		ch = j;
742 		while ((j = cbits(getch())) >= '0' &&  j <= '9')
743 			k++;
744 	}
745 	if (!k)
746 		k = j;
747 	numtab[findr(i)].fmt = k & BYTEMASK;
748 
749 	return (0);
750 }
751 
752 int
753 setaf()	/* return format of number register */
754 {
755 	int i, j;
756 
757 	i = usedr(getsn());
758 	if (i == -1)
759 		return (0);
760 	if (numtab[i].fmt > 20)	/* it was probably a, A, i or I */
761 		*pbp++ = numtab[i].fmt;
762 	else
763 		for (j = (numtab[i].fmt ? numtab[i].fmt : 1); j; j--)
764 			*pbp++ = '0';
765 
766 	return (0);
767 }
768 
769 
770 int
771 vnumb(i)
772 int	*i;
773 {
774 	vflag++;
775 	dfact = lss;
776 	res = VERT;
777 	return(inumb(i));
778 }
779 
780 
781 int
782 hnumb(i)
783 int	*i;
784 {
785 	dfact = EM;
786 	res = HOR;
787 	return(inumb(i));
788 }
789 
790 
791 int
792 inumb(n)
793 int	*n;
794 {
795 	int	i, j, f;
796 	tchar ii;
797 
798 	f = 0;
799 	if (n) {
800 		if ((j = cbits(ii = getch())) == '+')
801 			f = 1;
802 		else if (j == '-')
803 			f = -1;
804 		else
805 			ch = ii;
806 	}
807 	i = atoi();
808 	if (n && f)
809 		i = *n + f * i;
810 	i = quant(i, res);
811 	vflag = 0;
812 	res = dfactd = dfact = 1;
813 	if (nonumb)
814 		i = 0;
815 	return(i);
816 }
817 
818 
819 int
820 quant(n, m)
821 int	n, m;
822 {
823 	int	i, neg;
824 
825 	neg = 0;
826 	if (n < 0) {
827 		neg++;
828 		n = -n;
829 	}
830 	/* better as i = ((n + (m/2))/m)*m */
831 	i = n / m;
832 	if ((n - m * i) > (m / 2))
833 		i += 1;
834 	i *= m;
835 	if (neg)
836 		i = -i;
837 	return(i);
838 }
839 
840 
841