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 1989 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 /*	from OpenSolaris "n9.c	1.11	05/06/08 SMI"	*/
32 
33 /*
34  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35  *
36  * Sccsid @(#)n9.c	1.78 (gritter) 10/23/09
37  */
38 
39 /*
40  * University Copyright- Copyright (c) 1982, 1986, 1988
41  * The Regents of the University of California
42  * All Rights Reserved
43  *
44  * University Acknowledgment- Portions of this document are derived from
45  * software developed by the University of California, Berkeley, and its
46  * contributors.
47  */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56 
57 #ifdef EUC
58 #include <locale.h>
59 #include <wctype.h>
60 #include <langinfo.h>
61 #endif	/* EUC */
62 #include "tdef.h"
63 #ifdef NROFF
64 #include "tw.h"
65 #endif
66 #include "pt.h"
67 #include "ext.h"
68 
69 #ifdef EUC
70 #define	ISO646	"646"
71 
72 int	multi_locale;
73 int	(*wdbdg)(wchar_t, wchar_t, int);
74 wchar_t	*(*wddlm)(wchar_t, wchar_t, int);
75 
76 int	csi_width[4] = {
77 	1,
78 	1,
79 	2,
80 	3,
81 };
82 #endif /* EUC */
83 
84 /*
85  * troff9.c
86  *
87  * misc functions
88  */
89 
90 tchar
setz(void)91 setz(void)
92 {
93 	tchar i;
94 
95 	if (!ismot(i = getch()) && cbits(i) != ohc)
96 		i |= ZBIT;
97 	return(i);
98 }
99 
100 static int
connectchar(tchar i)101 connectchar(tchar i)
102 {
103 	int	*cp, c;
104 
105 	c = cbits(i);
106 	if (*connectch) {
107 		for (cp = connectch; *cp; cp++)
108 			if (c == *cp)
109 				return 1;
110 		return 0;
111 	}
112 	return c == RULE || c == UNDERLINE || c == ROOTEN;
113 }
114 
115 void
setline(void)116 setline(void)
117 {
118 	register tchar *i;
119 	tchar c, delim;
120 	int	length;
121 	int	w, cnt, rem, temp;
122 	tchar linebuf[NC];
123 
124 	if (ismot(c = getch()))
125 		return;
126 	delim = c;
127 	vflag = 0;
128 	dfact = EM;
129 	length = quant(hatoi(), HOR);
130 	dfact = 1;
131 	if (!length) {
132 		eat(delim);
133 		return;
134 	}
135 s0:
136 	if (c = getch(), issame(c, delim)) {
137 		ch = c;
138 		c = RULE | chbits;
139 	} else if (cbits(c) == FILLER)
140 		goto s0;
141 	w = width(c);
142 	i = linebuf;
143 	if (length < 0) {
144 		*i++ = makem(length);
145 		length = -length;
146 	}
147 	if (!(cnt = length / w)) {
148 		*i++ = makem(-(temp = ((w - length) / 2)));
149 		*i++ = c;
150 		*i++ = makem(-(w - length - temp));
151 		goto s1;
152 	}
153 	if ((rem = length % w)) {
154 		if (connectchar(c))
155 			*i++ = c | ZBIT;
156 		*i++ = makem(rem);
157 	}
158 	if (cnt) {
159 		*i++ = RPT;
160 		*i++ = cnt;
161 		*i++ = c;
162 	}
163 s1:
164 	*i++ = 0;
165 	eat(delim);
166 	pushback(linebuf);
167 }
168 
169 
170 tchar
eat(tchar c)171 eat(tchar c)
172 {
173 	register tchar i;
174 
175 	while (i = getch(), !issame(i, c) &&  (cbits(i) != '\n'))
176 		;
177 	if (cbits(c) != ' ' && !issame(i, c))
178 		nodelim(c);
179 	return(i);
180 }
181 
182 
183 void
setov(void)184 setov(void)
185 {
186 	register int j = 0, k;
187 	tchar i, delim, o[NOV];
188 	int w[NOV];
189 
190 	if (ismot(i = getch()))
191 		return;
192 	delim = i;
193 	for (k = 0; (k < NOV) && (j = cbits(i = getch()), !issame(i, delim)) &&  (j != '\n'); k++) {
194 		o[k] = i;
195 		w[k] = width(i);
196 	}
197 	if (!issame(j, delim))
198 		nodelim(delim);
199 	o[k] = w[k] = 0;
200 	if (o[0])
201 		for (j = 1; j; ) {
202 			j = 0;
203 			for (k = 1; o[k] ; k++) {
204 				if (w[k-1] < w[k]) {
205 					j++;
206 					i = w[k];
207 					w[k] = w[k-1];
208 					w[k-1] = i;
209 					i = o[k];
210 					o[k] = o[k-1];
211 					o[k-1] = i;
212 				}
213 			}
214 		}
215 	else
216 		return;
217 	pbbuf[pbp++] = makem(w[0] / 2);
218 	for (k = 0; o[k]; k++)
219 		;
220 	while (k>0) {
221 		k--;
222 		if (pbp >= pbsize-4)
223 			if (growpbbuf() == NULL) {
224 				errprint("no space for .ov");
225 				done(2);
226 			}
227 		pbbuf[pbp++] = makem(-((w[k] + w[k+1]) / 2));
228 		pbbuf[pbp++] = o[k];
229 	}
230 }
231 
232 
233 void
setbra(void)234 setbra(void)
235 {
236 	register int k;
237 	tchar i, *j, dwn, delim;
238 	int	cnt;
239 	tchar brabuf[NC];
240 
241 	if (ismot(i = getch()))
242 		return;
243 	delim = i;
244 	j = brabuf + 1;
245 	cnt = 0;
246 #ifdef NROFF
247 	dwn = sabsmot(2 * t.Halfline) | MOT | VMOT;
248 #endif
249 #ifndef NROFF
250 	dwn = sabsmot((int)EM) | MOT | VMOT;
251 #endif
252 	while ((k = cbits(i = getch()), !issame(delim, i)) && (k != '\n') &&  (j <= (brabuf + NC - 4))) {
253 		*j++ = i | ZBIT;
254 		*j++ = dwn;
255 		cnt++;
256 	}
257 	if (!issame(i, delim))
258 		nodelim(delim);
259 	if (--cnt < 0)
260 		return;
261 	else if (!cnt) {
262 		ch = *(j - 2);
263 		return;
264 	}
265 	*j = 0;
266 #ifdef NROFF
267 	*--j = *brabuf = sabsmot(cnt * t.Halfline) | MOT | NMOT | VMOT;
268 #endif
269 #ifndef NROFF
270 	*--j = *brabuf = sabsmot((cnt * (int)EM) / 2) | MOT | NMOT | VMOT;
271 #endif
272 	*--j &= ~ZBIT;
273 	pushback(brabuf);
274 }
275 
276 
277 void
setvline(void)278 setvline(void)
279 {
280 	register int i;
281 	tchar c, d, delim, rem, ver, neg;
282 	int	cnt, v;
283 	tchar vlbuf[NC];
284 	register tchar *vlp;
285 
286 	if (ismot(c = getch()))
287 		return;
288 	delim = c;
289 	dfact = lss;
290 	vflag++;
291 	i = quant(hatoi(), VERT);
292 	dfact = 1;
293 	if (!i) {
294 		eat(delim);
295 		vflag = 0;
296 		return;
297 	}
298 	if (c = getch(), issame(c, delim)) {
299 		c = BOXRULE | chbits;	/*default box rule*/
300 	} else {
301 		d = getch();
302 		if (!issame(d, delim))
303 			nodelim(delim);
304 	}
305 	c |= ZBIT;
306 	neg = 0;
307 	if (i < 0) {
308 		i = -i;
309 		neg = NMOT;
310 	}
311 #ifdef NROFF
312 	v = 2 * t.Halfline;
313 #endif
314 #ifndef NROFF
315 	v = EM;
316 #endif
317 	cnt = i / v;
318 	rem = makem(i % v) | neg;
319 	ver = makem(v) | neg;
320 	vlp = vlbuf;
321 	if (!neg)
322 		*vlp++ = ver;
323 	if (absmot(rem) != 0) {
324 		*vlp++ = c;
325 		*vlp++ = rem;
326 	}
327 	while ((vlp < (vlbuf + NC - 3)) && cnt--) {
328 		*vlp++ = c;
329 		*vlp++ = ver;
330 	}
331 	*(vlp - 2) &= ~ZBIT;
332 	if (!neg)
333 		vlp--;
334 	*vlp++ = 0;
335 	pushback(vlbuf);
336 	vflag = 0;
337 }
338 
339 #define	NPAIR	(NC/2-6)	/* max pairs in spline, etc. */
340 
341 void
setdraw(void)342 setdraw (void)	/* generate internal cookies for a drawing function */
343 {
344 	int i, dx[NPAIR], dy[NPAIR], type;
345 	tchar c, delim;
346 #ifndef	NROFF
347 	int	hpos, vpos;
348 	int j, k;
349 	tchar drawbuf[NC];
350 #else
351 	extern int tlp, utf8;
352 	char drawbuf[NC];
353 #endif	/* NROFF */
354 
355 	/* input is \D'f dx dy dx dy ... c' (or at least it had better be) */
356 	/* this does drawing function f with character c and the */
357 	/* specified dx,dy pairs interpreted as appropriate */
358 	/* pairs are deltas from last point, except for radii */
359 
360 	/* l dx dy:	line from here by dx,dy */
361 	/* c x:		circle of diameter x, left side here */
362 	/* e x y:	ellipse of diameters x,y, left side here */
363 	/* a dx1 dy1 dx2 dy2:
364 			ccw arc: ctr at dx1,dy1, then end at dx2,dy2 from there */
365 	/* ~ dx1 dy1 dx2 dy2...:
366 			spline to dx1,dy1 to dx2,dy2 ... */
367 	/* f dx dy ...:	f is any other char:  like spline */
368 
369 	if (ismot(c = getch()))
370 		return;
371 	delim = c;
372 	type = cbits(getch());
373 	for (i = 0; i < NPAIR ; i++) {
374 		c = getch();
375 		if (issame(c, delim))
376 			break;
377 	/* ought to pick up optional drawing character */
378 		if (cbits(c) != ' ')
379 			ch = c;
380 		vflag = 0;
381 		dfact = type == DRAWTHICKNESS ? 1 : EM;
382 		dx[i] = quant(hatoi(), HOR);
383 		if (dx[i] > MAXMOT)
384 			dx[i] = MAXMOT;
385 		else if (dx[i] < -MAXMOT)
386 			dx[i] = -MAXMOT;
387 		if (c = getch(), issame(c, delim)) {	/* spacer */
388 			dy[i++] = 0;
389 			break;
390 		}
391 		vflag = 1;
392 		dfact = lss;
393 		dy[i] = quant(hatoi(), VERT);
394 		if (type == DRAWTHICKNESS)
395 			dy[i] = 0;
396 		else if (dy[i] > MAXMOT)
397 			dy[i] = MAXMOT;
398 		else if (dy[i] < -MAXMOT)
399 			dy[i] = -MAXMOT;
400 	}
401 	dfact = 1;
402 	vflag = 0;
403 #ifndef NROFF
404 	drawbuf[0] = DRAWFCN | chbits | ZBIT;
405 	drawbuf[1] = type | chbits | ZBIT;
406 	drawbuf[2] = '.' | chbits | ZBIT;	/* use default drawing character */
407 	hpos = vpos = 0;
408 	for (k = 0, j = 3; k < i; k++) {
409 		drawbuf[j++] = MOT | ((dx[k] >= 0) ?
410 				sabsmot(dx[k]) : (NMOT | sabsmot(-dx[k])));
411 		drawbuf[j++] = MOT | VMOT | ((dy[k] >= 0) ?
412 				sabsmot(dy[k]) : (NMOT | sabsmot(-dy[k])));
413 		hpos += dx[k];
414 		vpos += dy[k];
415 	}
416 	if (type == DRAWELLIPSE || type == DRAWELLIPSEFI) {
417 		drawbuf[5] = drawbuf[4] | NMOT;	/* so the net vertical is zero */
418 		j = 6;
419 	}
420 	if (gflag && (type == DRAWPOLYGON || type == DRAWPOLYGONFI) &&
421 			(hpos || vpos)) {
422 		drawbuf[j++] = MOT | ((hpos < 0) ?
423 				sabsmot(-hpos) : (NMOT | sabsmot(hpos)));
424 		drawbuf[j++] = MOT | VMOT | ((vpos < 0) ?
425 				sabsmot(-vpos) : (NMOT | sabsmot(vpos)));
426 	}
427 	drawbuf[j++] = DRAWFCN | chbits | ZBIT;	/* marks end for ptout */
428 	drawbuf[j] = 0;
429 	pushback(drawbuf);
430 #else
431 	switch (type) {
432 	case 'l':
433 		if (dx[0] && !dy[0]) {
434 			if (dx[0] < 0) {
435 				snprintf(drawbuf, sizeof(drawbuf), "\\h'%du'",
436 				    dx[0]);
437 				cpushback(drawbuf);
438 			}
439 			snprintf(drawbuf, sizeof(drawbuf), "\\l'%du%s'",
440 			    dx[0], tlp ? "\\&-" : utf8 ? "\\U'2500'" : "");
441 			cpushback(drawbuf);
442 		} else if (dy[0] && !dx[0]) {
443 			snprintf(drawbuf, sizeof(drawbuf), "\\L'%du%s'",
444 			    dy[0], tlp ? "|" : utf8 ? "\\U'2502'" : "");
445 			cpushback(drawbuf);
446 		}
447 	}
448 #endif
449 }
450 
451 
452 void
casefc(void)453 casefc(void)
454 {
455 	register int i;
456 	tchar j;
457 
458 	gchtab[fc] &= ~FCBIT;
459 	fc = IMP;
460 	padc = ' ';
461 	if (skip(0) || ismot(j = getch()) || (i = cbits(j)) == '\n')
462 		return;
463 	fc = i;
464 	gchtab[fc] |= FCBIT;
465 	if (skip(0) || ismot(ch) || (ch = cbits(ch)) == fc)
466 		return;
467 	padc = ch;
468 }
469 
470 
471 tchar
setfield(int x)472 setfield(int x)
473 {
474 	register tchar ii, jj, *fp;
475 	register int i, j, k;
476 	int length, ws, npad, temp, type;
477 	tchar **pp, *padptr[NPP];
478 	tchar fbuf[FBUFSZ];
479 	int savfc, savtc, savlc;
480 	tchar rchar = 0, nexti = 0;
481 	int savepos;
482 	int oev;
483 
484 	prdblesc = 1;
485 	if (x == tabch)
486 		rchar = tabc | chbits;
487 	else if (x ==  ldrch)
488 		rchar = dotc | chbits;
489 	if (chartab[trtab[cbits(rchar)]] != 0)
490 		rchar = setchar(rchar);
491 	temp = npad = ws = 0;
492 	savfc = fc;
493 	savtc = tabch;
494 	savlc = ldrch;
495 	tabch = ldrch = fc = IMP;
496 	savepos = numtab[HP].val;
497 	gchtab[tabch] &= ~TABBIT;
498 	gchtab[ldrch] &= ~LDRBIT;
499 	gchtab[fc] &= ~FCBIT;
500 	gchtab[IMP] |= TABBIT|LDRBIT|FCBIT;
501 	for (j = 0; ; j++) {
502 		if ((tabtab[j] & TABMASK) == 0) {
503 			if (x == savfc)
504 				errprint("zero field width.");
505 			jj = 0;
506 			goto rtn;
507 		}
508 		if ((length = ((tabtab[j] & TABMASK) - numtab[HP].val)) > 0 )
509 			break;
510 	}
511 	type = tabtab[j] & (~TABMASK);
512 	fp = fbuf;
513 	pp = padptr;
514 	if (x == savfc) {
515 		*fp++ = mkxfunc(FLDMARK, 0);
516 		nexti = getch();
517 		while (1) {
518 			j = cbits(ii = nexti);
519 			jj = width(ii);
520 			oev = ev;
521 			if (j != savfc && j != '\n' &&
522 					pp < (padptr + NPP - 1) &&
523 					fp < (fbuf + FBUFSZ - 3))
524 				nexti = getch();
525 			else
526 				nexti = 0;
527 			if (ev == oev)
528 				jj += kernadjust(ii, nexti);
529 			widthp = jj;
530 			numtab[HP].val += jj;
531 			if (j == padc) {
532 				npad++;
533 				*pp++ = fp;
534 				if (pp > (padptr + NPP - 1))
535 					break;
536 				goto s1;
537 			} else if (j == savfc)
538 				break;
539 			else if (j == '\n') {
540 				temp = j;
541 				nlflg = 0;
542 				break;
543 			}
544 			ws += jj;
545 s1:
546 			*fp++ = ii;
547 			if (fp > (fbuf + FBUFSZ - 3))
548 				break;
549 		}
550 		if (!npad) {
551 			npad++;
552 			*pp++ = fp;
553 			*fp++ = 0;
554 		}
555 		*fp++ = temp;
556 		*fp++ = 0;
557 		temp = i = (j = length - ws) / npad;
558 		i = (i / HOR) * HOR;
559 		if ((j -= i * npad) < 0)
560 			j = -j;
561 		ii = makem(i);
562 		if (temp < 0)
563 			ii |= NMOT;
564 		for (; npad > 0; npad--) {
565 			*(*--pp) = ii;
566 			if (j) {
567 				j -= HOR;
568 				(*(*pp)) += HOR;
569 			}
570 		}
571 		pushback(fbuf);
572 		jj = 0;
573 	} else if (type == 0) {
574 		/*plain tab or leader*/
575 		if (pbp >= pbsize-4)
576 			growpbbuf();
577 		pbbuf[pbp++] = mkxfunc(FLDMARK, 0);
578 		if ((j = width(rchar)) > 0) {
579 			int nchar;
580 			k = kernadjust(rchar, rchar);
581 			if (length < j)
582 				nchar = 0;
583 			else {
584 				nchar = 1;
585 				length -= j;
586 				nchar += length / (k+j);
587 				length %= k+j;
588 			}
589 			pbbuf[pbp++] = FILLER;
590 			while (nchar-->0) {
591 				if (pbp >= pbsize-5)
592 					if (growpbbuf() == NULL)
593 						break;
594 				numtab[HP].val += j;
595 				widthp = j;
596 				if (nchar > 0) {
597 					numtab[HP].val += k;
598 					widthp += k;
599 				}
600 				pbbuf[pbp++] = rchar;
601 			}
602 			pbbuf[pbp++] = FILLER;
603 		}
604 		if (length)
605 			jj = sabsmot(length) | MOT;
606 		else
607 			jj = 0;
608 	} else {
609 		/*center tab*/
610 		/*right tab*/
611 		*fp++ = mkxfunc(FLDMARK, 0);
612 		nexti = getch();
613 		while (((j = cbits(ii = nexti)) != savtc) &&  (j != '\n') && (j != savlc)) {
614 			jj = width(ii);
615 			oev = ev;
616 			if (fp < (fbuf + FBUFSZ - 3)) {
617 				nexti = getch();
618 				if (ev == oev)
619 					jj += kernadjust(ii, nexti);
620 			}
621 			ws += jj;
622 			numtab[HP].val += jj;
623 			widthp = jj;
624 			*fp++ = ii;
625 			if (fp > (fbuf + FBUFSZ - 3))
626 				break;
627 		}
628 		*fp++ = ii;
629 		*fp++ = 0;
630 		if (type == RTAB)
631 			length -= ws;
632 		else
633 			length -= ws / 2; /*CTAB*/
634 		pushback(fbuf);
635 		if ((j = width(rchar)) != 0 && length > 0) {
636 			int nchar;
637 			k = kernadjust(rchar, rchar);
638 			if (length < j)
639 				nchar = 0;
640 			else {
641 				nchar = 1;
642 				length -= j;
643 				nchar += length / (k+j);
644 				length %= k+j;
645 			}
646 			if (pbp >= pbsize-3)
647 				growpbbuf();
648 			pbbuf[pbp++] = FILLER;
649 			while (nchar-- > 0) {
650 				if (pbp >= pbsize-3)
651 					if (growpbbuf() == NULL)
652 						break;
653 				pbbuf[pbp++] = rchar;
654 			}
655 		}
656 		length = (length / HOR) * HOR;
657 		jj = makem(length);
658 		nlflg = 0;
659 	}
660 rtn:
661 	gchtab[fc] &= ~FCBIT;
662 	gchtab[tabch] &= ~TABBIT;
663 	gchtab[ldrch] &= ~LDRBIT;
664 	fc = savfc;
665 	tabch = savtc;
666 	ldrch = savlc;
667 	gchtab[fc] |= FCBIT;
668 	gchtab[tabch] = TABBIT;
669 	gchtab[ldrch] |= LDRBIT;
670 	numtab[HP].val = savepos;
671 	if (pbp < pbsize-3 || growpbbuf())
672 		pbbuf[pbp++] = mkxfunc(FLDMARK, x);
673 	prdblesc = 0;
674 	return(jj | ADJBIT);
675 }
676 
677 
678 static int
readpenalty(int * valp)679 readpenalty(int *valp)
680 {
681 	int	n, t;
682 
683 	t = dpenal ? dpenal - INFPENALTY0 - 1 : 0;
684 	noscale++;
685 	n = inumb(&t);
686 	noscale--;
687 	if (nonumb)
688 		return 0;
689 	if (n > INFPENALTY0)
690 		n = INFPENALTY0;
691 	else if (n < -INFPENALTY0)
692 		n = -INFPENALTY0;
693 	n += INFPENALTY0 + 1;
694 	*valp = n;
695 	return 1;
696 }
697 
698 static int
getpenalty(int * valp)699 getpenalty(int *valp)
700 {
701 	tchar	c, delim;
702 
703 	if (ismot(delim = getch()))
704 		return 0;
705 	if (readpenalty(valp) == 0)
706 		return 0;
707 	c = getch();
708 	if (!issame(c, delim)) {
709 		nodelim(delim);
710 		return 0;
711 	}
712 	return 1;
713 }
714 
715 tchar
setpenalty(void)716 setpenalty(void)
717 {
718 	int	n;
719 
720 	if (getpenalty(&n))
721 		return mkxfunc(PENALTY, n);
722 	return 0;
723 }
724 
725 tchar
setdpenal(void)726 setdpenal(void)
727 {
728 	if (getpenalty(&dpenal))
729 		return mkxfunc(DPENAL, dpenal);
730 	return 0;
731 }
732 
733 
734 tchar
mkxfunc(int f,int s)735 mkxfunc(int f, int s)
736 {
737 	tchar	t = XFUNC;
738 	setfbits(t, f);
739 	setsbits(t, s);
740 	return t;
741 }
742 
743 void
pushinlev(void)744 pushinlev(void)
745 {
746 	if (ninlev >= ainlev) {
747 		ainlev += 4;
748 		inlevp = realloc(inlevp, ainlev * sizeof *inlevp);
749 	}
750 	inlevp[ninlev]._apts = apts;
751 	inlevp[ninlev]._apts1 = apts1;
752 	inlevp[ninlev]._pts = pts;
753 	inlevp[ninlev]._pts1 = pts1;
754 	inlevp[ninlev]._font = font;
755 	inlevp[ninlev]._font1 = font1;
756 	inlevp[ninlev]._cc = cc;
757 	inlevp[ninlev]._c2 = c2;
758 	inlevp[ninlev]._ohc = ohc;
759 	inlevp[ninlev]._hyf = hyf;
760 	inlevp[ninlev]._tabc = tabc;
761 	inlevp[ninlev]._dotc = dotc;
762 	inlevp[ninlev]._dpenal = dpenal;
763 	ninlev++;
764 }
765 
766 tchar
popinlev(void)767 popinlev(void)
768 {
769 	tchar	c = 0;
770 
771 	if (--ninlev < 0) {
772 		ninlev = 0;
773 		return c;
774 	}
775 	if (dpenal != inlevp[ninlev]._dpenal)
776 		c = mkxfunc(DPENAL, inlevp[ninlev]._dpenal);
777 	apts = inlevp[ninlev]._apts;
778 	apts1 = inlevp[ninlev]._apts1;
779 	pts = inlevp[ninlev]._pts;
780 	pts1 = inlevp[ninlev]._pts1;
781 	font = inlevp[ninlev]._font;
782 	font1 = inlevp[ninlev]._font1;
783 	cc = inlevp[ninlev]._cc;
784 	c2 = inlevp[ninlev]._c2;
785 	ohc = inlevp[ninlev]._ohc;
786 	hyf = inlevp[ninlev]._hyf;
787 	tabc = inlevp[ninlev]._tabc;
788 	dotc = inlevp[ninlev]._dotc;
789 	dpenal = inlevp[ninlev]._dpenal;
790 	mchbits();
791 	if (ninlev == 0) {
792 		free(inlevp);
793 		inlevp = NULL;
794 		ainlev = 0;
795 	}
796 	return c;
797 }
798 
799 #ifdef EUC
800 /* locale specific initialization */
801 void
localize(void)802 localize(void)
803 {
804 	extern int	wdbindf(wchar_t, wchar_t, int);
805 	extern wchar_t	*wddelim(wchar_t, wchar_t, int);
806 	char	*codeset;
807 
808 	codeset = nl_langinfo(CODESET);
809 
810 	if (mb_cur_max > 1)
811 		multi_locale = 1;
812 	else {
813 		if (*codeset == '\0' ||
814 			(strcmp(codeset, ISO646) == 0)) {
815 			/*
816 			 * if codeset is an empty string
817 			 * assumes this is C locale (7-bit) locale.
818 			 * This happens in 2.5, 2.5.1, and 2.6 system
819 			 * Or, if codeset is "646"
820 			 * this is 7-bit locale.
821 			 */
822 			multi_locale = 0;
823 		} else {
824 			/* 8-bit locale */
825 			multi_locale = 1;
826 		}
827 
828 	}
829 	wdbdg = wdbindf;
830 	wddlm = wddelim;
831 }
832 
833 #ifndef	__sun
834 int
wdbindf(wchar_t wc1,wchar_t wc2,int type)835 wdbindf(wchar_t wc1, wchar_t wc2, int type)
836 {
837 	return 6;
838 }
839 
840 wchar_t *
wddelim(wchar_t wc1,wchar_t wc2,int type)841 wddelim(wchar_t wc1, wchar_t wc2, int type)
842 {
843 	return L" ";
844 }
845 #endif	/* !__sun */
846 #endif /* EUC */
847 
848 void
caselc_ctype(void)849 caselc_ctype(void)
850 {
851 #ifdef	EUC
852 	char	c, *buf = NULL;
853 	int	i = 0, sz = 0;
854 
855 	skip(1);
856 	do {
857 		c = getach()&0377;
858 		if (i >= sz)
859 			buf = realloc(buf, (sz += 8) * sizeof *buf);
860 		buf[i++] = c;
861 	} while (c && c != ' ' && c != '\n');
862 	buf[i-1] = 0;
863 	setlocale(LC_CTYPE, buf);
864 	mb_cur_max = MB_CUR_MAX;
865 	localize();
866 #ifndef	NROFF
867 	ptlocale(buf);
868 #endif
869 	free(buf);
870 #endif
871 }
872 
873 #ifndef	NROFF
874 struct fg {
875 	char	buf[512];
876 	char	*bp;
877 	char	*ep;
878 	int	fd;
879 	int	eof;
880 };
881 
882 static int
psskip(struct fg * fp,size_t n)883 psskip(struct fg *fp, size_t n)
884 {
885 	size_t	i;
886 
887 	if (fp->eof)
888 		return -1;
889 	if (fp->bp < fp->ep) {
890 		i = fp->ep - fp->bp;
891 		if (i > n) {
892 			fp->bp += n;
893 			return 0;
894 		}
895 		fp->bp = fp->buf;
896 		n -= i;
897 	}
898 	if (lseek(fp->fd, n, SEEK_CUR) == (off_t)-1)
899 		return -1;
900 	return 0;
901 }
902 
903 static int
psgetline(struct fg * fp,char ** linebp,size_t * linesize)904 psgetline(struct fg *fp, char **linebp, size_t *linesize)
905 {
906 	int	i, n = 0;
907 	int	nl = 0;
908 
909 	if (fp->bp == NULL)
910 		fp->bp = fp->buf;
911 	for (;;) {
912 		if (fp->eof == 0 && fp->bp == fp->buf) {
913 			if ((i = read(fp->fd, fp->buf, sizeof fp->buf)) <= 0)
914 				fp->eof = 1;
915 			fp->ep = &fp->buf[i];
916 		}
917 		for (;;) {
918 			if (*linesize < n + 2)
919 				*linebp = realloc(*linebp, *linesize += 128);
920 			if (fp->bp >= fp->ep)
921 				break;
922 			if (*fp->bp == '\n' || nl) {
923 				nl = 2;
924 				break;
925 			}
926 			if (*fp->bp == '\r')
927 				nl = 1;
928 			(*linebp)[n++] = *fp->bp++;
929 		}
930 		if (fp->bp < fp->ep && *fp->bp == '\n') {
931 			(*linebp)[n++] = *fp->bp++;
932 			break;
933 		}
934 		if (nl == 2 || fp->eof)
935 			break;
936 		fp->bp = fp->buf;
937 	}
938 	(*linebp)[n] = 0;
939 	return n;
940 }
941 
942 static char *
getcom(const char * cp,const char * tp)943 getcom(const char *cp, const char *tp)
944 {
945 	int	n;
946 
947 	n = strlen(tp);
948 	if (strncmp(cp, tp, n))
949 		return NULL;
950 	if (cp[n] == ' ' || cp[n] == '\t' || cp[n] == '\r' ||
951 			cp[n] == '\n' || cp[n] == 0)
952 		return (char *)&cp[n];
953 	return NULL;
954 }
955 
956 static void
getpsbb(const char * name,double bb[4])957 getpsbb(const char *name, double bb[4])
958 {
959 	struct fg	*fp;
960 	char	*buf = NULL;
961 	char	*cp;
962 	size_t	size = 0;
963 	int	fd, n, k;
964 	int	lineno = 0;
965 	int	found = 0;
966 	int	atend = 0;
967 	int	state = 0;
968 	int	indoc = 0;
969 
970 	if ((fd = open(name, O_RDONLY)) < 0) {
971 		errprint("can't open %s", name);
972 		return;
973 	}
974 	fp = calloc(1, sizeof *fp);
975 	fp->fd = fd;
976 	for (;;) {
977 		n = psgetline(fp, &buf, &size);
978 		if (++lineno == 1 && (n == 0 || strncmp(buf, "%!PS-", 5))) {
979 			errprint("%s is not a DSC-conforming "
980 					"PostScript document", name);
981 			break;
982 		}
983 		if (n > 0 && state != 1 &&
984 				(cp = getcom(buf, "%%BoundingBox:")) != NULL) {
985 			while (*cp == ' ' || *cp == '\t')
986 				cp++;
987 			if (strncmp(cp, "(atend)", 7) == 0) {
988 				atend++;
989 				continue;
990 			}
991 			bb[0] = strtod(cp, &cp);
992 			if (*cp)
993 				bb[1] = strtod(cp, &cp);
994 			if (*cp)
995 				bb[2] = strtod(cp, &cp);
996 			if (*cp) {
997 				bb[3] = strtod(cp, &cp);
998 				found = 1;
999 			} else
1000 				errprint("missing arguments to "
1001 					"%%%%BoundingBox: in %s, line %d\n",
1002 					name, lineno);
1003 			continue;
1004 		}
1005 		if (n > 0 && state != 1 &&
1006 				(cp = getcom(buf, "%%HiResBoundingBox:"))
1007 				!= NULL) {
1008 			while (*cp == ' ' || *cp == '\t')
1009 				cp++;
1010 			if (strncmp(cp, "(atend)", 7) == 0) {
1011 				atend++;
1012 				continue;
1013 			}
1014 			bb[0] = strtod(cp, &cp);
1015 			if (*cp)
1016 				bb[1] = strtod(cp, &cp);
1017 			if (*cp)
1018 				bb[2] = strtod(cp, &cp);
1019 			if (*cp) {
1020 				bb[3] = strtod(cp, &cp);
1021 				break;
1022 			} else {
1023 				errprint("missing arguments to "
1024 					"%%%%HiResBoundingBox: in %s, "
1025 					"line %d\n",
1026 					name, lineno);
1027 				continue;
1028 			}
1029 		}
1030 		if (n == 0 || (state == 0 &&
1031 				(getcom(buf, "%%EndComments") != NULL ||
1032 				 buf[0] != '%' || buf[1] == ' ' ||
1033 				 buf[1] == '\t' || buf[1] == '\r' ||
1034 				 buf[1] == '\n'))) {
1035 		eof:	if (found == 0 && (atend == 0 || n == 0))
1036 				errprint("%s lacks a %%%%BoundingBox: DSC "
1037 					"comment", name);
1038 			if (atend == 0 || n == 0)
1039 				break;
1040 			state = 1;
1041 			continue;
1042 		}
1043 		if (indoc == 0 && getcom(buf, "%%EOF") != NULL) {
1044 			n = 0;
1045 			goto eof;
1046 		}
1047 		if (state == 1 && indoc == 0 &&
1048 				getcom(buf, "%%Trailer") != NULL) {
1049 			state = 2;
1050 			continue;
1051 		}
1052 		if (state == 1 && getcom(buf, "%%BeginDocument:") != NULL) {
1053 			indoc++;
1054 			continue;
1055 		}
1056 		if (state == 1 && indoc > 0 &&
1057 				getcom(buf, "%%EndDocument") != NULL) {
1058 			indoc--;
1059 			continue;
1060 		}
1061 		if (state == 1 &&
1062 				(cp = getcom(buf, "%%BeginBinary:")) != NULL) {
1063 			if ((k = strtol(cp, &cp, 10)) > 0)
1064 				psskip(fp, k);
1065 			continue;
1066 		}
1067 		if (state == 1 && (cp = getcom(buf, "%%BeginData:")) != NULL) {
1068 			if ((k = strtol(cp, &cp, 10)) > 0) {
1069 				while (*cp == ' ' || *cp == '\t')
1070 					cp++;
1071 				while (*cp && *cp != ' ' && *cp != '\t')
1072 					cp++;
1073 				while (*cp == ' ' || *cp == '\t')
1074 					cp++;
1075 				if (strncmp(cp, "Bytes", 5) == 0)
1076 					psskip(fp, k);
1077 				else if (strncmp(cp, "Lines", 5) == 0) {
1078 					while (k--) {
1079 						n = psgetline(fp, &buf, &size);
1080 						if (n == 0)
1081 							goto eof;
1082 					}
1083 				}
1084 			}
1085 			continue;
1086 		}
1087 	}
1088 	free(fp);
1089 	free(buf);
1090 	close(fd);
1091 }
1092 #endif	/* !NROFF */
1093 
1094 void
casepsbb(void)1095 casepsbb(void)
1096 {
1097 #ifndef	NROFF
1098 	char	*buf = NULL;
1099 	int	c;
1100 	int	n = 0, sz = 0;
1101 	double	bb[4] = { 0, 0, 0, 0 };
1102 
1103 	lgf++;
1104 	skip(1);
1105 	do {
1106 		c = getach();
1107 		if (n >= sz)
1108 			buf = realloc(buf, (sz += 14) * sizeof *buf);
1109 		buf[n++] = c;
1110 	} while (c);
1111 	getpsbb(buf, bb);
1112 	free(buf);
1113 	setnrf("llx", bb[0], 0);
1114 	setnrf("lly", bb[1], 0);
1115 	setnrf("urx", bb[2], 0);
1116 	setnrf("ury", bb[3], 0);
1117 #endif	/* !NROFF */
1118 }
1119 
1120 static const struct {
1121 	enum warn	n;
1122 	const char	*s;
1123 } warnnames[] = {
1124 	{ WARN_NONE,	"none" },
1125 	{ WARN_CHAR,	"char" },
1126 	{ WARN_NUMBER,	"number" },
1127 	{ WARN_BREAK,	"break" },
1128 	{ WARN_DELIM,	"delim" },
1129 	{ WARN_EL,	"el" },
1130 	{ WARN_SCALE,	"scale" },
1131 	{ WARN_RANGE,	"range" },
1132 	{ WARN_SYNTAX,	"syntax" },
1133 	{ WARN_DI,	"di" },
1134 	{ WARN_MAC,	"mac" },
1135 	{ WARN_REG,	"reg" },
1136 	{ WARN_RIGHT_BRACE, "right-brace" },
1137 	{ WARN_MISSING,	"missing" },
1138 	{ WARN_INPUT,	"input" },
1139 	{ WARN_ESCAPE,	"escape" },
1140 	{ WARN_SPACE,	"space" },
1141 	{ WARN_FONT,	"font" },
1142 	{ WARN_ALL,	"all" },
1143 	{ WARN_W,	"w" },
1144 	{ 0,		NULL }
1145 };
1146 
1147 static int
warn1(void)1148 warn1(void)
1149 {
1150 	char	name[NC];
1151 	int	i, n, sign;
1152 	tchar	c;
1153 
1154 	switch (cbits(c = getch())) {
1155 	case '-':
1156 		c = getch();
1157 		sign = -1;
1158 		break;
1159 	case '+':
1160 		c = getch();
1161 		sign = 1;
1162 		break;
1163 	default:
1164 		sign = 0;
1165 		break;
1166 	case 0:
1167 		return 1;
1168 	}
1169 	ch = c;
1170 	n = atoi0();
1171 	if ((i = cbits(ch)) != 0 && i != ' ' && i != '\n') {
1172 		if (c != ch) {
1173 			while (getach());
1174 			errprint("illegal number, char %c", i);
1175 			return 1;
1176 		}
1177 		for (i = 0; i < sizeof name - 2; i++) {
1178 			if ((c = getach()) == 0)
1179 				break;
1180 			name[i] = c;
1181 		}
1182 		name[i] = 0;
1183 		for (i = 0; warnnames[i].s; i++)
1184 			if (strcmp(name, warnnames[i].s) == 0) {
1185 				n = warnnames[i].n;
1186 				break;
1187 			}
1188 		if (warnnames[i].s == NULL) {
1189 			errprint("unknown warning category %s", name);
1190 			return 1;
1191 		}
1192 	}
1193 	switch (sign) {
1194 	case 1:
1195 		warn |= n;
1196 		break;
1197 	case -1:
1198 		warn &= ~n;
1199 		break;
1200 	default:
1201 		warn = n;
1202 	}
1203 	return 0;
1204 }
1205 
1206 void
casewarn(void)1207 casewarn(void)
1208 {
1209 	if (skip(0))
1210 		warn = WARN_W;
1211 	else
1212 		while (!warn1() && !skip(0));
1213 }
1214 
1215 void
nosuch(int rq)1216 nosuch(int rq)
1217 {
1218 	if (rq && rq != RIGHT && rq != PAIR(RIGHT, RIGHT) && warn & WARN_MAC)
1219 		errprint("%s: no such request", macname(rq));
1220 }
1221 
1222 void
missing(void)1223 missing(void)
1224 {
1225 	if (warn & WARN_MISSING) {
1226 		if (lastrq)
1227 			errprint("%s: missing argument", macname(lastrq));
1228 		else
1229 			errprint("missing argument");
1230 	}
1231 }
1232 
1233 void
nodelim(int delim)1234 nodelim(int delim)
1235 {
1236 	if (warn & WARN_DELIM)
1237 		errprint("%c delimiter missing", (int)delim);
1238 }
1239 
1240 void
illseq(int wc,const char * mb,int n)1241 illseq(int wc, const char *mb, int n)
1242 {
1243 	if ((warn & WARN_INPUT) == 0)
1244 		return;
1245 	if (n == -3)
1246 		errprint("non-ASCII input byte 0x%x terminates name", wc);
1247 	else if (n == 0) {
1248 		if (wc & ~0177)
1249 			errprint("ignoring '%U' in input", wc);
1250 		else
1251 			errprint("ignoring '\\%o' in input", wc);
1252 	} else
1253 		errprint("illegal byte sequence at '\\%o' in input", *mb&0377);
1254 }
1255 
1256 void
storerq(int i)1257 storerq(int i)
1258 {
1259 	tchar	tp[2];
1260 
1261 	tp[0] = mkxfunc(RQ, i);
1262 	tp[1] = 0;
1263 	pushback(tp);
1264 }
1265 
1266 int
fetchrq(tchar * tp)1267 fetchrq(tchar *tp)
1268 {
1269 	if (ismot(tp[0]) || !isxfunc(tp[0], RQ))
1270 		return 0;
1271 	return sbits(tp[0]);
1272 }
1273 
1274 void
morechars(int n)1275 morechars(int n)
1276 {
1277 	int	i, nnc;
1278 
1279 	if (n <= NCHARS)
1280 		return;
1281 	for (nnc = 1024; nnc <= n; nnc <<= 1);
1282 	widcache = realloc(widcache, nnc * sizeof *widcache);
1283 	memset(&widcache[NCHARS], 0, (nnc-NCHARS) * sizeof *widcache);
1284 	trtab = realloc(trtab, nnc * sizeof *trtab);
1285 	trnttab = realloc(trnttab, nnc * sizeof *trnttab);
1286 	for (i = NCHARS; i < nnc; i++)
1287 		trnttab[i] = trtab[i] = i;
1288 	trintab = realloc(trintab, nnc * sizeof *trintab);
1289 	memset(&trintab[NCHARS], 0, (nnc-NCHARS) * sizeof *trintab);
1290 	gchtab = realloc(gchtab, nnc * sizeof *gchtab);
1291 	memset(&gchtab[NCHARS], 0, (nnc-NCHARS) * sizeof *gchtab);
1292 	chartab = realloc(chartab, nnc * sizeof *chartab);
1293 	memset(&chartab[NCHARS], 0, (nnc-NCHARS) * sizeof *chartab);
1294 #ifndef	NROFF
1295 	fchartab = realloc(fchartab, nnc * sizeof *fchartab);
1296 	memset(&fchartab[NCHARS], 0, (nnc-NCHARS) * sizeof *fchartab);
1297 	for (i = 0; i <= nfonts; i++) {
1298 		extern short	**fitab;
1299 		if (fitab != NULL && fitab[i] != NULL) {
1300 			fitab[i] = realloc(fitab[i], nnc * sizeof **fitab);
1301 			memset(&fitab[i][NCHARS], 0,
1302 					(nnc-NCHARS) * sizeof **fitab);
1303 		}
1304 		if (lhangtab != NULL && lhangtab[i] != NULL) {
1305 			lhangtab[i] = realloc(lhangtab[i],
1306 					nnc * sizeof **lhangtab);
1307 			memset(&lhangtab[i][NCHARS], 0,
1308 					(nnc-NCHARS) * sizeof **lhangtab);
1309 		}
1310 		if (lhangtab != NULL && rhangtab[i] != NULL) {
1311 			rhangtab[i] = realloc(rhangtab[i],
1312 					nnc * sizeof **rhangtab);
1313 			memset(&rhangtab[i][NCHARS], 0,
1314 					(nnc-NCHARS) * sizeof **rhangtab);
1315 		}
1316 		if (kernafter != NULL && kernafter[i] != NULL) {
1317 			kernafter[i] = realloc(kernafter[i],
1318 					nnc * sizeof **kernafter);
1319 			memset(&kernafter[i][NCHARS], 0,
1320 					(nnc-NCHARS) * sizeof **kernafter);
1321 		}
1322 		if (kernbefore != NULL && kernbefore[i] != NULL) {
1323 			kernbefore[i] = realloc(kernbefore[i],
1324 					nnc * sizeof **kernbefore);
1325 			memset(&kernbefore[i][NCHARS], 0,
1326 					(nnc-NCHARS) * sizeof **kernbefore);
1327 		}
1328 		if (ftrtab != NULL && ftrtab[i] != NULL) {
1329 			int	j;
1330 			ftrtab[i] = realloc(ftrtab[i], nnc * sizeof **ftrtab);
1331 			for (j = NCHARS; j < nnc; j++)
1332 				ftrtab[i][j] = j;
1333 		}
1334 		if (lgtab != NULL && lgtab[i] != NULL) {
1335 			lgtab[i] = realloc(lgtab[i], nnc * sizeof **lgtab);
1336 			memset(&lgtab[i][NCHARS], 0,
1337 					(nnc-NCHARS) * sizeof **lgtab);
1338 		}
1339 		if (lgrevtab != NULL && lgrevtab[i] != NULL) {
1340 			lgrevtab[i] = realloc(lgrevtab[i],
1341 					nnc * sizeof **lgrevtab);
1342 			memset(&lgrevtab[i][NCHARS], 0,
1343 					(nnc-NCHARS) * sizeof **lgrevtab);
1344 		}
1345 	}
1346 #endif	/* !NROFF */
1347 	NCHARS = nnc;
1348 }
1349