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