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