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