1 /*
2  * troff4.c
3  *
4  * number registers, conversion, arithmetic
5  */
6 
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
10 
11 
12 int	regcnt = NNAMES;
13 int	falsef	= 0;	/* on if inside false branch of if */
14 
15 #define	NHASHSIZE	128	/* must be 2**n */
16 #define	NHASH(i)	((i>>6)^i) & (NHASHSIZE-1)
17 Numtab	*nhash[NHASHSIZE];
18 
19 Numtab *numtabp = NULL;
20 #define NDELTA 400
21 int ncnt = 0;
22 
setn(void)23 void setn(void)
24 {
25 	int i, j, f;
26 	Tchar ii;
27 	Uchar *p;
28 	char buf[NTM];		/* for \n(.S */
29 
30 	f = nform = 0;
31 	if ((i = cbits(ii = getach())) == '+')
32 		f = 1;
33 	else if (i == '-')
34 		f = -1;
35 	else if (ii)	/* don't put it back if it's already back (thanks to jaap) */
36 		ch = ii;
37 	if (falsef)
38 		f = 0;
39 	if ((i = getsn()) == 0)
40 		return;
41 	p = unpair(i);
42 	if (p[0] == '.')
43 		switch (p[1]) {
44 		case 's':
45 			i = pts;
46 			break;
47 		case 'v':
48 			i = lss;
49 			break;
50 		case 'f':
51 			i = font;
52 			break;
53 		case 'p':
54 			i = pl;
55 			break;
56 		case 't':
57 			i = findt1();
58 			break;
59 		case 'o':
60 			i = po;
61 			break;
62 		case 'l':
63 			i = ll;
64 			break;
65 		case 'i':
66 			i = in;
67 			break;
68 		case '$':
69 			i = frame->nargs;
70 			break;
71 		case 'A':
72 			i = ascii;
73 			break;
74 		case 'c':
75 			i = numtabp[CD].val;
76 			break;
77 		case 'n':
78 			i = lastl;
79 			break;
80 		case 'a':
81 			i = ralss;
82 			break;
83 		case 'h':
84 			i = dip->hnl;
85 			break;
86 		case 'd':
87 			if (dip != d)
88 				i = dip->dnl;
89 			else
90 				i = numtabp[NL].val;
91 			break;
92 		case 'u':
93 			i = fi;
94 			break;
95 		case 'j':
96 			i = ad + 2 * admod;
97 			break;
98 		case 'w':
99 			i = widthp;
100 			break;
101 		case 'x':
102 			i = nel;
103 			break;
104 		case 'y':
105 			i = un;
106 			break;
107 		case 'T':
108 			i = dotT;
109 			break;	 /* -Tterm used in nroff */
110 		case 'V':
111 			i = VERT;
112 			break;
113 		case 'H':
114 			i = HOR;
115 			break;
116 		case 'k':
117 			i = ne;
118 			break;
119 		case 'P':
120 			i = print;
121 			break;
122 		case 'L':
123 			i = ls;
124 			break;
125 		case 'R':	/* maximal # of regs that can be addressed */
126 			i = 255*256 - regcnt;
127 			break;
128 		case 'z':
129 			p = unpair(dip->curd);
130 			*pbp++ = p[1];	/* watch order */
131 			*pbp++ = p[0];
132 			return;
133 		case 'b':
134 			i = bdtab[font];
135 			break;
136 		case 'F':
137 			cpushback(cfname[ifi]);
138 			return;
139  		case 'S':
140  			buf[0] = j = 0;
141  			for( i = 0; tabtab[i] != 0 && i < NTAB; i++) {
142  				if (i > 0)
143  					buf[j++] = ' ';
144  				sprintf(&buf[j], "%ld", tabtab[i] & TABMASK);
145  				j = strlen(buf);
146  				if ( tabtab[i] & RTAB)
147  					sprintf(&buf[j], "uR");
148  				else if (tabtab[i] & CTAB)
149  					sprintf(&buf[j], "uC");
150  				else
151  					sprintf(&buf[j], "uL");
152  				j += 2;
153  			}
154  			cpushback(buf);
155  			return;
156 		default:
157 			goto s0;
158 		}
159 	else {
160 s0:
161 		if ((j = findr(i)) == -1)
162 			i = 0;
163 		else {
164 			i = numtabp[j].val = numtabp[j].val + numtabp[j].inc * f;
165 			nform = numtabp[j].fmt;
166 		}
167 	}
168 	setn1(i, nform, (Tchar) 0);
169 }
170 
171 Tchar	numbuf[25];
172 Tchar	*numbufp;
173 
wrc(Tchar i)174 int wrc(Tchar i)
175 {
176 	if (numbufp >= &numbuf[24])
177 		return(0);
178 	*numbufp++ = i;
179 	return(1);
180 }
181 
182 
183 
184 /* insert into input number i, in format form, with size-font bits bits */
setn1(int i,int form,Tchar bits)185 void setn1(int i, int form, Tchar bits)
186 {
187 	numbufp = numbuf;
188 	nrbits = bits;
189 	nform = form;
190 	fnumb(i, wrc);
191 	*numbufp = 0;
192 	pushback(numbuf);
193 }
194 
prnumtab(Numtab * p)195 void prnumtab(Numtab *p)
196 {
197 	int i;
198 	for (i = 0; i < ncnt; i++)
199 		if (p)
200 			if (p[i].r != 0)
201 				fprintf(stderr, "slot %d, %s, val %d\n", i, unpair(p[i].r), p[i].val);
202 			else
203 				fprintf(stderr, "slot %d empty\n", i);
204 		else
205 			fprintf(stderr, "slot %d empty\n", i);
206 }
207 
nnspace(void)208 void nnspace(void)
209 {
210 	ncnt = sizeof(numtab)/sizeof(Numtab) + NDELTA;
211 	numtabp = (Numtab *) grow((char *)numtabp, ncnt, sizeof(Numtab));
212 	if (numtabp == NULL) {
213 		ERROR "not enough memory for registers (%d)", ncnt WARN;
214 		exit(1);
215 	}
216 	numtabp = (Numtab *) memcpy((char *)numtabp, (char *)numtab,
217 							sizeof(numtab));
218 	if (numtabp == NULL) {
219 		ERROR "Cannot initialize registers" WARN;
220 		exit(1);
221 	}
222 }
223 
grownumtab(void)224 void grownumtab(void)
225 {
226 	ncnt += NDELTA;
227 	numtabp = (Numtab *) grow((char *) numtabp, ncnt, sizeof(Numtab));
228 	if (numtabp == NULL) {
229 		ERROR "Too many number registers (%d)", ncnt WARN;
230 		done2(04);
231 	} else {
232 		memset((char *)(numtabp) + (ncnt - NDELTA) * sizeof(Numtab),
233 						0, NDELTA * sizeof(Numtab));
234 		nrehash();
235 	}
236 }
237 
nrehash(void)238 void nrehash(void)
239 {
240 	Numtab *p;
241 	int i;
242 
243 	for (i=0; i<NHASHSIZE; i++)
244 		nhash[i] = 0;
245 	for (p=numtabp; p < &numtabp[ncnt]; p++)
246 		p->link = 0;
247 	for (p=numtabp; p < &numtabp[ncnt]; p++) {
248 		if (p->r == 0)
249 			continue;
250 		i = NHASH(p->r);
251 		p->link = nhash[i];
252 		nhash[i] = p;
253 	}
254 }
255 
nunhash(Numtab * rp)256 void nunhash(Numtab *rp)
257 {
258 	Numtab *p;
259 	Numtab **lp;
260 
261 	if (rp->r == 0)
262 		return;
263 	lp = &nhash[NHASH(rp->r)];
264 	p = *lp;
265 	while (p) {
266 		if (p == rp) {
267 			*lp = p->link;
268 			p->link = 0;
269 			return;
270 		}
271 		lp = &p->link;
272 		p = p->link;
273 	}
274 }
275 
findr(int i)276 int findr(int i)
277 {
278 	Numtab *p;
279 	int h = NHASH(i);
280 
281 	if (i == 0)
282 		return(-1);
283 a0:
284 	for (p = nhash[h]; p; p = p->link)
285 		if (i == p->r)
286 			return(p - numtabp);
287 	for (p = numtabp; p < &numtabp[ncnt]; p++) {
288 		if (p->r == 0) {
289 			p->r = i;
290 			p->link = nhash[h];
291 			nhash[h] = p;
292 			regcnt++;
293 			return(p - numtabp);
294 		}
295 	}
296 	grownumtab();
297 	goto a0;
298 }
299 
usedr(int i)300 int usedr(int i)	/* returns -1 if nr i has never been used */
301 {
302 	Numtab *p;
303 
304 	if (i == 0)
305 		return(-1);
306 	for (p = nhash[NHASH(i)]; p; p = p->link)
307 		if (i == p->r)
308 			return(p - numtabp);
309 	return -1;
310 }
311 
312 
fnumb(int i,int (* f)(Tchar))313 int fnumb(int i, int (*f)(Tchar))
314 {
315 	int j;
316 
317 	j = 0;
318 	if (i < 0) {
319 		j = (*f)('-' | nrbits);
320 		i = -i;
321 	}
322 	switch (nform) {
323 	default:
324 	case '1':
325 	case 0:
326 		return decml(i, f) + j;
327 	case 'i':
328 	case 'I':
329 		return roman(i, f) + j;
330 	case 'a':
331 	case 'A':
332 		return abc(i, f) + j;
333 	}
334 }
335 
336 
decml(int i,int (* f)(Tchar))337 int decml(int i, int (*f)(Tchar))
338 {
339 	int j, k;
340 
341 	k = 0;
342 	nform--;
343 	if ((j = i / 10) || (nform > 0))
344 		k = decml(j, f);
345 	return(k + (*f)((i % 10 + '0') | nrbits));
346 }
347 
348 
roman(int i,int (* f)(Tchar))349 int roman(int i, int (*f)(Tchar))
350 {
351 
352 	if (!i)
353 		return((*f)('0' | nrbits));
354 	if (nform == 'i')
355 		return(roman0(i, f, "ixcmz", "vldw"));
356 	else
357 		return(roman0(i, f, "IXCMZ", "VLDW"));
358 }
359 
360 
roman0(int i,int (* f)(Tchar),char * onesp,char * fivesp)361 int roman0(int i, int (*f)(Tchar), char *onesp, char *fivesp)
362 {
363 	int q, rem, k;
364 
365 	if (!i)
366 		return(0);
367 	k = roman0(i / 10, f, onesp + 1, fivesp + 1);
368 	q = (i = i % 10) / 5;
369 	rem = i % 5;
370 	if (rem == 4) {
371 		k += (*f)(*onesp | nrbits);
372 		if (q)
373 			i = *(onesp + 1);
374 		else
375 			i = *fivesp;
376 		return(k += (*f)(i | nrbits));
377 	}
378 	if (q)
379 		k += (*f)(*fivesp | nrbits);
380 	while (--rem >= 0)
381 		k += (*f)(*onesp | nrbits);
382 	return(k);
383 }
384 
385 
abc(int i,int (* f)(Tchar))386 int abc(int i, int (*f)(Tchar))
387 {
388 	if (!i)
389 		return((*f)('0' | nrbits));
390 	else
391 		return(abc0(i - 1, f));
392 }
393 
394 
abc0(int i,int (* f)(Tchar))395 int abc0(int i, int (*f)(Tchar))
396 {
397 	int j, k;
398 
399 	k = 0;
400 	if (j = i / 26)
401 		k = abc0(j - 1, f);
402 	return(k + (*f)((i % 26 + nform) | nrbits));
403 }
404 
atoi0(void)405 long atoi0(void)
406 {
407 	int c, k, cnt;
408 	Tchar ii;
409 	long i, acc;
410 
411 	acc = 0;
412 	nonumb = 0;
413 	cnt = -1;
414 a0:
415 	cnt++;
416 	ii = getch();
417 	c = cbits(ii);
418 	switch (c) {
419 	default:
420 		ch = ii;
421 		if (cnt)
422 			break;
423 	case '+':
424 		i = ckph();
425 		if (nonumb)
426 			break;
427 		acc += i;
428 		goto a0;
429 	case '-':
430 		i = ckph();
431 		if (nonumb)
432 			break;
433 		acc -= i;
434 		goto a0;
435 	case '*':
436 		i = ckph();
437 		if (nonumb)
438 			break;
439 		acc *= i;
440 		goto a0;
441 	case '/':
442 		i = ckph();
443 		if (nonumb)
444 			break;
445 		if (i == 0) {
446 			flusho();
447 			ERROR "divide by zero." WARN;
448 			acc = 0;
449 		} else
450 			acc /= i;
451 		goto a0;
452 	case '%':
453 		i = ckph();
454 		if (nonumb)
455 			break;
456 		acc %= i;
457 		goto a0;
458 	case '&':	/*and*/
459 		i = ckph();
460 		if (nonumb)
461 			break;
462 		if ((acc > 0) && (i > 0))
463 			acc = 1;
464 		else
465 			acc = 0;
466 		goto a0;
467 	case ':':	/*or*/
468 		i = ckph();
469 		if (nonumb)
470 			break;
471 		if ((acc > 0) || (i > 0))
472 			acc = 1;
473 		else
474 			acc = 0;
475 		goto a0;
476 	case '=':
477 		if (cbits(ii = getch()) != '=')
478 			ch = ii;
479 		i = ckph();
480 		if (nonumb) {
481 			acc = 0;
482 			break;
483 		}
484 		if (i == acc)
485 			acc = 1;
486 		else
487 			acc = 0;
488 		goto a0;
489 	case '>':
490 		k = 0;
491 		if (cbits(ii = getch()) == '=')
492 			k++;
493 		else
494 			ch = ii;
495 		i = ckph();
496 		if (nonumb) {
497 			acc = 0;
498 			break;
499 		}
500 		if (acc > (i - k))
501 			acc = 1;
502 		else
503 			acc = 0;
504 		goto a0;
505 	case '<':
506 		k = 0;
507 		if (cbits(ii = getch()) == '=')
508 			k++;
509 		else
510 			ch = ii;
511 		i = ckph();
512 		if (nonumb) {
513 			acc = 0;
514 			break;
515 		}
516 		if (acc < (i + k))
517 			acc = 1;
518 		else
519 			acc = 0;
520 		goto a0;
521 	case ')':
522 		break;
523 	case '(':
524 		acc = atoi0();
525 		goto a0;
526 	}
527 	return(acc);
528 }
529 
530 
ckph(void)531 long ckph(void)
532 {
533 	Tchar i;
534 	long j;
535 
536 	if (cbits(i = getch()) == '(')
537 		j = atoi0();
538 	else {
539 		j = atoi1(i);
540 	}
541 	return(j);
542 }
543 
544 
545 /*
546  * print error about illegal numeric argument;
547  */
prnumerr(void)548 void prnumerr(void)
549 {
550 	char err_buf[40];
551 	static char warn[] = "Numeric argument expected";
552 	int savcd = numtabp[CD].val;
553 
554 	if (numerr.type == RQERR)
555 		sprintf(err_buf, "%c%s: %s", nb ? cbits(c2) : cbits(cc),
556 						unpair(numerr.req), warn);
557 	else
558 		sprintf(err_buf, "\\%c'%s': %s", numerr.esc, &numerr.escarg,
559 									warn);
560 	if (frame != stk)	/* uncertainty correction */
561 		numtabp[CD].val--;
562 	ERROR "%s", err_buf WARN;
563 	numtabp[CD].val = savcd;
564 }
565 
566 
atoi1(Tchar ii)567 long atoi1(Tchar ii)
568 {
569 	int i, j, digits;
570 	double acc;	/* this is the only double in troff! */
571 	int neg, abs, field, decpnt;
572 	extern int ifnum;
573 
574 
575 	neg = abs = field = decpnt = digits = 0;
576 	acc = 0;
577 	for (;;) {
578 		i = cbits(ii);
579 		switch (i) {
580 		default:
581 			break;
582 		case '+':
583 			ii = getch();
584 			continue;
585 		case '-':
586 			neg = 1;
587 			ii = getch();
588 			continue;
589 		case '|':
590 			abs = 1 + neg;
591 			neg = 0;
592 			ii = getch();
593 			continue;
594 		}
595 		break;
596 	}
597 a1:
598 	while (i >= '0' && i <= '9') {
599 		field++;
600 		digits++;
601 		acc = 10 * acc + i - '0';
602 		ii = getch();
603 		i = cbits(ii);
604 	}
605 	if (i == '.' && !decpnt++) {
606 		field++;
607 		digits = 0;
608 		ii = getch();
609 		i = cbits(ii);
610 		goto a1;
611 	}
612 	if (!field) {
613 		ch = ii;
614 		goto a2;
615 	}
616 	switch (i) {
617 	case 'u':
618 		i = j = 1;	/* should this be related to HOR?? */
619 		break;
620 	case 'v':	/*VSs - vert spacing*/
621 		j = lss;
622 		i = 1;
623 		break;
624 	case 'm':	/*Ems*/
625 		j = EM;
626 		i = 1;
627 		break;
628 	case 'n':	/*Ens*/
629 		j = EM;
630 		if (TROFF)
631 			i = 2;
632 		else
633 			i = 1;	/*Same as Ems in NROFF*/
634 		break;
635 	case 'p':	/*Points*/
636 		j = INCH;
637 		i = 72;
638 		break;
639 	case 'i':	/*Inches*/
640 		j = INCH;
641 		i = 1;
642 		break;
643 	case 'c':	/*Centimeters*/
644 		/* if INCH is too big, this will overflow */
645 		j = INCH * 50;
646 		i = 127;
647 		break;
648 	case 'P':	/*Picas*/
649 		j = INCH;
650 		i = 6;
651 		break;
652 	default:
653 		j = dfact;
654 		ch = ii;
655 		i = dfactd;
656 	}
657 	if (neg)
658 		acc = -acc;
659 	if (!noscale) {
660 		acc = (acc * j) / i;
661 	}
662 	if (field != digits && digits > 0)
663 		while (digits--)
664 			acc /= 10;
665 	if (abs) {
666 		if (dip != d)
667 			j = dip->dnl;
668 		else
669 			j = numtabp[NL].val;
670 		if (!vflag) {
671 			j = numtabp[HP].val;
672 		}
673 		if (abs == 2)
674 			j = -j;
675 		acc -= j;
676 	}
677 a2:
678 	nonumb = (!field || field == decpnt);
679 	if (nonumb && (trace & TRNARGS) && !ismot(ii) && !nlflg && !ifnum) {
680 		if (cbits(ii) != RIGHT ) /* Too painful to do right */
681 			prnumerr();
682 	}
683 	return(acc);
684 }
685 
686 
caserr(void)687 void caserr(void)
688 {
689 	int i, j;
690 	Numtab *p;
691 
692 	lgf++;
693 	while (!skip() && (i = getrq()) ) {
694 		j = usedr(i);
695 		if (j < 0)
696 			continue;
697 		p = &numtabp[j];
698 		nunhash(p);
699 		p->r = p->val = p->inc = p->fmt = 0;
700 		regcnt--;
701 	}
702 }
703 
704 /*
705  * .nr request; if tracing, don't check optional
706  * 2nd argument because tbl generates .in 1.5n
707  */
casenr(void)708 void casenr(void)
709 {
710 	int i, j;
711 	int savtr = trace;
712 
713 	lgf++;
714 	skip();
715 	if ((i = findr(getrq())) == -1)
716 		goto rtn;
717 	skip();
718 	j = inumb(&numtabp[i].val);
719 	if (nonumb)
720 		goto rtn;
721 	numtabp[i].val = j;
722 	skip();
723 	trace = 0;
724 	j = atoi0();		/* BUG??? */
725 	trace = savtr;
726 	if (nonumb)
727 		goto rtn;
728 	numtabp[i].inc = j;
729 rtn:
730 	return;
731 }
732 
caseaf(void)733 void caseaf(void)
734 {
735 	int i, k;
736 	Tchar j;
737 
738 	lgf++;
739 	if (skip() || !(i = getrq()) || skip())
740 		return;
741 	k = 0;
742 	j = getch();
743 	if (!isalpha(cbits(j))) {
744 		ch = j;
745 		while ((j = cbits(getch())) >= '0' &&  j <= '9')
746 			k++;
747 	}
748 	if (!k)
749 		k = j;
750 	numtabp[findr(i)].fmt = k;	/* was k & BYTEMASK */
751 }
752 
setaf(void)753 void setaf(void)	/* return format of number register */
754 {
755 	int i, j;
756 
757 	i = usedr(getsn());
758 	if (i == -1)
759 		return;
760 	if (numtabp[i].fmt > 20)	/* it was probably a, A, i or I */
761 		*pbp++ = numtabp[i].fmt;
762 	else
763 		for (j = (numtabp[i].fmt ? numtabp[i].fmt : 1); j; j--)
764 			*pbp++ = '0';
765 }
766 
767 
vnumb(int * i)768 int vnumb(int *i)
769 {
770 	vflag++;
771 	dfact = lss;
772 	res = VERT;
773 	return(inumb(i));
774 }
775 
776 
hnumb(int * i)777 int hnumb(int *i)
778 {
779 	dfact = EM;
780 	res = HOR;
781 	return(inumb(i));
782 }
783 
784 
inumb(int * n)785 int inumb(int *n)
786 {
787 	int i, j, f;
788 	Tchar ii;
789 
790 	f = 0;
791 	if (n) {
792 		if ((j = cbits(ii = getch())) == '+')
793 			f = 1;
794 		else if (j == '-')
795 			f = -1;
796 		else
797 			ch = ii;
798 	}
799 	i = atoi0();
800 	if (n && f)
801 		i = *n + f * i;
802 	i = quant(i, res);
803 	vflag = 0;
804 	res = dfactd = dfact = 1;
805 	if (nonumb)
806 		i = 0;
807 	return(i);
808 }
809 
810 
quant(int n,int m)811 int quant(int n, int m)
812 {
813 	int i, neg;
814 
815 	neg = 0;
816 	if (n < 0) {
817 		neg++;
818 		n = -n;
819 	}
820 	/* better as i = ((n + m/2)/m)*m */
821 	i = n / m;
822 	if (n - m * i > m / 2)
823 		i += 1;
824 	i *= m;
825 	if (neg)
826 		i = -i;
827 	return(i);
828 }
829