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