xref: /original-bsd/old/roff/common_source/n4.c (revision 81aa1937)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)n4.c	4.2 (Berkeley) 04/18/91";
10 #endif /* not lint */
11 
12 #include "tdef.h"
13 extern
14 #include "d.h"
15 extern
16 #include "v.h"
17 #ifdef NROFF
18 extern
19 #include "tw.h"
20 #endif
21 #include "sdef.h"
22 /*
23 troff4.c
24 
25 number registers, conversion, arithmetic
26 */
27 
28 extern	int	inchar[LNSIZE], *pinchar;	/* XXX */
29 extern struct s *frame;
30 
31 extern int ascii;
32 extern int cbuf[NC];
33 extern int *cp;
34 extern int r[NN];
35 extern int *vlist;
36 extern int inc[NN];
37 extern int fmt[NN];
38 extern int ch;
39 extern int lgf;
40 extern int pl;
41 extern int lastl;
42 extern int ralss;
43 extern int totout;
44 extern int nrbits;
45 extern int nonumb;
46 extern int vflag;
47 extern int noscale;
48 extern int dfact;
49 extern int dfactd;
50 extern int po;
51 extern int nform;
52 extern int ll;
53 extern int in;
54 extern int font;
55 extern int bdtab[];
56 extern int lss;
57 extern int pts;
58 extern int fi;
59 extern int res;
60 extern int cwidth;
61 extern int dotT;
62 extern int ev;
63 extern int ne;
64 extern int ad, admod;
65 extern int print;
66 extern int ls;
67 extern int nel, un;
68 extern int xxx;
69 int regcnt = NNAMES;
70 
71 setn()
72 {
73 	register i,j;
74 	int f;
75 
76 	f = nform = 0;
77 	if((i=getch() & CMASK) == '+')f = 1;
78 		else if(i == '-')f = -1;
79 			else ch = i;
80 	if((i=getsn()) == 0)return;
81 	if((i & 0177) == '.')switch(i>>BYTE){
82 		case 's': i = pts & 077;	break;
83 		case 'v': i = lss;		break;
84 		case 'f': i = font + 1;	break;
85 		case 'p': i = pl;		break;
86 		case 't':  i = findt1();	break;
87 		case 'o': i = po;		break;
88 		case 'l': i = ll;		break;
89 		case 'i': i = in;		break;
90 		case '$': i = frame->nargs;		break;
91 		case 'A': i = ascii;		break;
92 		case 'c': i = v.cd;		break;
93 		case 'n': i = lastl;		break;
94 		case 'a': i = ralss;		break;
95 		case 'h': i = dip->hnl;	break;
96 		case 'd':
97 			if(dip != d)i = dip->dnl; else i = v.nl;
98 			break;
99 		case 'u': i = fi;		break;
100 		case 'j': i = ad + 2*admod;	break;
101 		case 'w': i = width(*(pinchar-1));		break;	/* XXX */
102 		case 'x': i = nel;	break;
103 		case 'y': i = un;		break;
104 		case 'T': i = dotT;		break; /*-Tterm used in nroff*/
105 		case 'V': i = VERT;		break;
106 		case 'H': i = HOR;		break;
107 		case 'k': i = ne;		break;
108 		case 'P': i = print;		break;
109 		case 'L': i = ls;		break;
110 		case 'R': i = NN - regcnt;	break;
111 		case 'z': i = dip->curd;
112 			cbuf[0] = i & BMASK;
113 			cbuf[1] = (i >> BYTE) & BMASK;
114 			cbuf[2] = 0;
115 			cp = cbuf;
116 			return;
117 #ifndef NROFF
118 		case 'b': i = bdtab[font];		break;
119 #endif
120 
121 		default:
122 			goto s0;
123 	}
124 	else{
125 s0:
126 		if((j=findr(i)) == -1)i = 0;
127 		else{
128 			i = (vlist[j] = (vlist[j] + inc[j]*f));
129 			nform = fmt[j];
130 		}
131 	}
132 	setn1(i);
133 	cp = cbuf;
134 }
135 setn1(i)
136 int i;
137 {
138 	extern int wrc();
139 
140 	cp = cbuf;
141 	nrbits = 0;
142 	fnumb(i,wrc);
143 	*cp = 0;
144 	cp = cbuf;
145 }
146 findr(i)
147 int i;
148 {
149 	register j;
150 	static int numerr;
151 
152 	if(i == 0)return(-1);
153 	for(j=0;j<NN;j++){
154 		if(i == r[j])break;
155 	}
156 	if(j != NN)return(j);
157 	for(j=0; j<NN; j++){
158 		if(r[j] == 0){
159 			r[j] = i;
160 			regcnt++;
161 			break;
162 		}
163 	}
164 	if(j==NN){
165 		if(!numerr)prstrfl("Too many number registers.\n");
166 		if(++numerr > 1)done2(04); else edone(04);
167 	}
168 	return(j);
169 }
170 fnumb(i,f)
171 int i, (*f)();
172 {
173 	register j;
174 
175 	j = 0;
176 	if(i < 0){
177 		j = (*f)('-' | nrbits);
178 		i = -i;
179 	}
180 	switch(nform){
181 		default:
182 		case '1':
183 		case 0: return(decml(i,f) + j);
184 		case 'i':
185 		case 'I': return(roman(i,f) + j);
186 		case 'a':
187 		case 'A': return(abc(i,f) + j);
188 	}
189 }
190 decml(i,f)
191 int i, (*f)();
192 {
193 	register j,k;
194 
195 	k = 0;
196 	nform--;
197 	if((j=i/10) || (nform > 0))k = decml(j,f);
198 	return(k + (*f)((i%10 + '0') | nrbits));
199 }
200 roman(i,f)
201 int i, (*f)();
202 {
203 
204 	if(!i)return((*f)('0' | nrbits));
205 	if(nform == 'i')return(roman0(i,f,"ixcmz","vldw"));
206 	else return(roman0(i,f,"IXCMZ","VLDW"));
207 }
208 roman0(i,f,onesp,fivesp)
209 int i, (*f)();
210 char *onesp, *fivesp;
211 {
212 	register q, rem, k;
213 
214 	k = 0;
215 	if(!i)return(0);
216 	k = roman0(i/10,f,onesp+1,fivesp+1);
217 	q = (i=i%10)/5;
218 	rem = i%5;
219 	if(rem == 4){
220 		k += (*f)(*onesp | nrbits);
221 		if(q)i = *(onesp+1);
222 			else i = *fivesp;
223 		return(k += (*f)(i | nrbits));
224 	}
225 	if(q)k += (*f)(*fivesp | nrbits);
226 	while(--rem >= 0)
227 		k += (*f)(*onesp | nrbits);
228 	return(k);
229 }
230 abc(i,f)
231 int i, (*f)();
232 {
233 	if(!i)return((*f)('0' | nrbits));
234 	else return(abc0(i-1,f));
235 }
236 abc0(i,f)
237 int i, (*f)();
238 {
239 	register j, k;
240 
241 	k = 0;
242 	if(j=i/26)k = abc0(j-1,f);
243 	return(k + (*f)((i%26 + nform) | nrbits));
244 }
245 wrc(i)
246 int i;
247 {
248 	if(cp >= &cbuf[NC])return(0);
249 	*cp++ = i;
250 	return(1);
251 }
252 atoi(){
253 	extern long atoi0();
254 
255 	return((int)atoi0());
256 }
257 long atoi0()
258 {
259 	register ii, k, cnt;
260 	long i, acc;
261 	extern long ckph();
262 
263 	i = 0; acc = 0;
264 	nonumb = 0;
265 	cnt = -1;
266 a0:
267 	cnt++;
268 	switch((ii=getch()) & CMASK){
269 		default:
270 			ch = ii;
271 			if(cnt)break;
272 		case '+':
273 			i = ckph();
274 			if(nonumb)break;
275 			acc += i;
276 			goto a0;
277 		case '-':
278 			i = ckph();
279 			if(nonumb)break;
280 			acc -= i;
281 			goto a0;
282 		case '*':
283 			i = ckph();
284 			if(nonumb)break;
285 			acc *= i;
286 			goto a0;
287 		case '/':
288 			i = ckph();
289 			if(nonumb)break;
290 			if(i == 0){
291 				prstrfl("Divide by zero.\n");
292 				acc = 0;
293 			}else acc /= i;
294 			goto a0;
295 		case '%':
296 			i = ckph();
297 			if(nonumb)break;
298 			acc %= i;
299 			goto a0;
300 		case '&':	/*and*/
301 			i = ckph();
302 			if(nonumb)break;
303 			if((acc > 0) && (i > 0))acc = 1; else acc = 0;
304 			goto a0;
305 		case ':':	/*or*/
306 			i = ckph();
307 			if(nonumb)break;
308 			if((acc > 0) || (i > 0))acc = 1; else acc = 0;
309 			goto a0;
310 		case '=':
311 			if(((ii=getch()) & CMASK) != '=')ch = ii;
312 			i = ckph();
313 			if(nonumb){acc = 0; break;}
314 			if(i == acc)acc = 1;
315 			else acc = 0;
316 			goto a0;
317 		case '>':
318 			k = 0;
319 			if(((ii=getch()) & CMASK) == '=')k++; else ch =ii;
320 			i = ckph();
321 			if(nonumb){acc = 0; break;}
322 			if(acc > (i - k))acc = 1; else acc = 0;
323 			goto a0;
324 		case '<':
325 			k = 0;
326 			if(((ii=getch()) & CMASK) == '=')k++; else ch =ii;
327 			i = ckph();
328 			if(nonumb){acc = 0; break;}
329 			if(acc < (i + k))acc = 1; else acc = 0;
330 			goto a0;
331 		case ')': break;
332 		case '(':
333 			acc = atoi0();
334 			goto a0;
335 	}
336 	return(acc);
337 }
338 long ckph(){
339 	register i;
340 	long j;
341 	extern long atoi0();
342 	extern long atoi1();
343 
344 	if(((i = getch()) & CMASK) == '(')j = atoi0();
345 	else{
346 		ch = i;
347 		j = atoi1();
348 	}
349 	return(j);
350 }
351 long atoi1()
352 {
353 	register i, j, digits;
354 	long acc;
355 	int neg, abs, field;
356 
357 	neg = abs = field = digits = 0;
358 	acc = 0;
359 a0:
360 	switch((i = getch()) & CMASK){
361 		default:
362 			ch = i;
363 			break;
364 		case '+':
365 			goto a0;
366 		case '-':
367 			neg = 1;
368 			goto a0;
369 		case '|':
370 			abs = 1 + neg;
371 			neg = 0;
372 			goto a0;
373 	}
374 a1:
375 	while(((j = ((i = getch()) & CMASK) - '0') >= 0) && (j <= 9)){
376 		field++;
377 		digits++;
378 		acc = 10*acc + j;
379 	}
380 	if((i & CMASK) == '.'){
381 		field++;
382 		digits = 0;
383 		goto a1;
384 	}
385 	ch = i;
386 	if(!field)goto a2;
387 	switch((i = getch()) & CMASK){
388 		case 'u':
389 			i = j = 1;
390 			break;
391 		case 'v':	/*VSs - vert spacing*/
392 			j = lss;
393 			i = 1;
394 			break;
395 		case 'm':	/*Ems*/
396 			j = EM;
397 			i = 1;
398 			break;
399 		case 'n':	/*Ens*/
400 			j = EM;
401 #ifndef NROFF
402 			i = 2;
403 #endif
404 #ifdef NROFF
405 			i = 1;	/*Same as Ems in NROFF*/
406 #endif
407 			break;
408 		case 'p':	/*Points*/
409 			j = INCH;
410 			i = 72;
411 			break;
412 		case 'i':	/*Inches*/
413 			j = INCH;
414 			i = 1;
415 			break;
416 		case 'c':	/*Centimeters*/
417 			j = INCH*50;
418 			i = 127;
419 			break;
420 		case 'P':	/*Picas*/
421 			j = INCH;
422 			i = 6;
423 			break;
424 		default:
425 			j = dfact;
426 			ch = i;
427 			i = dfactd;
428 	}
429 	if(neg) acc = -acc;
430 	if(!noscale){
431 		acc = (acc*j)/i;
432 	}
433 	if((field != digits) && (digits > 0))while(digits--)acc /= 10;
434 	if(abs){
435 		if(dip != d)j = dip->dnl; else j = v.nl;
436 		if(!vflag)j = v.hp = sumhp();	/* XXX */
437 		if(abs == 2)j = -j;
438 		acc -= j;
439 	}
440 a2:
441 	nonumb = !field;
442 	return(acc);
443 }
444 caserr(){
445 	register i,j;
446 
447 	lgf++;
448 	while(!skip() && (i=getrq()) ){
449 		for(j=NNAMES; j<NN; j++){  /*NNAMES predefined names*/
450 			if(i == r[j])break;
451 		}
452 		if(j!=NN){
453 			r[j]=vlist[j]=inc[j]=fmt[j]=0;
454 			regcnt--;
455 		}
456 	}
457 }
458 casenr(){
459 	register i, j;
460 
461 	lgf++;
462 	skip();
463 	if((i = findr(getrq())) == -1)goto rtn;
464 	skip();
465 	j = inumb(&vlist[i]);
466 	if(nonumb)goto rtn;
467 	vlist[i] = j;
468 	skip();
469 	j = atoi();
470 	if(nonumb)goto rtn;
471 	inc[i] = j;
472 rtn:
473 	return;
474 }
475 caseaf(){
476 	register i, j, k;
477 
478 	lgf++;
479 	if(skip() || !(i = getrq()) || skip())return;
480 	k = 0;
481 	if(!alph(j=getch())){
482 		ch = j;
483 		while(((j = getch() & CMASK) >= '0') &&
484 			(j <= '9'))k++;
485 	}
486 	if(!k)k=j;
487 	fmt[findr(i)] = k & BMASK;
488 }
489 vnumb(i)
490 int *i;
491 {
492 	vflag++;
493 	dfact = lss;
494 	res = VERT;
495 	return(inumb(i));
496 }
497 hnumb(i)
498 int *i;
499 {
500 	dfact = EM;
501 	res = HOR;
502 	return(inumb(i));
503 }
504 inumb(n)
505 int *n;
506 {
507 	register i, j, f;
508 
509 	f = 0;
510 	if(n){
511 	if((j = (i = getch()) & CMASK) == '+')f = 1;
512 		else if(j == '-')f = -1;
513 			else ch = i;
514 	}
515 	i = atoi();
516 	if(n && f)i = *n + f*i;
517 	i = quant(i,res);
518 	vflag = 0;
519 	res = dfactd = dfact = 1;
520 	if(nonumb)i = 0;
521 	return(i);
522 }
523 quant(n,m)
524 int n, m;
525 {
526 	register i, neg;
527 
528 	neg = 0;
529 	if(n<0){
530 		neg++;
531 		n = -n;
532 	}
533 	i = n/m;
534 	if((n - m*i) > (m/2))i += 1;
535 	i *= m;
536 	if(neg)i = -i;
537 	return(i);
538 }
539