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
55int	regcnt = NNAMES;
56int	falsef	= 0;	/* on if inside false branch of if */
57#define	NHASH(i)	((i>>6)^i)&0177
58struct	numtab	*nhash[128];	/* 128 == the 0177 on line above */
59
60int
61setn()
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 {
180s0:
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
193tchar	numbuf[17];
194tchar	*numbufp;
195
196int
197wrc(i)
198tchar 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 */
209int
210setn1(i, form, bits)
211int	i;
212tchar 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
227int
228nrehash()
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
248int
249nunhash(rp)
250struct 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
271int
272findr(i)
273int	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
299int
300usedr(i)	/* returns -1 if nr i has never been used */
301int	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
314int
315fnumb(i, f)
316int	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
345int
346decml(i, f)
347int	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
359int
360roman(i, f)
361int	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
373int
374roman0(i, f, onesp, fivesp)
375int	i, (*f)();
376char	*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
402int
403abc(i, f)
404int	i, (*f)();
405{
406	if (!i)
407		return((*f)('0' | nrbits));
408	else
409		return(abc0(i - 1, f));
410}
411
412
413int
414abc0(i, f)
415int	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
425long	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;
436a0:
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
553long	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
569long	atoi1(ii)
570tchar 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	}
598a1:
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	}
680a2:
681	nonumb = !field;
682	return(acc);
683}
684
685
686int
687caserr()
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
707int
708casenr()
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;
726rtn:
727	return (0);
728}
729
730
731int
732caseaf()
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
754int
755setaf()	/* 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
772int
773vnumb(i)
774int	*i;
775{
776	vflag++;
777	dfact = lss;
778	res = VERT;
779	return(inumb(i));
780}
781
782
783int
784hnumb(i)
785int	*i;
786{
787	dfact = EM;
788	res = HOR;
789	return(inumb(i));
790}
791
792
793int
794inumb(n)
795int	*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
821int
822quant(n, m)
823int	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