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 2003 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 "t6.c	1.9	05/06/08 SMI"	*/
32 
33 /*
34  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35  *
36  * Sccsid @(#)t6.c	1.194 (gritter) 2/7/10
37  */
38 
39 /*
40  * Changes Copyright (c) 2014 Carsten Kunze <carsten.kunze at arcor.de>
41  */
42 
43 /*
44  * University Copyright- Copyright (c) 1982, 1986, 1988
45  * The Regents of the University of California
46  * All Rights Reserved
47  *
48  * University Acknowledgment- Portions of this document are derived from
49  * software developed by the University of California, Berkeley, and its
50  * contributors.
51  */
52 
53 /*
54  * t6.c
55  *
56  * width functions, sizes and fonts
57  */
58 
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <limits.h>
64 #include "tdef.h"
65 #include "dev.h"
66 #include <ctype.h>
67 #include <string.h>
68 #include <fcntl.h>
69 #include <unistd.h>
70 #include "ext.h"
71 #include "afm.h"
72 #include "pt.h"
73 #include "troff.h"
74 #include "fontmap.h"
75 
76 /* fitab[f][c] is 0 if c is not on font f */
77 	/* if it's non-zero, c is in fontab[f] at position
78 	 * fitab[f][c].
79 	 */
80 int	*fontlab;
81 int	*pstab;
82 int	*cstab;
83 int	*ccstab;
84 int	**fallbacktab;
85 float	*zoomtab;
86 int	*bdtab;
87 int	**lhangtab;
88 int	**rhangtab;
89 int	**kernafter;
90 int	**kernbefore;
91 int	**ftrtab;
92 struct lgtab	**lgtab;
93 int	***lgrevtab;
94 struct tracktab	*tracktab;
95 int	sbold = 0;
96 int	kern = 0;
97 struct box	mediasize, bleedat, trimat, cropat;
98 int	psmaxcode;
99 struct ref	*anchors, *links, *ulinks;
100 static int	_minflg;
101 int	lastrst;
102 int	lastrsb;
103 int	spacewidth;
104 
105 static void	kernsingle(int **);
106 static int	_ps2cc(const char *name, int create);
107 
108 int
width(register tchar j)109 width(register tchar j)
110 {
111 	register int i, k;
112 
113 	_minflg = minflg;
114 	minflg = minspc = 0;
115 	lasttrack = 0;
116 	rawwidth = 0;
117 	lastrst = lastrsb = 0;
118 	if (isadjspc(j))
119 		return(0);
120 	if (j & (ZBIT|MOT)) {
121 		if (iszbit(j))
122 			return(0);
123 		if (isvmot(j))
124 			return(0);
125 		k = absmot(j);
126 		if (isnmot(j))
127 			k = -k;
128 		return(k);
129 	}
130 	i = cbits(j);
131 	if (html && i >= NCHARS)
132 		i = ' ';
133 	if (i < ' ') {
134 		if (i == '\b')
135 			return(-widthp);
136 		if (i == PRESC)
137 			i = eschar;
138 		else if (iscontrol(i))
139 			return(0);
140 		else if (isxfunc(j, CHAR)) {
141 			k = charout[sbits(j)].width + lettrack;
142 			lastrst = charout[sbits(j)].height;
143 			lastrsb = -charout[sbits(j)].depth;
144 			goto set;
145 		}
146 	} else if (i == ' ' && issentsp(j))
147 	{
148 		_minflg = 0;
149 		return(ses);
150 	}
151 	if (i==ohc)
152 		return(0);
153 	if (!xflag || !isdi(j)) {
154 		if (i == STRETCH)
155 			setcbits(j, ' ');
156 		i = trtab[i];
157 		i = ftrans(fbits(j), i);
158 	}
159 	if (i < 32)
160 		return(0);
161 	lasttrack = 0;
162 	if (sfbits(j) == oldbits) {
163 		xfont = pfont;
164 		xpts = ppts;
165 	} else
166 		xbits(j, 0);
167 	if (widcache[i-32].fontpts == xfont + (xpts<<8) &&
168 			(i > 32 || widcache[i-32].evid == evname) &&
169 			!setwdf && !_minflg && !horscale) {
170 		rawwidth = widcache[i-32].width - widcache[i-32].track;
171 		k = widcache[i-32].width + lettrack;
172 		lastrst = widcache[i-32].rst;
173 		lastrsb = widcache[i-32].rsb;
174 		lasttrack = widcache[i-32].track;
175 	} else {
176 		if (_minflg && i == 32 && cbits(j) != 32)
177 			_minflg = 0;
178 		k = getcw(i-32);
179 		if (i == 32 && _minflg && !cs) {
180 			_minflg = 0;
181 			minspc = getcw(0) - k;
182 		}
183 		_minflg = 0;
184 	set:	if (bd && !fmtchar)
185 			k += (bd - 1) * HOR;
186 		if (cs && !fmtchar)
187 			k = cs;
188 	}
189 	widthp = k;
190 	return(k);
191 }
192 
193 /*
194  * clear width cache-- s means just space
195  */
196 void
zapwcache(int s)197 zapwcache(int s)
198 {
199 	register int i;
200 
201 	if (s) {
202 		widcache[0].fontpts = 0;
203 		return;
204 	}
205 	for (i=0; i<NWIDCACHE; i++)
206 		widcache[i].fontpts = 0;
207 }
208 
209 int
getcw(register int i)210 getcw(register int i)
211 {
212 	register int	k;
213 	register int	*p;
214 	register int	x, j;
215 	int nocache = 0;
216 	int	ofont = xfont;
217 	int	s, t;
218 	double	z = 1, zv;
219 	struct afmtab	*a;
220 	int	cd = 0;
221 
222 	bd = 0;
223 	if (i >= nchtab + 128-32) {
224 		if (afmtab && fontbase[xfont]->afmpos - 1 >= 0) {
225 			cd = nchtab + 128;
226 			i -= cd;
227 		} else {
228 			j = abscw(i + 32 - (nchtab+128));
229 			goto g0;
230 		}
231 	}
232 	if (i == 0) {	/* a blank */
233 		if (_minflg) {
234 			j = minspsz;
235 			nocache = 1;
236 		} else
237 			j = spacesz;
238 		if (fontbase[xfont]->cspacewidth >= 0)
239 			k = fontbase[xfont]->cspacewidth;
240 		else if (spacewidth || gflag)
241 			k = fontbase[xfont]->spacewidth;
242 		else
243 			k = fontab[xfont][0];
244 		k = (k * j + 6) / 12;
245 		lastrst = lastrsb = 0;
246 		/* this nonsense because .ss cmd uses 1/36 em as its units */
247 		/* and default is 12 */
248 		goto g1;
249 	}
250 	if ((j = fitab[xfont][i]) == 0) {	/* it's not on current font */
251 		int ii, jj, t;
252 		/* search through search list of xfont
253 		 * to see what font it ought to be on.
254 		 * first searches explicit fallbacks, then
255 		 * searches S, then remaining fonts in wraparound order.
256 		 */
257 		nocache = 1;
258 		if (fallbacktab[xfont]) {
259 			for (jj = 0; fallbacktab[xfont][jj] != 0; jj++) {
260 				if ((ii = findft(fallbacktab[xfont][jj],0)) < 0)
261 					continue;
262 				t = ftrans(ii, i + 32) - 32;
263 				j = fitab[ii][t];
264 				if (j != 0) {
265 					xfont = ii;
266 					goto found;
267 				}
268 			}
269 		}
270 		if (smnt) {
271 			for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
272 				if (fontbase[ii] == NULL)
273 					continue;
274 				t = ftrans(ii, i + 32) - 32;
275 				j = fitab[ii][t];
276 				if (j != 0) {
277 					/*
278 					 * troff traditionally relies on the
279 					 * device postprocessor to find the
280 					 * appropriate character since it
281 					 * searches the fonts in the same
282 					 * order. This does not work with the
283 					 * new requests anymore, so change
284 					 * the font explicitly.
285 					 */
286 					if (xflag)
287 						xfont = ii;
288 				found:	p = fontab[ii];
289 					k = *(p + j);
290 					if (afmtab &&
291 					    (t=fontbase[ii]->afmpos-1)>=0) {
292 						a = afmtab[t];
293 						if (a->bbtab[j]) {
294 							lastrst = a->bbtab[j][3];
295 							lastrsb = a->bbtab[j][1];
296 						} else {
297 							lastrst = a->ascender;
298 							lastrsb = a->descender;
299 						}
300 					}
301 					if (xfont == sbold)
302 						bd = bdtab[ii];
303 					if (setwdf)
304 						numtab[CT].val |= kerntab[ii][j];
305 					goto g1;
306 				}
307 			}
308 		}
309 		k = fontab[xfont][0];	/* leave a space-size space */
310 		lastrst = lastrsb = 0;
311 		goto g1;
312 	}
313  g0:
314 	p = fontab[xfont];
315 	if (setwdf)
316 		numtab[CT].val |= kerntab[xfont][j];
317 	if (afmtab && (t = fontbase[xfont]->afmpos-1) >= 0) {
318 		a = afmtab[t];
319 		if (a->bbtab[j]) {
320 			lastrst = a->bbtab[j][3];
321 			lastrsb = a->bbtab[j][1];
322 		} else {
323 			/*
324 			 * Avoid zero values by all means. In many use
325 			 * cases, endless loops will result unless values
326 			 * are non-zero.
327 			 */
328 			lastrst = a->ascender;
329 			lastrsb = a->descender;
330 		}
331 	}
332 	k = *(p + j);
333 	if (dev.anysize == 0 || xflag == 0 || (z = zoomtab[xfont]) == 0)
334 		z = 1;
335  g1:
336 	zv = z;
337 	if (horscale) {
338 		z *= horscale;
339 		nocache = 1;
340 	}
341 	if (!bd)
342 		bd = bdtab[ofont];
343 	if ((cs = cstab[ofont])) {
344 		nocache = 1;
345 		if ((ccs = ccstab[ofont]))
346 			x = pts2u(ccs);
347 		else
348 			x = xpts;
349 		cs = (cs * EMPTS(x)) / 36;
350 	}
351 	k = (k * z * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth;
352 	lastrst = (lastrst * zv * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth;
353 	lastrsb = (lastrsb * zv * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth;
354 	rawwidth = k;
355 	s = xpts;
356 	lasttrack = 0;
357 	if (s <= tracktab[ofont].s1 && tracktab[ofont].n1)
358 		lasttrack = tracktab[ofont].n1;
359 	else if (s >= tracktab[ofont].s2 && tracktab[ofont].n2)
360 		lasttrack = tracktab[ofont].n2;
361 	else if (s > tracktab[ofont].s1 && s < tracktab[ofont].s2) {
362 		int	r;
363 		r = (s * tracktab[ofont].n2 - s * tracktab[ofont].n1
364 				+ tracktab[ofont].s2 * tracktab[ofont].n1
365 				- tracktab[ofont].s1 * tracktab[ofont].n2)
366 			/ (tracktab[ofont].s2 - tracktab[ofont].s1);
367 		if (r != 0)
368 			lasttrack = r;
369 	}
370 	k += lasttrack + lettrack;
371 	i += cd;
372 	if (nocache|bd)
373 		widcache[i].fontpts = 0;
374 	else {
375 		widcache[i].fontpts = xfont + (xpts<<8);
376 		widcache[i].width = k - lettrack;
377 		widcache[i].rst = lastrst;
378 		widcache[i].rsb = lastrsb;
379 		widcache[i].track = lasttrack;
380 		widcache[i].evid = evname;
381 	}
382 	return(k);
383 	/* Unitwidth is Units/Point, where
384 	 * Units is the fundamental digitization
385 	 * of the character set widths, and
386 	 * Point is the number of goobies in a point
387 	 * e.g., for cat, Units=36, Point=6, so Unitwidth=36/6=6
388 	 * In effect, it's the size at which the widths
389 	 * translate directly into units.
390 	 */
391 }
392 
393 int
abscw(int n)394 abscw(int n)	/* return index of abs char n in fontab[], etc. */
395 {	register int i, ncf;
396 
397 	ncf = fontbase[xfont]->nwfont & BYTEMASK;
398 	for (i = 0; i < ncf; i++)
399 		if (codetab[xfont][i] == n)
400 			return i;
401 	return 0;
402 }
403 
404 int
onfont(tchar c)405 onfont(tchar c)
406 {
407 	int	k = cbits(c);
408 	int	f = fbits(c);
409 
410 	if (k <= ' ')
411 		return 1;
412 	k -= 32;
413 	if (k >= nchtab + 128-32) {
414 		if (afmtab && fontbase[f]->afmpos - 1 >= 0)
415 			k -= nchtab + 128;
416 		else
417 			return abscw(k + 32 - (nchtab+128)) != 0;
418 	}
419 	return fitab[f][k] != 0;
420 }
421 
422 static int
fvert2pts(int f,int s,int k)423 fvert2pts(int f, int s, int k)
424 {
425 	double	z;
426 
427 	if (k != 0) {
428 		k = (k * u2pts(s) + (Unitwidth / 2)) / Unitwidth;
429 		if (dev.anysize && xflag && (z = zoomtab[f]) != 0)
430 			k *= z;
431 	}
432 	return k;
433 }
434 
435 int
getascender(void)436 getascender(void)
437 {
438 	struct afmtab	*a;
439 	int	n;
440 
441 	if ((n = fontbase[font]->afmpos - 1) >= 0) {
442 		a = afmtab[n];
443 		return fvert2pts(font, pts, a->ascender);
444 	} else
445 		return 0;
446 }
447 
448 int
getdescender(void)449 getdescender(void)
450 {
451 	struct afmtab	*a;
452 	int	n;
453 
454 	if ((n = fontbase[font]->afmpos - 1) >= 0) {
455 		a = afmtab[n];
456 		return fvert2pts(font, pts, a->descender);
457 	} else
458 		return 0;
459 }
460 
461 int
kernadjust(tchar c,tchar d)462 kernadjust(tchar c, tchar d)
463 {
464 	lastkern = 0;
465 	if (!kern || ismot(c) || ismot(d) || html)
466 		return 0;
467 	if (!isdi(c)) {
468 		c = trtab[cbits(c)] | (c & SFMASK);
469 		c = ftrans(fbits(c), cbits(c)) | (c & SFMASK);
470 	}
471 	if (!isdi(d)) {
472 		d = trtab[cbits(d)] | (d & SFMASK);
473 		d = ftrans(fbits(d), cbits(d)) | (d & SFMASK);
474 	}
475 	return getkw(c, d);
476 }
477 
478 #define	kprime		1021
479 #define	khash(c, d)	(((2654435769U * (c) * (d) >> 16)&0x7fffffff) % kprime)
480 
481 static struct knode {
482 	struct knode	*next;
483 	tchar	c;
484 	tchar	d;
485 	int	n;
486 } **ktable;
487 
488 static void
kadd(tchar c,tchar d,int n)489 kadd(tchar c, tchar d, int n)
490 {
491 	struct knode	*kn;
492 	int	h;
493 
494 	if (ktable == NULL)
495 		ktable = calloc(kprime, sizeof *ktable);
496 	h = khash(c, d);
497 	kn = calloc(1, sizeof *kn);
498 	kn->c = c;
499 	kn->d = d;
500 	kn->n = n;
501 	kn->next = ktable[h];
502 	ktable[h] = kn;
503 }
504 
505 static void
kzap(int f)506 kzap(int f)
507 {
508 	struct knode	*kp;
509 	int	i;
510 
511 	if (ktable == NULL)
512 		return;
513 	for (i = 0; i < kprime; i++)
514 		for (kp = ktable[i]; kp; kp = kp->next)
515 			if (fbits(kp->c) == f || fbits(kp->d) == f)
516 				kp->n = INT_MAX;
517 }
518 
519 static tchar
findchar(tchar c)520 findchar(tchar c)
521 {
522 	int	f, i;
523 
524 	f = fbits(c);
525 	c = cbits(c);
526 	i = c - 32;
527 	if (c != ' ' && i > 0 && i < nchtab + 128 - 32 && fitab[f][i] == 0) {
528 		int	ii, jj;
529 		if (fallbacktab[f]) {
530 			for (jj = 0; fallbacktab[f][jj] != 0; jj++) {
531 				if ((ii = findft(fallbacktab[f][jj], 0)) < 0)
532 					continue;
533 				if (fitab[ii][i] != 0) {
534 					f = ii;
535 					goto found;
536 				}
537 			}
538 		}
539 		if (smnt) {
540 			for (ii=smnt, jj=0; jj < nfonts; jj++, ii=ii % nfonts + 1) {
541 				if (fontbase[ii] == NULL)
542 					continue;
543 				if (fitab[ii][i] != 0) {
544 					f = ii;
545 					goto found;
546 				}
547 			}
548 		}
549 		return 0;
550 	}
551 found:
552 	setfbits(c, f);
553 	return c;
554 }
555 
556 static struct knode *
klook(tchar c,tchar d)557 klook(tchar c, tchar d)
558 {
559 	struct knode	*kp;
560 	int	h;
561 
562 	c = findchar(c);
563 	d = findchar(d);
564 	h = khash(c, d);
565 	for (kp = ktable[h]; kp; kp = kp->next)
566 		if (kp->c == c && kp->d == d)
567 			break;
568 	return kp && kp->n != INT_MAX ? kp : NULL;
569 }
570 
571 int
getkw(tchar c,tchar d)572 getkw(tchar c, tchar d)
573 {
574 	struct knode	*kp;
575 	struct afmtab	*a;
576 	int	f, g, i, j, k, n, s, I, J;
577 	double	z;
578 
579 	if (isxfunc(c, CHAR))
580 		c = charout[sbits(c)].ch;
581 	if (isxfunc(d, CHAR))
582 		d = charout[sbits(d)].ch;
583 	lastkern = 0;
584 	if (!kern || iszbit(c) || iszbit(d) || ismot(c) || ismot(d))
585 		return 0;
586 	if (sbits(c) != sbits(d))
587 		return 0;
588 	f = fbits(c);
589 	g = fbits(d);
590 	if ((s = sbits(c)) == 0) {
591 		s = xpts;
592 		if (f == 0)
593 			f = xfont;
594 	}
595 	i = cbits(c);
596 	j = cbits(d);
597 	if (i == SLANT || j == SLANT || i == XFUNC || j == XFUNC || cstab[f])
598 		return 0;
599 	k = 0;
600 	if (i >= 32 && j >= 32) {
601 		if (ktable != NULL && (kp = klook(c, d)) != NULL)
602 			k = kp->n;
603 		else if ((n = (fontbase[f]->afmpos)-1) >= 0 &&
604 				n == (fontbase[g]->afmpos)-1 &&
605 				fontbase[f]->kernfont >= 0) {
606 			a = afmtab[n];
607 			I = i - 32;
608 			J = j - 32;
609 			if (I >= nchtab + 128)
610 				I -= nchtab + 128;
611 			if (J >= nchtab + 128)
612 				J -= nchtab + 128;
613 			k = afmgetkern(a, I, J);
614 			if (abs(k) < fontbase[f]->kernfont)
615 				k = 0;
616 		}
617 		if (j>32 && kernafter != NULL && kernafter[fbits(c)] != NULL)
618 			k += kernafter[fbits(c)][i];
619 		if (i>32 && kernbefore != NULL && kernbefore[fbits(d)] != NULL)
620 			k += kernbefore[fbits(d)][j];
621 	}
622 	if (k != 0) {
623 		k = (k * u2pts(s) + (Unitwidth / 2)) / Unitwidth;
624 		if (dev.anysize && xflag && (z = zoomtab[f]) != 0)
625 			k *= z;
626 	}
627 	lastkern = k;
628 	return k;
629 }
630 
631 void
xbits(register tchar i,int bitf)632 xbits(register tchar i, int bitf)
633 {
634 	register int k;
635 
636 	xfont = fbits(i);
637 	k = sbits(i);
638 	if (k) {
639 		xpts = dev.anysize && xflag ? k : pstab[--k];
640 		oldbits = sfbits(i);
641 		pfont = xfont;
642 		ppts = xpts;
643 		return;
644 	}
645 	switch (bitf) {
646 	case 0:
647 		xfont = font;
648 		xpts = pts;
649 		break;
650 	case 1:
651 		xfont = pfont;
652 		xpts = ppts;
653 		break;
654 	case 2:
655 		xfont = mfont;
656 		xpts = mpts;
657 	}
658 }
659 
660 static tchar
postchar1(const char * temp,int f)661 postchar1(const char *temp, int f)
662 {
663 	struct namecache	*np;
664 	struct afmtab	*a;
665 	int	i;
666 
667 	if (afmtab && (i = (fontbase[f]->afmpos) - 1) >= 0) {
668 		a = afmtab[i];
669 		np = afmnamelook(a, temp);
670 		if (np->afpos != 0) {
671 			if (np->fival[0] != NOCODE &&
672 					fitab[f][np->fival[0]])
673 				return np->fival[0] + 32 + nchtab + 128;
674 			else if (np->fival[1] != NOCODE &&
675 					fitab[f][np->fival[1]])
676 				return np->fival[1] + 32 + nchtab + 128;
677 			else
678 				return 0;
679 		}
680 	}
681 	return(0);
682 }
683 
684 static tchar
postchar(const char * temp,int * fp)685 postchar(const char *temp, int *fp)
686 {
687 	int	i, j;
688 	tchar	c;
689 
690 	*fp = font;
691 	if ((c = postchar1(temp, *fp)) != 0)
692 		return c;
693 	if (fallbacktab[font]) {
694 		for (j = 0; fallbacktab[font][j] != 0; j++) {
695 			if ((i = findft(fallbacktab[font][j], 0)) < 0)
696 				continue;
697 			if ((c = postchar1(temp, i)) != 0 && fchartab[c] == 0) {
698 				*fp = i;
699 				return c;
700 			}
701 		}
702 	}
703 	if (smnt) {
704 		for (i=smnt, j=0; j < nfonts; j++, i=i % nfonts + 1) {
705 			if (fontbase[i] == NULL)
706 				continue;
707 			if ((c = postchar1(temp, i)) != 0 && fchartab[c] == 0) {
708 				*fp = i;
709 				return c;
710 			}
711 		}
712 	}
713 	return 0;
714 }
715 
716 const struct amap {
717 	char *alias;
718 	char *trname;
719 } amap[] = {
720 	{ "lq", "``" },
721 	{ "rq", "''" },
722 	{ NULL, NULL }
723 };
724 
725 tchar
setch(int delim)726 setch(int delim) {
727 	register int j;
728 	char	temp[NC];
729 	tchar	c, d[2] = {0, 0};
730 	int	f, n;
731 	const struct amap *ap;
732 
733 	n = 0;
734 	if (delim == 'C')
735 		d[0] = getach();
736 	do {
737 		c = getach();
738 		if (c == 0 && n < 2)
739 			return(0);
740 		if (n >= sizeof temp) {
741 			temp[n-1] = 0;
742 			break;
743 		}
744 		if ((delim == '[' && c == ']') || (delim == 'C' && c == d[0])) {
745 			temp[n] = 0;
746 			break;
747 		}
748 		temp[n++] = c;
749 		if (delim == '(' && n == 2) {
750 			temp[n] = 0;
751 			break;
752 		}
753 	} while (c);
754 	for (ap = amap; ap->alias; ap++)
755 		if (!strcmp(ap->alias, temp)) {
756 			size_t l;
757 			char *s = ap->trname;
758 			if ((l = strlen(s) + 1) > NC) {
759 				fprintf(stderr, "%s %i: strlen(%s)+1 > %d\n",
760 				    __FILE__, __LINE__, s, NC);
761 				break;
762 			}
763 			memcpy(temp, s, l);
764 			break;
765 		}
766 	if (delim == '[' && c != ']') {
767 		nodelim(']');
768 		return ' ';
769 	}
770 	if (delim == 'C' && c != d[0]) {
771 		nodelim(d[0]);
772 		return ' ';
773 	}
774 	c = 0;
775 	if (delim == '[' || delim == 'C') {
776 		size_t l = strlen(temp);
777 		if (gemu) {
778 			if (l == 5 && *temp == 'u'
779 			    && isxdigit((unsigned)temp[1])
780 			    && isxdigit((unsigned)temp[2])
781 			    && isxdigit((unsigned)temp[3])
782 			    && isxdigit((unsigned)temp[4])) {
783 				int n;
784 				n = strtol(temp + 1, NULL, 16);
785 				if (n)
786 					c = setuc0(n);
787 			} else if ((l == 6 || (l == 7
788 			    && isdigit((unsigned)temp[6])))
789 			    && isdigit((unsigned)temp[5])
790 			    && isdigit((unsigned)temp[4])
791 			    && !strncmp(temp, "char", 4)) {
792 				int i = atoi(temp + 4);
793 				if (i <= 127)
794 					c = i + nchtab + 128;
795 			}
796 		}
797 		if (!c && (c = postchar(temp, &f))) {
798 			c |= chbits & ~FMASK;
799 			setfbits(c, f);
800 		}
801 	}
802 	if (c == 0)
803 		for (j = 0; j < nchtab; j++)
804 			if (strcmp(&chname[chtab[j]], temp) == 0) {
805 				c = (j + 128) | chbits;
806 				break;
807 			}
808 	if (c == 0 && delim == '(')
809 		if ((c = postchar(temp, &f)) != 0) {
810 			c |= chbits & ~FMASK;
811 			setfbits(c, f);
812 		}
813 	if (c == 0 && (c = _ps2cc(temp, 0)) != 0) {
814 		c += nchtab + 128 + 32 + 128 - 32 + nchtab;
815 		if (chartab[c] == NULL)
816 			c = 0;
817 	}
818 	if (c == 0 && warn & WARN_CHAR)
819 		errprint("missing glyph \\%c%s%s%s%s", delim, d, temp, d,
820 				delim == '[' ? "]" : "");
821 	if (c == 0 && !tryglf)
822 		c = ' ';
823 	return c;
824 }
825 
setabs(void)826 tchar setabs(void)		/* set absolute char from \C'...' */
827 {
828 	int n;
829 
830 	getch();
831 	n = 0;
832 	n = inumb(&n);
833 	getch();
834 	if (nonumb || n + nchtab + 128 >= NCHARS)
835 		return 0;
836 	return n + nchtab + 128;
837 }
838 
839 
840 
841 int
findft(register int i,int required)842 findft(register int i, int required)
843 {
844 	register int k;
845 	int nk;
846 	char	*mn, *mp;
847 
848 	if ((k = i - '0') >= 0 && k <= nfonts && k < smnt && fontbase[k])
849 		return(k);
850 	for (k = 0; k > nfonts || fontlab[k] != i; k++)
851 		if (k > nfonts) {
852 			mn = macname(i);
853 			nk = k;
854 			if ((k = strtol(mn, &mp, 10)) >= 0 && *mp == 0 &&
855 					mp > mn && k <= nfonts && fontbase[k])
856 				break;
857 			if (setfp(nk, i, NULL) == -1)
858 				return -1;
859 			else {
860 				fontlab[nk] = i;
861 				return nk;
862 			}
863 			if (required && warn & WARN_FONT)
864 				errprint("%s: no such font", mn);
865 			return(-1);
866 		}
867 	return(k);
868 }
869 
870 void
caseps(void)871 caseps(void)
872 {
873 	register int i;
874 
875 	if (skip(0))
876 		i = apts1;
877 	else {
878 		if (xflag == 0) {
879 			noscale++;
880 			apts = u2pts(apts);
881 		} else {
882 			dfact = INCH;
883 			dfactd = 72;
884 			res = VERT;
885 		}
886 		i = inumb(&apts);
887 		if (xflag == 0) {
888 			noscale--;
889 			i = pts2u(i);
890 			apts = pts2u(apts);
891 		}
892 		if (nonumb)
893 			return;
894 	}
895 	casps1(i);
896 }
897 
898 void
casps1(register int i)899 casps1(register int i)
900 {
901 
902 /*
903  * in olden times, it used to ignore changes to 0 or negative.
904  * this is meant to allow the requested size to be anything,
905  * in particular so eqn can generate lots of \s-3's and still
906  * get back by matching \s+3's.
907 
908 	if (i <= 0)
909 		return;
910 */
911 	apts1 = apts;
912 	apts = i;
913 	pts1 = pts;
914 	pts = findps(i);
915 	mchbits();
916 }
917 
918 int
findps(register int i)919 findps(register int i)
920 {
921 	register int j, k;
922 
923 	if (dev.anysize && xflag) {
924 		if (i <= 0)
925 			i = pstab[0];
926 		return i;
927 	}
928 	for (j=k=0 ; pstab[j] != 0 ; j++)
929 		if (abs(pstab[j]-i) < abs(pstab[k]-i))
930 			k = j;
931 
932 	return(pstab[k]);
933 }
934 
935 void
mchbits(void)936 mchbits(void)
937 {
938 	register int i, j, k;
939 
940 	i = pts;
941 	if (dev.anysize && xflag)
942 		j = i - 1;
943 	else for (j = 0; i > (k = pstab[j]); j++)
944 		if (!k) {
945 			k = pstab[--j];
946 			break;
947 		}
948 	chbits = 0;
949 	setsbits(chbits, ++j);
950 	setfbits(chbits, font);
951 	zapwcache(1);
952 	if (minspsz) {
953 		k = spacesz;
954 		spacesz = minspsz;
955 		minsps = width(' ' | chbits);
956 		spacesz = k;
957 		zapwcache(1);
958 	}
959 	if (letspsz) {
960 		k = spacesz;
961 		spacesz = letspsz;
962 		letsps = width(' ' | chbits);
963 		spacesz = k;
964 		zapwcache(1);
965 	}
966 	k = spacesz;
967 	spacesz = sesspsz;
968 	ses = width(' ' | chbits);
969 	spacesz = k;
970 	zapwcache(1);
971 	sps = width(' ' | chbits);
972 	zapwcache(1);
973 }
974 
975 void
setps(void)976 setps(void)
977 {
978 	tchar	c;
979 	register int i, j = 0;
980 	int	k;
981 
982 	i = cbits(c = getch());
983 	if (ismot(c) && xflag)
984 		return;
985 	if (ischar(i) && isdigit(i)) {		/* \sd or \sdd */
986 		i -= '0';
987 		if (i == 0)		/* \s0 */
988 			j = apts1;
989 		else if (i <= 3 && ischar(j = cbits(ch = getch())) &&
990 		    isdigit(j)) {	/* \sdd */
991 			j = 10 * i + j - '0';
992 			ch = 0;
993 			j = pts2u(j);
994 		} else		/* \sd */
995 			j = pts2u(i);
996 	} else if (i == '(') {		/* \s(dd */
997 		j = cbits(getch()) - '0';
998 		j = 10 * j + cbits(getch()) - '0';
999 		if (j == 0)		/* \s(00 */
1000 			j = apts1;
1001 		else
1002 			j = pts2u(j);
1003 	} else if (i == '+' || i == '-') {	/* \s+, \s- */
1004 		j = cbits(c = getch());
1005 		if (ischar(j) && isdigit(j)) {		/* \s+d, \s-d */
1006 			j -= '0';
1007 			j = pts2u(j);
1008 		} else if (j == '(') {		/* \s+(dd, \s-(dd */
1009 			j = cbits(getch()) - '0';
1010 			j = 10 * j + cbits(getch()) - '0';
1011 			j = pts2u(j);
1012 		} else if (xflag) {	/* \s+[dd], */
1013 			k = j == '[' ? ']' : j;			/* \s-'dd' */
1014 			setcbits(c, k);
1015 			dfact = INCH;
1016 			dfactd = 72;
1017 			res = HOR;
1018 			j = hatoi();
1019 			res = dfactd = dfact = 1;
1020 			if (nonumb)
1021 				return;
1022 			if (!issame(getch(), c))
1023 				nodelim(k);
1024 		}
1025 		if (i == '-')
1026 			j = -j;
1027 		j += apts;
1028 	} else if (xflag) {	/* \s'+dd', \s[dd] */
1029 		if (i == '[') {
1030 			i = ']';
1031 			setcbits(c, i);
1032 		}
1033 		dfact = INCH;
1034 		dfactd = 72;
1035 		res = HOR;
1036 		j = inumb2(&apts, &k);
1037 		if (nonumb)
1038 			return;
1039 		if (j == 0 && k == 0)
1040 			j = apts1;
1041 		if (!issame(getch(), c))
1042 			nodelim(i);
1043 	}
1044 	casps1(j);
1045 }
1046 
1047 
setht(void)1048 tchar setht(void)		/* set character height from \H'...' */
1049 {
1050 	int n;
1051 	tchar c;
1052 
1053 	getch();
1054 	dfact = INCH;
1055 	dfactd = 72;
1056 	res = VERT;
1057 	n = inumb(&apts);
1058 	getch();
1059 	if (n == 0 || nonumb)
1060 		n = apts;	/* does this work? */
1061 	c = CHARHT;
1062 	c |= ZBIT;
1063 	setfbits(c, font);
1064 	setsbits(c, n);
1065 	return(c);
1066 }
1067 
setslant(void)1068 tchar setslant(void)		/* set slant from \S'...' */
1069 {
1070 	int n;
1071 	tchar c;
1072 
1073 	getch();
1074 	n = 0;
1075 	n = inumb(&n);
1076 	getch();
1077 	if (nonumb)
1078 		n = 0;
1079 	c = SLANT;
1080 	c |= ZBIT;
1081 	setfbits(c, font);
1082 	setsbits(c, n+180);
1083 	return(c);
1084 }
1085 
1086 void
caseft(void)1087 caseft(void)
1088 {
1089 	skip(0);
1090 	setfont(1);
1091 }
1092 
1093 void
setfont(int a)1094 setfont(int a)
1095 {
1096 	register int i, j;
1097 
1098 	if (a)
1099 		i = getrq(3);
1100 	else
1101 		i = getsn(1);
1102 	if (!i || i == 'P') {
1103 		j = font1;
1104 		goto s0;
1105 	}
1106 	if (/* i == 'S' || */ i == '0')
1107 		return;
1108 	if ((j = findft(i, 0)) == -1)
1109 		if ((j = setfp(0, i, 0)) == -1) { /* try to put it in position 0 */
1110 			if (xflag) {
1111 				font1 = font;
1112 			}
1113 			return;
1114 		}
1115 s0:
1116 	font1 = font;
1117 	font = j;
1118 	mchbits();
1119 }
1120 
1121 void
setwd(void)1122 setwd(void)
1123 {
1124 	register int base, wid;
1125 	register tchar i;
1126 	tchar	delim, lasti = 0;
1127 	int	emsz, k;
1128 	int	savhp, savapts, savapts1, savfont, savfont1, savpts, savpts1;
1129 	int	savlgf;
1130 	int	rst = 0, rsb = 0;
1131 	int	n;
1132 
1133 	base = numtab[SB].val = numtab[ST].val = wid = numtab[CT].val = 0;
1134 	if (ismot(i = getch()))
1135 		return;
1136 	delim = i;
1137 	argdelim = delim;
1138 	n = noschr;
1139 	noschr = 0;
1140 	savhp = numtab[HP].val;
1141 	numtab[HP].val = 0;
1142 	savapts = apts;
1143 	savapts1 = apts1;
1144 	savfont = font;
1145 	savfont1 = font1;
1146 	savpts = pts;
1147 	savpts1 = pts1;
1148 	savlgf = lgf;
1149 	lgf = 0;
1150 	setwdf++;
1151 	while (i = getch(), !issame(i, delim) && !nlflg) {
1152 		k = width(i);
1153 		k += kernadjust(lasti, i);
1154 		lasti = i;
1155 		wid += k;
1156 		numtab[HP].val += k;
1157 		if (!ismot(i)) {
1158 			emsz = POINT * u2pts(xpts);
1159 		} else if (isvmot(i)) {
1160 			k = absmot(i);
1161 			if (isnmot(i))
1162 				k = -k;
1163 			base -= k;
1164 			emsz = 0;
1165 		} else
1166 			continue;
1167 		if (base < numtab[SB].val)
1168 			numtab[SB].val = base;
1169 		if ((k = base + emsz) > numtab[ST].val)
1170 			numtab[ST].val = k;
1171 		if (lastrst > rst)
1172 			rst = lastrst;
1173 		if (lastrsb < rsb)
1174 			rsb = lastrsb;
1175 	}
1176 	if (!issame(i, delim))
1177 		nodelim(delim);
1178 	argdelim = 0;
1179 	noschr = n;
1180 	setn1(wid, 0, (tchar) 0);
1181 	prwatchn(&numtab[CT]);
1182 	prwatchn(&numtab[SB]);
1183 	prwatchn(&numtab[ST]);
1184 	setnr("rst", rst, 0);
1185 	setnr("rsb", rsb, 0);
1186 	numtab[HP].val = savhp;
1187 	apts = savapts;
1188 	apts1 = savapts1;
1189 	font = savfont;
1190 	font1 = savfont1;
1191 	pts = savpts;
1192 	pts1 = savpts1;
1193 	lgf = savlgf;
1194 	mchbits();
1195 	setwdf = 0;
1196 }
1197 
1198 
vmot(void)1199 tchar vmot(void)
1200 {
1201 	dfact = lss;
1202 	vflag++;
1203 	return(mot());
1204 }
1205 
1206 
hmot(void)1207 tchar hmot(void)
1208 {
1209 	dfact = EM;
1210 	return(mot());
1211 }
1212 
1213 
mot(void)1214 tchar mot(void)
1215 {
1216 	register int j, n;
1217 	register tchar i;
1218 	tchar c, delim;
1219 
1220 	j = HOR;
1221 	delim = getch(); /*eat delim*/
1222 	if ((n = hatoi())) {
1223 		if (vflag)
1224 			j = VERT;
1225 		i = makem(quant(n, j));
1226 	} else
1227 		i = 0;
1228 	c = getch();
1229 	if (!issame(c, delim))
1230 		nodelim(delim);
1231 	vflag = 0;
1232 	dfact = 1;
1233 	return(i);
1234 }
1235 
1236 
sethl(int k)1237 tchar sethl(int k)
1238 {
1239 	register int j;
1240 	tchar i;
1241 
1242 	j = EM / 2;
1243 	if (k == 'u')
1244 		j = -j;
1245 	else if (k == 'r')
1246 		j = -2 * j;
1247 	vflag++;
1248 	i = makem(j);
1249 	vflag = 0;
1250 	return(i);
1251 }
1252 
1253 
makem(register int i)1254 tchar makem(register int i)
1255 {
1256 	register tchar j;
1257 
1258 	if ((j = i) < 0)
1259 		j = -j;
1260 	j = sabsmot(j) | MOT;
1261 	if (i < 0)
1262 		j |= NMOT;
1263 	if (vflag)
1264 		j |= VMOT;
1265 	return(j);
1266 }
1267 
1268 
getlg(tchar i)1269 tchar getlg(tchar i)
1270 {
1271 	tchar j, k, pb[NC];
1272 	struct lgtab *lp;
1273 	int c, f, n, lgn;
1274 
1275 	f = fbits(i);
1276 	if (lgtab[f] == NULL)	/* font lacks ligatures */
1277 		return(i);
1278 	c = cbits(i);
1279 	lp = &lgtab[f][c];
1280 	if (lp->from != c || (lp = lp->link) == NULL)
1281 		return(i);
1282 	k = i;
1283 	n = 1;
1284 	lgn = lg == 2 ? 2 : 1000;
1285 	for (;;) {
1286 		j = getch0();
1287 		if (n < sizeof pb)
1288 			pb[n-1] = j;
1289 		c = cbits(j);
1290 		while (lp != NULL && lp->from != c)
1291 			lp = lp->next;
1292 		if (lp == NULL || lp->to == 0) {
1293 			pbbuf[pbp++] = j;
1294 			return(k);
1295 		}
1296 		if (lp->to == -1) {	/* fdeferlig request */
1297 			pb[n < sizeof pb ? n : sizeof pb - 1] = 0;
1298 			pushback(pb);
1299 			return(i);
1300 		}
1301 		k = (i & SFMASK) | lp->to | AUTOLIG;
1302 		if (lp->link == NULL || ++n > lgn)
1303 			return(k);
1304 		lp = lp->link;
1305 	}
1306 }
1307 
1308 int
strlg(int f,int * tp,int n)1309 strlg(int f, int *tp, int n)
1310 {
1311 	struct lgtab	*lp;
1312 	int	i;
1313 
1314 	if (n == 1)
1315 		return tp[0];
1316 	if (lgtab[f] == NULL)
1317 		return 0;
1318 	lp = &lgtab[f][tp[0]];
1319 	if (lp->from != tp[0])
1320 		return 0;
1321 	for (i = 1; i < n; i++) {
1322 		if ((lp = lp->link) == NULL)
1323 			return 0;
1324 		while (lp != NULL && lp->from != tp[i])
1325 			lp = lp->next;
1326 		if (lp == NULL || lp->to == 0)
1327 			return 0;
1328 	}
1329 	return lp->to > 0 ? lp->to : 0;
1330 }
1331 
1332 void
caselg(void)1333 caselg(void)
1334 {
1335 
1336 	lg = 1;
1337 	if (skip(0))
1338 		return;
1339 	lg = hatoi();
1340 }
1341 
1342 static void
addlig(int f,tchar * from,int to)1343 addlig(int f, tchar *from, int to)
1344 {
1345 	int	i, j;
1346 	struct lgtab	*lp;
1347 
1348 	if (from[0] == 0 || from[1] == 0) {
1349 		if (warn & WARN_FONT)
1350 			errprint("short ligature has no effect");
1351 		return;
1352 	}
1353 	if (lgtab[f] == NULL)
1354 		lgtab[f] = calloc(NCHARS, sizeof **lgtab);
1355 	i = cbits(from[0]);
1356 	gchtab[i] |= LGBIT;
1357 	lp = &lgtab[f][i];
1358 	lp->from = i;
1359 	j = 1;
1360 	for (;;) {
1361 		i = cbits(from[j]);
1362 		if (lp->link == NULL) {
1363 			if (from[j+1] != 0) {
1364 				if (warn & WARN_FONT)
1365 					errprint("ligature step missing");
1366 				return;
1367 			}
1368 			lp->link = calloc(1, sizeof *lp->link);
1369 			lp = lp->link;
1370 			lp->from = i;
1371 			lp->to = to;
1372 			break;
1373 		}
1374 		lp = lp->link;
1375 		if (++j >= 4) {
1376 			if (warn & WARN_FONT)
1377 				errprint("ignoring ligature of length >4");
1378 			return;
1379 		}
1380 		while (lp->from != i && lp->next)
1381 			lp = lp->next;
1382 		if (lp->from != i) {
1383 			if (from[j] != 0) {
1384 				if (warn & WARN_FONT)
1385 					errprint("ligature step missing");
1386 				return;
1387 			}
1388 			lp->next = calloc(1, sizeof *lp->next);
1389 			lp = lp->next;
1390 			lp->from = i;
1391 		}
1392 		if (from[j] == 0) {
1393 			lp->to = to;
1394 			break;
1395 		}
1396 	}
1397 	if (to >= 0) {
1398 		if (lgrevtab[f] == NULL)
1399 			lgrevtab[f] = calloc(NCHARS, sizeof **lgrevtab);
1400 		lgrevtab[f][to] = malloc((j+2) * sizeof ***lgrevtab);
1401 		j = 0;
1402 		while ((lgrevtab[f][to][j] = cbits(from[j])))
1403 			j++;
1404 	}
1405 	/*
1406 	 * If the font still contains the charlib substitutes for ff,
1407 	 * Fi, and Fl, hide them. The ".flig" request is intended for
1408 	 * use in combination with expert fonts only.
1409 	 */
1410 	if ((to == LIG_FF || (cbits(from[0]) == 'f' && cbits(from[1]) == 'f' &&
1411 			      cbits(from[2]) == 0)) &&
1412 			fitab[f][LIG_FF-32] != NOCODE)
1413 		if (codetab[f][fitab[f][LIG_FF-32]] < 32)
1414 			fitab[f][LIG_FF-32] = 0;
1415 	if ((to == LIG_FFI || (cbits(from[0]) == 'f' && cbits(from[1]) == 'f' &&
1416 			       cbits(from[2]) == 'i' && cbits(from[3]) == 0)) &&
1417 			fitab[f][LIG_FFI-32] != NOCODE)
1418 		if (codetab[f][fitab[f][LIG_FFI-32]] < 32)
1419 			fitab[f][LIG_FFI-32] = 0;
1420 	if ((to == LIG_FFL || (cbits(from[0]) == 'f' && cbits(from[1]) == 'f' &&
1421 			       cbits(from[2]) == 'l' && cbits(from[3]) == 0)) &&
1422 			fitab[f][LIG_FFL-32] != NOCODE)
1423 		if (codetab[f][fitab[f][LIG_FFL-32]] < 32)
1424 			fitab[f][LIG_FFL-32] = 0;
1425 }
1426 
1427 static void
dellig(int f,tchar * from)1428 dellig(int f, tchar *from)
1429 {
1430 	struct lgtab	*lp, *lq;
1431 	int	i, j;
1432 
1433 	if (from[0] == 0 || from[1] == 0)
1434 		return;
1435 	if (lgtab[f] == NULL)
1436 		return;
1437 	i = cbits(from[0]);
1438 	lp = lq = &lgtab[f][i];
1439 	j = 1;
1440 	for (;;) {
1441 		i = cbits(from[j]);
1442 		if (lp->link == NULL)
1443 			break;
1444 		lq = lp;
1445 		lp = lp->link;
1446 		while (lp->from != i && lp->next) {
1447 			lq = lp;
1448 			lp = lp->next;
1449 		}
1450 		if (lp->from != i)
1451 			break;
1452 		if (from[++j] == 0) {
1453 			if (lq->link == lp)
1454 				lq->link = lp->next;
1455 			else if (lq->next == lp)
1456 				lq->next = lp->next;
1457 			if (lp->link)
1458 				if (warn & WARN_FONT)
1459 					errprint("deleted ligature cuts chain");
1460 			free(lgrevtab[f][lp->to]);
1461 			lgrevtab[f][lp->to] = NULL;
1462 			free(lp);
1463 			break;
1464 		}
1465 	}
1466 }
1467 
1468 void
setlig(int f,int j)1469 setlig(int f, int j)
1470 {
1471 	tchar	from[4], to;
1472 
1473 	free(lgrevtab[f]);
1474 	lgrevtab[f] = NULL;
1475 	free(lgtab[f]);
1476 	lgtab[f] = NULL;
1477 	from[0] = 'f';
1478 	from[2] = from[3] = 0;
1479 	from[1] = 'f';
1480 	to = LIG_FF;
1481 	if (j & LFF)
1482 		addlig(f, from, to);
1483 	from[1] = 'i';
1484 	to = LIG_FI;
1485 	if (j & LFI)
1486 		addlig(f, from, to);
1487 	from[1] = 'l';
1488 	to = LIG_FL;
1489 	if (j & LFL)
1490 		addlig(f, from, to);
1491 	from[1] = 'f';
1492 	from[2] = 'i';
1493 	to = LIG_FFI;
1494 	if (j & LFFI)
1495 		addlig(f, from, to);
1496 	from[2] = 'l';
1497 	to = LIG_FFL;
1498 	if (j & LFFL)
1499 		addlig(f, from, to);
1500 }
1501 
1502 static int
getflig(int f,int mode)1503 getflig(int f, int mode)
1504 {
1505 	int	delete, allnum;
1506 	tchar	from[NC], to;
1507 	int	c, i, j;
1508 	char	number[NC];
1509 
1510 	if (skip(0))
1511 		return 0;
1512 	switch (cbits(c = getch())) {
1513 	case '-':
1514 		c = getch();
1515 		delete = 1;
1516 		break;
1517 	case '+':
1518 		c = getch();
1519 		/*FALLTHRU*/
1520 	default:
1521 		delete = 0;
1522 		break;
1523 	case 0:
1524 		return 0;
1525 	}
1526 	allnum = 1;
1527 	for (i = 0; i < sizeof from - 2; i++) {
1528 		from[i] = c;
1529 		j = cbits(c);
1530 		if (c == 0 || ismot(c) || j == ' ' || j == '\n') {
1531 			from[i] = 0;
1532 			ch = j;
1533 			break;
1534 		}
1535 		if (j < '0' || j > '9')
1536 			allnum = 0;
1537 		c = getch();
1538 	}
1539 	if (mode == 0 && allnum == 1) {	/* backwards compatibility */
1540 		if (skip(0) == 0)
1541 			goto new;
1542 		for (j = 0; j <= i+1; j++)
1543 			number[j] = cbits(from[j]);
1544 		j = strtol(number, NULL, 10);
1545 		setlig(f, j);
1546 		return 0;
1547 	}
1548 	if (delete == 0) {
1549 		if (mode >= 0) {
1550 			if (skip(1))
1551 				return 0;
1552 		new:	to = cbits(getch());
1553 		} else
1554 			to = -1;
1555 		addlig(f, from, to);
1556 	} else
1557 		dellig(f, from);
1558 	return 1;
1559 }
1560 
1561 void
caseflig(int defer)1562 caseflig(int defer)
1563 {
1564 	int	i, j;
1565 
1566 	lgf++;
1567 	if (skip(1))
1568 		return;
1569 	i = getrq(2);
1570 	if ((j = findft(i, 1)) < 0)
1571 		return;
1572 	i = 0;
1573 	while (getflig(j, defer ? -1 : i++) != 0);
1574 }
1575 
1576 void
casefdeferlig(void)1577 casefdeferlig(void)
1578 {
1579 	caseflig(1);
1580 }
1581 
1582 void
casefp(int spec)1583 casefp(int spec)
1584 {
1585 	register int i, j;
1586 	char *file, *supply;
1587 
1588 	lgf++;
1589 	skip(0);
1590 	if ((i = xflag ? hatoi() : cbits(getch()) - '0') < 0 || i > 255)
1591 	bad:	errprint("fp: bad font position %d", i);
1592 	else if (skip(0) || !(j = getrq(3)))
1593 		errprint("fp: no font name");
1594 	else {
1595 		if (skip(0) || !getname()) {
1596 			if (i == 0)
1597 				goto bad;
1598 			setfp(i, j, 0);
1599 		} else {		/* 3rd argument = filename */
1600 			size_t l;
1601 			l = strlen(nextf) + 1;
1602 			file = malloc(l);
1603 			n_strcpy(file, nextf, l);
1604 			if (!skip(0) && getname()) {
1605 				l = strlen(nextf) + 1;
1606 				supply = malloc(l);
1607 				n_strcpy(supply, nextf, l);
1608 			} else
1609 				supply = NULL;
1610 			if (loadafm(i?i:-1, j, file, supply, 0, spec) == 0) {
1611 				if (i == 0) {
1612 					if (warn & WARN_FONT)
1613 						errprint("fp: cannot mount %s",
1614 								file);
1615 				} else
1616 					setfp(i, j, file);
1617 			}
1618 			free(file);
1619 			free(supply);
1620 		}
1621 	}
1622 }
1623 
1624 void
casefps(void)1625 casefps(void)
1626 {
1627 	const struct {
1628 		enum spec	spec;
1629 		const char	*name;
1630 	} tab[] = {
1631 		{ SPEC_MATH,	"math" },
1632 		{ SPEC_GREEK,	"greek" },
1633 		{ SPEC_PUNCT,	"punct" },
1634 		{ SPEC_LARGE,	"large" },
1635 		{ SPEC_S1,	"S1" },
1636 		{ SPEC_S,	"S" },
1637 		{ SPEC_NONE,	NULL }
1638 	};
1639 	char	name[NC];
1640 	int	c = 0, i;
1641 	enum spec	s = SPEC_NONE;
1642 
1643 	if (skip(1))
1644 		return;
1645 	do {
1646 		for (i = 0; i < sizeof name - 2; i++) {
1647 			if ((c = getach()) == 0 || c == ':' || c == ',')
1648 				break;
1649 			name[i] = c;
1650 		}
1651 		name[i] = 0;
1652 		for (i = 0; tab[i].name; i++)
1653 			if (strcmp(tab[i].name, name) == 0) {
1654 				s |= tab[i].spec;
1655 				break;
1656 			}
1657 		if (tab[i].name == NULL)
1658 			errprint("fps: unknown special set %s", name);
1659 	} while (c);
1660 	casefp(s);
1661 }
1662 
1663 int
setfp(int pos,int f,char * truename)1664 setfp(int pos, int f, char *truename)	/* mount font f at position pos[0...nfonts] */
1665 {
1666 	char longname[4096], *shortname, *ap;
1667 	char *fpout;
1668 	int i, nw;
1669 
1670 	zapwcache(0);
1671 	if (truename)
1672 		shortname = truename;
1673 	else
1674 		shortname = macname(f);
1675 	shortname = mapft(shortname);
1676 	snprintf(longname, sizeof longname, "%s/dev%s/%s",
1677 			fontfile, devname, shortname);
1678 	if ((fpout = readfont(longname, &dev, warn & WARN_FONT)) == NULL)
1679 		return(-1);
1680 	if (pos >= Nfont)
1681 		growfonts(pos+1);
1682 	if (pos > nfonts)
1683 		nfonts = pos;
1684 	fontbase[pos] = (struct Font *)fpout;
1685 	if ((ap = strstr(fontbase[pos]->namefont, ".afm")) != NULL) {
1686 		*ap = 0;
1687 		if (ap == &fontbase[pos]->namefont[1])
1688 			f &= BYTEMASK;
1689 		loadafm(pos, f, fontbase[pos]->namefont, NULL, 1, SPEC_NONE);
1690 		free(fpout);
1691 	} else {
1692 		nw = fontbase[pos]->nwfont & BYTEMASK;
1693 		makefont(pos, &((char *)fontbase[pos])[sizeof(struct Font)],
1694 			&((char *)fontbase[pos])[sizeof(struct Font) + nw],
1695 			&((char *)fontbase[pos])[sizeof(struct Font) + 2*nw],
1696 			&((char *)fontbase[pos])[sizeof(struct Font) + 3*nw],
1697 			nw);
1698 		setlig(pos, fontbase[pos]->ligfont);
1699 	}
1700 	if (pos == smnt) {
1701 		smnt = 0;
1702 		sbold = 0;
1703 	}
1704 	if ((fontlab[pos] = f) == 'S')
1705 		smnt = pos;
1706 	bdtab[pos] = cstab[pos] = ccstab[pos] = 0;
1707 	zoomtab[pos] = 0;
1708 	fallbacktab[pos] = NULL;
1709 	free(lhangtab[pos]);
1710 	lhangtab[pos] = NULL;
1711 	free(rhangtab[pos]);
1712 	rhangtab[pos] = NULL;
1713 	memset(&tracktab[pos], 0, sizeof tracktab[pos]);
1714 	for (i = 0; i < NCHARS; i++)
1715 		ftrtab[pos][i] = i;
1716 	kzap(pos);
1717 		/* if there is a directory, no place to store its name. */
1718 		/* if position isn't zero, no place to store its value. */
1719 		/* only time a FONTPOS is pushed back is if it's a */
1720 		/* standard font on position 0 (i.e., mounted implicitly. */
1721 		/* there's a bug here:  if there are several input lines */
1722 		/* that look like .ft XX in short successtion, the output */
1723 		/* will all be in the last one because the "x font ..." */
1724 		/* comes out too soon.  pushing back FONTPOS doesn't work */
1725 		/* with .ft commands because input is flushed after .xx cmds */
1726 	if (realpage && ap == NULL)
1727 		ptfpcmd(pos, shortname, NULL, 0);
1728 	if (pos == 0)
1729 		ch = (tchar) FONTPOS | (tchar) f << 22;
1730 	return(pos);
1731 }
1732 
1733 int
nextfp(void)1734 nextfp(void)
1735 {
1736 	int	i;
1737 
1738 	for (i = 1; i <= nfonts; i++)
1739 		if (fontbase[i] == NULL)
1740 			return i;
1741 	if (i <= 255)
1742 		return i;
1743 	return 0;
1744 }
1745 
1746 void
casecs(void)1747 casecs(void)
1748 {
1749 	register int i, j;
1750 
1751 	noscale++;
1752 	if (skip(1))
1753 		goto rtn;
1754 	if (!(i = getrq(2)))
1755 		goto rtn;
1756 	if ((i = findft(i, 1)) < 0)
1757 		goto rtn;
1758 	skip(0);
1759 	cstab[i] = hatoi();
1760 	skip(0);
1761 	j = hatoi();
1762 	if (nonumb)
1763 		ccstab[i] = 0;
1764 	else
1765 		ccstab[i] = findps(j);
1766 rtn:
1767 	zapwcache(0);
1768 	noscale = 0;
1769 }
1770 
1771 void
casebd(void)1772 casebd(void)
1773 {
1774 	register int i, j = 0, k;
1775 
1776 	zapwcache(0);
1777 	k = 0;
1778 bd0:
1779 	if (skip(1) || !(i = getrq(2)) || (j = findft(i, 1)) == -1) {
1780 		if (k)
1781 			goto bd1;
1782 		else
1783 			return;
1784 	}
1785 	if (j == smnt) {
1786 		k = smnt;
1787 		goto bd0;
1788 	}
1789 	if (k) {
1790 		sbold = j;
1791 		j = k;
1792 	}
1793 bd1:
1794 	skip(0);
1795 	noscale++;
1796 	bdtab[j] = hatoi();
1797 	noscale = 0;
1798 }
1799 
1800 void
casevs(void)1801 casevs(void)
1802 {
1803 	register int i;
1804 
1805 	skip(0);
1806 	vflag++;
1807 	dfact = INCH; /* default scaling is points! */
1808 	dfactd = 72;
1809 	res = VERT;
1810 	i = inumb(&lss);
1811 	if (nonumb)
1812 		i = lss1;
1813 	if (xflag && i < 0) {
1814 		if (warn & WARN_RANGE)
1815 			errprint("negative vertical spacing ignored");
1816 		i = lss1;
1817 	}
1818 	if (i < VERT)
1819 		i = VERT;
1820 	lss1 = lss;
1821 	lss = i;
1822 }
1823 
1824 void
casess(int flg)1825 casess(int flg)
1826 {
1827 	register int i, j;
1828 
1829 	noscale++;
1830 	if (skip(flg == 0))
1831 		minsps = minspsz = 0;
1832 	else if ((i = hatoi()) != 0 && !nonumb) {
1833 		if (xflag && flg == 0 && !skip(0)) {
1834 			j = hatoi();
1835 			if (!nonumb) {
1836 				sesspsz = j & 0177;
1837 				spacesz = sesspsz;
1838 				zapwcache(1);
1839 				ses = width(' ' | chbits);
1840 			}
1841 		}
1842 		if (flg) {
1843 			j = spacesz;
1844 			minspsz = i & 0177;
1845 			spacesz = minspsz;
1846 			zapwcache(1);
1847 			minsps = width(' ' | chbits);
1848 			spacesz = j;
1849 			zapwcache(0);
1850 			sps = width(' ' | chbits);
1851 		} else {
1852 			spacesz = i & 0177;
1853 			zapwcache(0);
1854 			sps = width(' ' | chbits);
1855 			if (minspsz > spacesz)
1856 				minsps = minspsz = 0;
1857 		}
1858 	}
1859 	noscale = 0;
1860 }
1861 
1862 void
caseminss(void)1863 caseminss(void)
1864 {
1865 	casess(1);
1866 }
1867 
1868 void
caseletadj(void)1869 caseletadj(void)
1870 {
1871 	int	s, n, x, l, h;
1872 
1873 	dfact = LAFACT / 100;
1874 	if (skip(0) || (n = hatoi()) == 0) {
1875 		letspsz = 0;
1876 		letsps = 0;
1877 		lspmin = 0;
1878 		lspmax = 0;
1879 		lshmin = 0;
1880 		lshmax = 0;
1881 		goto ret;
1882 	}
1883 	if (skip(1))
1884 		goto ret;
1885 	dfact = LAFACT / 100;
1886 	l = hatoi();
1887 	if (skip(1))
1888 		goto ret;
1889 	noscale++;
1890 	s = hatoi();
1891 	noscale--;
1892 	if (skip(1))
1893 		goto ret;
1894 	dfact = LAFACT / 100;
1895 	x = hatoi();
1896 	if (skip(1))
1897 		goto ret;
1898 	dfact = LAFACT / 100;
1899 	h = hatoi();
1900 	letspsz = s;
1901 	lspmin = LAFACT - n;
1902 	lspmax = x - LAFACT;
1903 	lshmin = LAFACT - l;
1904 	lshmax = h - LAFACT;
1905 	s = spacesz;
1906 	spacesz = letspsz;
1907 	zapwcache(1);
1908 	letsps = width(' ' | chbits);
1909 	spacesz = s;
1910 	zapwcache(1);
1911 	sps = width(' ' | chbits);
1912 	zapwcache(1);
1913 ret:
1914 	dfact = 1;
1915 }
1916 
1917 void
casefspacewidth(void)1918 casefspacewidth(void)
1919 {
1920 	int	f, n, i;
1921 
1922 	lgf++;
1923 	if (skip(1))
1924 		return;
1925 	i = getrq(2);
1926 	if ((f = findft(i, 1)) < 0)
1927 		return;
1928 	if (skip(0)) {
1929 		fontbase[f]->cspacewidth = -1;
1930 		fontab[f][0] = fontbase[f]->spacewidth;
1931 	} else {
1932 		noscale++;
1933 		n = hatoi();
1934 		noscale--;
1935 		unitsPerEm = 1000;
1936 		if (n >= 0)
1937 			fontbase[f]->cspacewidth = fontab[f][0] = _unitconv(n);
1938 		else if (warn & WARN_RANGE)
1939 			errprint("ignoring negative space width %d", n);
1940 	}
1941 	zapwcache(1);
1942 }
1943 
1944 void
casespacewidth(void)1945 casespacewidth(void)
1946 {
1947 	noscale++;
1948 	spacewidth = skip(0) || hatoi();
1949 	noscale--;
1950 }
1951 
xlss(void)1952 tchar xlss(void)
1953 {
1954 	/* stores \x'...' into
1955 	 * two successive tchars.
1956 	 * the first contains HX, the second the value,
1957 	 * encoded as a vertical motion.
1958 	 * decoding is done in n2.c by pchar().
1959 	 */
1960 	int	i;
1961 
1962 	getch();
1963 	dfact = lss;
1964 	i = quant(hatoi(), VERT);
1965 	dfact = 1;
1966 	getch();
1967 	if (i >= 0)
1968 		pbbuf[pbp++] = MOT | VMOT | sabsmot(i);
1969 	else
1970 		pbbuf[pbp++] = MOT | VMOT | NMOT | sabsmot(-i);
1971 	return(HX);
1972 }
1973 
1974 struct afmtab **afmtab;
1975 int nafm;
1976 
1977 char *
onefont(char * prefix,char * file,char * type)1978 onefont(char *prefix, char *file, char *type)
1979 {
1980 	char	*path, *fp, *tp;
1981 	size_t	l;
1982 
1983 	l = strlen(prefix) + strlen(file) + 2;
1984 	path = malloc(l);
1985 	n_strcpy(path, prefix, l);
1986 	n_strcat(path, "/", l);
1987 	n_strcat(path, file, l);
1988 	if (type) {
1989 		for (fp = file; *fp; fp++);
1990 		for (tp = type; *tp; tp++);
1991 		while (tp >= type && fp >= file && *fp-- == *tp--);
1992 		if (tp >= type) {
1993 			l = strlen(path) + strlen(type) + 2;
1994 			tp = malloc(l);
1995 			n_strcpy(tp, path, l);
1996 			n_strcat(tp, ".", l);
1997 			n_strcat(tp, type, l);
1998 			free(path);
1999 			path = tp;
2000 		}
2001 	}
2002 	return path;
2003 }
2004 
2005 static char *
getfontpath(char * file,char * type)2006 getfontpath(char *file, char *type)
2007 {
2008 	char	*path, *troffonts, *tp, *tq, c;
2009 	size_t	l;
2010 
2011 	if ((troffonts = getenv("TROFFONTS")) != NULL) {
2012 		l = strlen(troffonts) + 1;
2013 		tp = malloc(l);
2014 		n_strcpy(tp, troffonts, l);
2015 		troffonts = tp;
2016 		do {
2017 			for (tq = tp; *tq && *tq != ':'; tq++);
2018 			c = *tq;
2019 			*tq = 0;
2020 			path = onefont(tp, file, type);
2021 			if (access(path, 0) == 0) {
2022 				free(troffonts);
2023 				return path;
2024 			}
2025 			free(path);
2026 			tp = &tq[1];
2027 		} while (c);
2028 		free(troffonts);
2029 	}
2030 	l = strlen(fontfile) + strlen(devname) + 10;
2031 	tp = malloc(l);
2032 	snprintf(tp, l, "%s/dev%s", fontfile, devname);
2033 	path = onefont(tp, file, type);
2034 	free(tp);
2035 	return path;
2036 }
2037 
2038 static void
checkenminus(int f)2039 checkenminus(int f)
2040 {
2041 	/*
2042 	 * A fix for a very special case: If the font supplies punctuation
2043 	 * characters but is not S1, only one of \- and \(en is present
2044 	 * since the PostScript character "endash" is mapped to both of
2045 	 * them.
2046 	 */
2047 	enum spec	spec;
2048 	int	i;
2049 
2050 	if (afmtab == NULL || (i = fontbase[f]->afmpos - 1) < 0)
2051 		return;
2052 	if (c_endash == 0 || c_minus == 0)
2053 		specnames();
2054 	spec = afmtab[i]->spec;
2055 	if ((spec&(SPEC_PUNCT|SPEC_S1)) == SPEC_PUNCT) {
2056 		if (fitab[f][c_endash-32] == 0 && ftrtab[f][c_minus-32])
2057 			ftrtab[f][c_endash] = c_minus;
2058 		else if (fitab[f][c_endash-32] && ftrtab[f][c_minus-32] != 0)
2059 			ftrtab[f][c_minus] = c_endash;
2060 	}
2061 }
2062 
2063 int
loadafm(int nf,int rq,char * file,char * supply,int required,enum spec spec)2064 loadafm(int nf, int rq, char *file, char *supply, int required, enum spec spec)
2065 {
2066 	struct stat	st;
2067 	int	fd;
2068 	char	*path, *contents;
2069 	struct afmtab	*a;
2070 	int	i, have = 0;
2071 	struct namecache	*np;
2072 	size_t	l;
2073 
2074 	zapwcache(0);
2075 	if (nf < 0)
2076 		nf = nextfp();
2077 	path = getfontpath(file, "afm");
2078 	if (access(path, 0) < 0) {
2079 		path = getfontpath(file, "otf");
2080 		if (access(path, 0) < 0)
2081 			path = getfontpath(file, "ttf");
2082 	}
2083 	if (dev.allpunct)
2084 		spec |= SPEC_PUNCT;
2085 	a = calloc(1, sizeof *a);
2086 	for (i = 0; i < nafm; i++)
2087 		if (strcmp(afmtab[i]->path, path) == 0 &&
2088 				afmtab[i]->spec == spec) {
2089 			*a = *afmtab[i];
2090 			have = 1;
2091 			break;
2092 		}
2093 	a->path = path;
2094 	l = strlen(file) + 1;
2095 	a->file = malloc(l);
2096 	n_strcpy(a->file, file, l);
2097 	a->spec = spec;
2098 	a->rq = rq;
2099 	a->Font.namefont[0] = rq&0377;
2100 	a->Font.namefont[1] = (rq>>8)&0377;
2101 	snprintf(a->Font.intname, sizeof(a->Font.intname), "%d", nf);
2102 	if (have)
2103 		goto done;
2104 	if ((fd = open(path, O_RDONLY)) < 0) {
2105 		if (required)
2106 			errprint("Can't open %s", path);
2107 		free(a->file);
2108 		free(a);
2109 		free(path);
2110 		return 0;
2111 	}
2112 	if (fstat(fd, &st) < 0) {
2113 		errprint("Can't stat %s", path);
2114 		free(a->file);
2115 		free(a);
2116 		free(path);
2117 		return -1;
2118 	}
2119 	contents = malloc(st.st_size + 1);
2120 	if (read(fd, contents, st.st_size) != st.st_size) {
2121 		errprint("Can't read %s", path);
2122 		free(a->file);
2123 		free(a);
2124 		free(path);
2125 		free(contents);
2126 		return -1;
2127 	}
2128 	contents[st.st_size] = 0;
2129 	close(fd);
2130 	if (afmget(a, contents, st.st_size) < 0) {
2131 		free(path);
2132 		free(contents);
2133 		return -1;
2134 	}
2135 	free(contents);
2136 	morechars(a->nchars+32+1+128-32+nchtab+32+nchtab+128+psmaxcode+1);
2137 done:	afmtab = realloc(afmtab, (nafm+1) * sizeof *afmtab);
2138 	afmtab[nafm] = a;
2139 	if (nf >= Nfont)
2140 		growfonts(nf+1);
2141 	a->Font.afmpos = nafm+1;
2142 	if ((np = afmnamelook(a, "space")) != NULL)
2143 		a->Font.spacewidth = a->fontab[np->afpos];
2144 	else
2145 		a->Font.spacewidth = a->fontab[0];
2146 	a->Font.cspacewidth = -1;
2147 	fontbase[nf] = &afmtab[nafm]->Font;
2148 	fontlab[nf] = rq;
2149 	free(fontab[nf]);
2150 	free(kerntab[nf]);
2151 	free(codetab[nf]);
2152 	free(fitab[nf]);
2153 	fontab[nf] = malloc(a->nchars * sizeof *fontab[nf]);
2154 	kerntab[nf] = malloc(a->nchars * sizeof *kerntab[nf]);
2155 	codetab[nf] = malloc(a->nchars * sizeof *codetab[nf]);
2156 	fitab[nf] = calloc(NCHARS, sizeof *fitab[nf]);
2157 	memcpy(fontab[nf], a->fontab, a->nchars * sizeof *fontab[nf]);
2158 	memcpy(kerntab[nf], a->kerntab, a->nchars * sizeof *kerntab[nf]);
2159 	memcpy(codetab[nf], a->codetab, a->nchars * sizeof *codetab[nf]);
2160 	memcpy(fitab[nf], a->fitab, a->fichars * sizeof *fitab[nf]);
2161 	bdtab[nf] = cstab[nf] = ccstab[nf] = 0;
2162 	zoomtab[nf] = 0;
2163 	fallbacktab[nf] = NULL;
2164 	free(lhangtab[nf]);
2165 	lhangtab[nf] = NULL;
2166 	free(rhangtab[nf]);
2167 	rhangtab[nf] = NULL;
2168 	memset(&tracktab[nf], 0, sizeof tracktab[nf]);
2169 	setlig(nf, a->Font.ligfont);
2170 	for (i = 0; i < NCHARS; i++)
2171 		ftrtab[nf][i] = i;
2172 	kzap(nf);
2173 	nafm++;
2174 	if (nf > nfonts)
2175 		nfonts = nf;
2176 	if (supply) {
2177 		char	*data;
2178 		if (strcmp(supply, "pfb") == 0 || strcmp(supply, "pfa") == 0 ||
2179 				strcmp(supply, "t42") == 0 ||
2180 				strcmp(supply, "otf") == 0 ||
2181 				strcmp(supply, "ttf") == 0)
2182 			data = getfontpath(file, supply);
2183 		else
2184 			data = getfontpath(supply, NULL);
2185 		a->supply = afmencodepath(data);
2186 		free(data);
2187 		if (realpage)
2188 			ptsupplyfont(a->fontname, a->supply);
2189 	}
2190 	checkenminus(nf);
2191 	if (realpage)
2192 		ptfpcmd(nf, macname(fontlab[nf]), a->path, (int)a->spec);
2193 	return 1;
2194 }
2195 
2196 int
tracknum(void)2197 tracknum(void)
2198 {
2199 	skip(1);
2200 	dfact = INCH;
2201 	dfactd = 72;
2202 	res = VERT;
2203 	return inumb(NULL);
2204 }
2205 
2206 void
casetrack(void)2207 casetrack(void)
2208 {
2209 	int	i, j, s1, n1, s2, n2;
2210 
2211 	if (skip(1))
2212 		return;
2213 	i = getrq(2);
2214 	if ((j = findft(i, 1)) < 0)
2215 		return;
2216 	s1 = tracknum();
2217 	if (!nonumb) {
2218 		n1 = tracknum();
2219 		if (!nonumb) {
2220 			s2 = tracknum();
2221 			if (!nonumb) {
2222 				n2 = tracknum();
2223 				if (!nonumb) {
2224 					tracktab[j].s1 = s1;
2225 					tracktab[j].n1 = n1;
2226 					tracktab[j].s2 = s2;
2227 					tracktab[j].n2 = n2;
2228 					zapwcache(0);
2229 				}
2230 			}
2231 		}
2232 	}
2233 }
2234 
2235 void
casefallback(void)2236 casefallback(void)
2237 {
2238 	int	*fb = NULL;
2239 	int	i, j, n = 0;
2240 
2241 	if (skip(1))
2242 		return;
2243 	i = getrq(2);
2244 	if ((j = findft(i, 1)) < 0)
2245 		return;
2246 	do {
2247 		skip(0);
2248 		i = getrq(2);
2249 		fb = realloc(fb, (n+2) * sizeof *fb);
2250 		fb[n++] = i;
2251 	} while (i);
2252 	fallbacktab[j] = fb;
2253 }
2254 
2255 void
casehidechar(void)2256 casehidechar(void)
2257 {
2258 	int	savfont = font, savfont1 = font1;
2259 	int	i, j;
2260 	tchar	k;
2261 
2262 	if (skip(1))
2263 		return;
2264 	i = getrq(2);
2265 	if ((j = findft(i, 1)) < 0)
2266 		return;
2267 	font = font1 = j;
2268 	mchbits();
2269 	while ((i = cbits(k = getch())) != '\n') {
2270 		if (fbits(k) != j || ismot(k) || i == ' ')
2271 			continue;
2272 		if (i >= nchtab + 128-32 && afmtab &&
2273 				fontbase[j]->afmpos - 1 >= 0)
2274 			i -= nchtab + 128;
2275 		fitab[j][i - 32] = 0;
2276 	}
2277 	font = savfont;
2278 	font1 = savfont1;
2279 	mchbits();
2280 	zapwcache(0);
2281 }
2282 
2283 void
casefzoom(void)2284 casefzoom(void)
2285 {
2286 	int	i, j;
2287 	float	f;
2288 
2289 	if (skip(1))
2290 		return;
2291 	i = getrq(2);
2292 	if ((j = findft(i, 1)) < 0)
2293 		return;
2294 	skip(1);
2295 	f = atof();
2296 	if (!nonumb && f >= 0) {
2297 		zoomtab[j] = f;
2298 		zapwcache(0);
2299 		if (realpage && j == xfont && !ascii)
2300 			ptps();
2301 	}
2302 }
2303 
2304 double
getfzoom(void)2305 getfzoom(void)
2306 {
2307 	return zoomtab[font];
2308 }
2309 
2310 void
casekern(void)2311 casekern(void)
2312 {
2313 	kern = skip(0) || hatoi() ? 1 : 0;
2314 }
2315 
2316 void
casefkern(void)2317 casefkern(void)
2318 {
2319 	int	f, i, j;
2320 
2321 	lgf++;
2322 	if (skip(1))
2323 		return;
2324 	i = getrq(2);
2325 	if ((f = findft(i, 1)) < 0)
2326 		return;
2327 	if (skip(0))
2328 		fontbase[f]->kernfont = 0;
2329 	else {
2330 		j = hatoi();
2331 		if (!nonumb)
2332 			fontbase[f]->kernfont = j ? j : -1;
2333 	}
2334 }
2335 
2336 static void
setpapersize(int setmedia)2337 setpapersize(int setmedia)
2338 {
2339 	const struct {
2340 		char	*name;
2341 		int	width;
2342 		int	heigth;
2343 	} papersizes[] = {
2344 		{ "executive",	 518,	 756 },
2345 		{ "letter",	 612,	 792 },
2346 		{ "legal",	 612,	 992 },
2347 		{ "ledger",	1224,	 792 },
2348 		{ "tabloid",	 792,	1224 },
2349 		{ "a0",		2384,	3370 },
2350 		{ "a1",		1684,	2384 },
2351 		{ "a2",		1191,	1684 },
2352 		{ "a3",		 842,	1191 },
2353 		{ "a4",		 595,	 842 },
2354 		{ "a5",		 420,	 595 },
2355 		{ "a6",		 298,	 420 },
2356 		{ "a7",		 210,	 298 },
2357 		{ "a8",		 147,	 210 },
2358 		{ "a9",		 105,	 147 },
2359 		{ "a10",	  74,	 105 },
2360 		{ "b0",		2835,	4008 },
2361 		{ "b1",		2004,	2835 },
2362 		{ "b2",		1417,	2004 },
2363 		{ "b3",		1000,	1417 },
2364 		{ "b4",		 709,	1000 },
2365 		{ "b5",		 499,	 709 },
2366 		{ "b6",		 354,	 499 },
2367 		{ "b7",		 249,	 354 },
2368 		{ "b8",		 176,	 249 },
2369 		{ "b9",		 125,	 176 },
2370 		{ "b10",	  87,	 125 },
2371 		{ "c0",		2599,	3677 },
2372 		{ "c1",		1837,	2599 },
2373 		{ "c2",		1298,	1837 },
2374 		{ "c3",		 918,	1298 },
2375 		{ "c4",		 649,	 918 },
2376 		{ "c5",		 459,	 649 },
2377 		{ "c6",		 323,	 459 },
2378 		{ "c7",		 230,	 323 },
2379 		{ "c8",		 162,	 230 },
2380 		{ NULL,		   0,	   0 }
2381 	};
2382 	int	c;
2383 	int	x = 0, y = 0, n;
2384 	char	buf[NC];
2385 
2386 	lgf++;
2387 	if (skip(1))
2388 		return;
2389 	c = cbits(ch);
2390 	if (isdigit(c) || c == '(') {
2391 		x = hatoi();
2392 		if (!nonumb) {
2393 			skip(1);
2394 			y = hatoi();
2395 		}
2396 		if (nonumb || x == 0 || y == 0)
2397 			return;
2398 	} else {
2399 		n = 0;
2400 		do {
2401 			c = getach();
2402 			if (n+1 < sizeof buf)
2403 				buf[n++] = c;
2404 		} while (c);
2405 		buf[n] = 0;
2406 		for (n = 0; papersizes[n].name != NULL; n++)
2407 			if (strcmp(buf, papersizes[n].name) == 0) {
2408 				x = papersizes[n].width * INCH / 72;
2409 				y = papersizes[n].heigth * INCH / 72;
2410 				break;
2411 			}
2412 		if (x == 0 || y == 0) {
2413 			errprint("Unknown paper size %s", buf);
2414 			return;
2415 		}
2416 	}
2417 	pl = defaultpl = y;
2418 	if (numtab[NL].val > pl) {
2419 		numtab[NL].val = pl;
2420 		prwatchn(&numtab[NL]);
2421 	}
2422 	po = x > 6 * PO ? PO : x / 8;
2423 	ll = ll1 = lt = lt1 = x - 2 * po;
2424 	setnel();
2425 	mediasize.val[2] = x;
2426 	mediasize.val[3] = y;
2427 	mediasize.flag |= 1;
2428 	if (setmedia)
2429 		mediasize.flag |= 2;
2430 	if (realpage)
2431 		ptpapersize();
2432 }
2433 
2434 void
casepapersize(void)2435 casepapersize(void)
2436 {
2437 	setpapersize(0);
2438 }
2439 
2440 void
casemediasize(void)2441 casemediasize(void)
2442 {
2443 	setpapersize(1);
2444 }
2445 
2446 static void
cutat(struct box * bp)2447 cutat(struct box *bp)
2448 {
2449 	int	c[4], i;
2450 
2451 	for (i = 0; i < 4; i++) {
2452 		if (skip(1))
2453 			return;
2454 		dfact = INCH;
2455 		dfactd = 72;
2456 		c[i] = inumb(NULL);
2457 		if (nonumb)
2458 			return;
2459 	}
2460 	for (i = 0; i < 4; i++)
2461 		bp->val[i] = c[i];
2462 	bp->flag |= 1;
2463 	if (realpage)
2464 		ptcut();
2465 }
2466 
2467 void
casetrimat(void)2468 casetrimat(void)
2469 {
2470 	cutat(&trimat);
2471 }
2472 
2473 void
casebleedat(void)2474 casebleedat(void)
2475 {
2476 	cutat(&bleedat);
2477 }
2478 
2479 void
casecropat(void)2480 casecropat(void)
2481 {
2482 	cutat(&cropat);
2483 }
2484 
2485 void
caselhang(void)2486 caselhang(void)
2487 {
2488 	kernsingle(lhangtab);
2489 }
2490 
2491 void
caserhang(void)2492 caserhang(void)
2493 {
2494 	kernsingle(rhangtab);
2495 }
2496 
2497 void
casekernpair(void)2498 casekernpair(void)
2499 {
2500 	int	savfont = font, savfont1 = font1;
2501 	int	f, g, i, j, n;
2502 	tchar	c, d, *cp = NULL, *dp = NULL;
2503 	int	a = 0, b = 0;
2504 
2505 	lgf++;
2506 	if (skip(1))
2507 		return;
2508 	i = getrq(2);
2509 	if ((f = findft(i, 1)) < 0)
2510 		return;
2511 	font = font1 = f;
2512 	mchbits();
2513 	if (skip(1))
2514 		goto done;
2515 	while ((j = cbits(c = getch())) > ' ' || j == UNPAD) {
2516 		if (fbits(c) != f) {
2517 			if (warn & WARN_CHAR)
2518 				errprint("glyph %C not in font %s",
2519 					c, macname(i));
2520 			continue;
2521 		}
2522 		cp = realloc(cp, ++a * sizeof *cp);
2523 		cp[a-1] = c;
2524 	}
2525 	if (a == 0 || skip(1))
2526 		goto done;
2527 	i = getrq(2);
2528 	if ((g = findft(i, 1)) < 0)
2529 		goto done;
2530 	font = font1 = g;
2531 	mchbits();
2532 	if (skip(1))
2533 		goto done;
2534 	while ((j = cbits(c = getch())) > ' ' || j == UNPAD) {
2535 		if (fbits(c) != g) {
2536 			if (warn & WARN_CHAR)
2537 				errprint("glyph %C not in font %s",
2538 					c, macname(i));
2539 			continue;
2540 		}
2541 		dp = realloc(dp, ++b * sizeof *dp);
2542 		dp[b-1] = c;
2543 	}
2544 	if (b == 0 || skip(1))
2545 		goto done;
2546 	noscale++;
2547 	n = hatoi();
2548 	noscale--;
2549 	unitsPerEm = 1000;
2550 	n = _unitconv(n);
2551 	for (i = 0; i < a; i++)
2552 		for (j = 0; j < b; j++) {
2553 			if ((c = cbits(cp[i])) == 0)
2554 				continue;
2555 			if (c == UNPAD)
2556 				c = ' ';
2557 			setfbits(c, f);
2558 			if ((d = cbits(dp[j])) == 0)
2559 				continue;
2560 			if (d == UNPAD)
2561 				d = ' ';
2562 			setfbits(d, g);
2563 			kadd(c, d, n);
2564 		}
2565 done:
2566 	free(cp);
2567 	free(dp);
2568 	font = savfont;
2569 	font1 = savfont1;
2570 	mchbits();
2571 }
2572 
2573 static void
kernsingle(int ** tp)2574 kernsingle(int **tp)
2575 {
2576 	int     savfont = font, savfont1 = font1;
2577 	int	f, i, j, n;
2578 	int	twice = 0;
2579 	tchar	c, *cp = NULL;
2580 	int	a;
2581 
2582 	lgf++;
2583 	if (skip(1))
2584 		return;
2585 	i = getrq(2);
2586 	if ((f = findft(i, 1)) < 0)
2587 		return;
2588 	font = font1 = f;
2589 	mchbits();
2590 	while (!skip(twice++ == 0)) {
2591 		a = 0;
2592 		while ((j = cbits(c = getch())) > ' ') {
2593 			if (fbits(c) != f) {
2594 				if (warn & WARN_CHAR)
2595 					errprint("glyph %C not in font %s",
2596 						c, macname(i));
2597 				continue;
2598 			}
2599 			cp = realloc(cp, ++a * sizeof *cp);
2600 			cp[a-1] = c;
2601 		}
2602 		if (skip(1))
2603 			break;
2604 		noscale++;
2605 		n = hatoi();
2606 		noscale--;
2607 		if (tp[f] == NULL)
2608 			tp[f] = calloc(NCHARS, sizeof *tp);
2609 		unitsPerEm = 1000;
2610 		n = _unitconv(n);
2611 		for (j = 0; j < a; j++)
2612 			tp[f][cbits(cp[j])] = n;
2613 	}
2614 	free(cp);
2615 	font = savfont;
2616 	font1 = savfont1;
2617 	mchbits();
2618 }
2619 
2620 void
casekernafter(void)2621 casekernafter(void)
2622 {
2623 	kernsingle(kernafter);
2624 }
2625 
2626 void
casekernbefore(void)2627 casekernbefore(void)
2628 {
2629 	kernsingle(kernbefore);
2630 }
2631 
2632 void
caseftr(void)2633 caseftr(void)
2634 {
2635 	int	savfont = font, savfont1 = font1;
2636 	int	f, i, j;
2637 	tchar	k;
2638 
2639 	lgf++;
2640 	if (skip(1))
2641 		return;
2642 	i = getrq(2);
2643 	if ((f = findft(i, 1)) < 0)
2644 		return;
2645 	font = font1 = f;
2646 	mchbits();
2647 	if (skip(1))
2648 		goto done;
2649 	while ((i = cbits(k=getch())) != '\n') {
2650 		if (ismot(k))
2651 			goto done;
2652 		if (ismot(k = getch()))
2653 			goto done;
2654 		if ((j = cbits(k)) == '\n')
2655 			j = ' ';
2656 		ftrtab[f][i] = j;
2657 	}
2658 done:
2659 	checkenminus(f);
2660 	font = savfont;
2661 	font1 = savfont1;
2662 	mchbits();
2663 }
2664 
2665 static int
getfeature(struct afmtab * a,int f)2666 getfeature(struct afmtab *a, int f)
2667 {
2668 	char	name[NC];
2669 	int	ch1, ch2, c, i, j, minus;
2670 	struct feature	*fp;
2671 
2672 	if (skip(0))
2673 		return 0;
2674 	switch (c = getach()) {
2675 	case '-':
2676 		c = getach();
2677 		minus = 1;
2678 		break;
2679 	case '+':
2680 		c = getach();
2681 		/*FALLTHRU*/
2682 	default:
2683 		minus = 0;
2684 		break;
2685 	case 0:
2686 		return 0;
2687 	}
2688 	for (i = 0; i < sizeof name - 2; i++) {
2689 		name[i] = c;
2690 		if ((c = getach()) == 0)
2691 			break;
2692 	}
2693 	name[i+1] = 0;
2694 	for (i = 0; (fp = a->features[i]); i++)
2695 		if (strcmp(fp->name, name) == 0) {
2696 			for (j = 0; j < fp->npairs; j++) {
2697 				ch1 = fp->pairs[j].ch1;
2698 				ch2 = fp->pairs[j].ch2;
2699 				if (minus) {
2700 					if (ftrtab[f][ch1] == ch2)
2701 						ftrtab[f][ch1] = ch1;
2702 				} else {
2703 					ftrtab[f][ch1] = ch2;
2704 				}
2705 			}
2706 			break;
2707 		}
2708 	if (fp == NULL)
2709 		errprint("no feature named %s in font %s", name, a->fontname);
2710 	return 1;
2711 }
2712 
2713 void
casefeature(void)2714 casefeature(void)
2715 {
2716 	struct afmtab	*a;
2717 	int	f, i, j;
2718 
2719 	lgf++;
2720 	if (skip(1))
2721 		return;
2722 	i = getrq(2);
2723 	if ((f = findft(i, 1)) < 0)
2724 		return;
2725 	if ((j = (fontbase[f]->afmpos) - 1) < 0 ||
2726 			((a = afmtab[j])->type != TYPE_OTF &&
2727 			a->type != TYPE_TTF)) {
2728 		errprint("font %s is not an OpenType font", macname(i));
2729 		return;
2730 	}
2731 	if (a->features == NULL) {
2732 		errprint("font %s has no OpenType features", a->fontname);
2733 		return;
2734 	}
2735 	while (getfeature(a, f) != 0);
2736 }
2737 
2738 #include "unimap.h"
2739 
2740 static int
ufmap(int c,int f,int * fp)2741 ufmap(int c, int f, int *fp)
2742 {
2743 	struct unimap	*up, ***um;
2744 	struct afmtab	*a;
2745 	int	i;
2746 
2747 	if ((c&~0xffff) == 0 &&
2748 			(i = (fontbase[f]->afmpos) - 1) >= 0 &&
2749 			(um = (a = afmtab[i])->unimap) != NULL &&
2750 			um[c>>8] != NULL &&
2751 			(up = um[c>>8][c&0377]) != NULL) {
2752 		*fp = f;
2753 		return up->u.code;
2754 	}
2755 	return 0;
2756 }
2757 
2758 int
un2tr(int c,int * fp)2759 un2tr(int c, int *fp)
2760 {
2761 	extern char	ifilt[];
2762 	struct unimap	*um, *up;
2763 	int	i, j;
2764 
2765 	switch (c) {
2766 	case 0x00A0:
2767 		*fp = font;
2768 		return UNPAD;
2769 	case 0x00AD:
2770 		*fp = font;
2771 		return ohc;
2772 	case 0x2002:
2773 		return makem((int)(EM)/2);
2774 	case 0x2003:
2775 		return makem((int)EM);
2776 	case 0x2004:
2777 		return makem((int)EM/3);
2778 	case 0x2005:
2779 		return makem((int)EM/4);
2780 	case 0x2006:
2781 		return makem((int)EM/6);
2782 	case 0x2007:
2783 		return makem(width('0' | chbits));
2784 	case 0x2008:
2785 		return makem(width('.' | chbits));
2786 	case 0x2009:
2787 		return makem((int)EM/6);
2788 	case 0x200A:
2789 		return makem((int)EM/12);
2790 	case 0x2010:
2791 		*fp = font;
2792 		return '-';
2793 	case 0x2027:
2794 		*fp = font;
2795 		return OHC | BLBIT;
2796 	case 0x2060:
2797 		*fp = font;
2798 		return FILLER;
2799 	default:
2800 		if ((i = ufmap(c, font, fp)) != 0)
2801 			return i;
2802 		if ((c&~0xffff) == 0 && unimap[c>>8] != NULL &&
2803 				(um = unimap[c>>8][c&0377]) != NULL) {
2804 			up = um;
2805 			do
2806 				if ((j = postchar1(up->u.psc, font)) != 0) {
2807 					*fp = font;
2808 					return j;
2809 				}
2810 			while ((up = up->next) != NULL);
2811 			up = um;
2812 			do
2813 				if ((j = postchar(up->u.psc, fp)) != 0)
2814 					return j;
2815 			while ((up = up->next) != NULL);
2816 			up = um;
2817 			do
2818 				if ((j = _ps2cc(up->u.psc, 0)) != 0) {
2819 					j += nchtab + 128 + 32 +
2820 						128 - 32 + nchtab;
2821 					if (chartab[j] != NULL)
2822 						return j;
2823 				}
2824 			while ((up = up->next) != NULL);
2825 		}
2826 		if (fallbacktab[font])
2827 			for (j = 0; fallbacktab[font][j] != 0; j++) {
2828 				if ((i = findft(fallbacktab[font][j], 0)) < 0)
2829 					continue;
2830 				if ((i = ufmap(c, i, fp)) != 0)
2831 					return i;
2832 			}
2833 		if (smnt)
2834 			for (i = smnt, j=0; j < nfonts; j++, i = i % nfonts + 1) {
2835 				if (fontbase[i] == NULL)
2836 					continue;
2837 				if ((i = ufmap(c, i, fp)) != 0)
2838 					return i;
2839 			}
2840 		*fp = font;
2841 		if ((c < 040 && c == ifilt[c]) || (c >= 040 && c < 0177))
2842 			return c;
2843 		else if ((c & ~0177) == 0) {
2844 			illseq(c, NULL, 0);
2845 			return 0;
2846 		} else if (defcf && (c & ~0xffff) == 0) {
2847 			char	buf[20];
2848 			snprintf(buf, sizeof(buf), "[uni%04X]", c);
2849 			cpushback(buf);
2850 			unadd(c, NULL);
2851 			return WORDSP;
2852 		} else if (html) {
2853 			return c;
2854 		} else {
2855 			if (warn & WARN_CHAR)
2856 				errprint("no glyph available for %U", c);
2857 			return tryglf ? 0 : ' ';
2858 		}
2859 	}
2860 }
2861 
2862 int
tr2un(tchar i,int f)2863 tr2un(tchar i, int f)
2864 {
2865 	struct afmtab	*a;
2866 	int	c, n;
2867 
2868 	if (i < 32)
2869 		return -1;
2870 	else if (i < 128)
2871 		return i;
2872 	if ((n = (fontbase[f]->afmpos) - 1) >= 0) {
2873 		a = afmtab[n];
2874 		if (a->unitab && i < a->nunitab && a->unitab[i])
2875 			return a->unitab[i];
2876 		if (i - 32 >= nchtab + 128)
2877 			i -= nchtab + 128;
2878 		if ((n = a->fitab[i - 32]) < a->nchars &&
2879 				a->nametab[n] != NULL)
2880 			for (c = 0; rawunimap[c].psc; c++)
2881 				if (strcmp(rawunimap[c].psc, a->nametab[n])==0)
2882 					return rawunimap[c].code;
2883 	}
2884 	return -1;
2885 }
2886 
2887 tchar
setuc0(int n)2888 setuc0(int n)
2889 {
2890 	int	f;
2891 	tchar	c;
2892 
2893 	if ((c = un2tr(n, &f)) != 0 && !ismot(c)) {
2894 		c |= chbits & ~FMASK;
2895 		setfbits(c, f);
2896 	}
2897 	return c;
2898 }
2899 
2900 static char *
getref(void)2901 getref(void)
2902 {
2903 	int	a = 0, i, c, delim;
2904 	char	*np = NULL;
2905 
2906 	if ((delim = getach()) != 0) {
2907 		for (i = 0; ; i++) {
2908 			if (i + 1 >= a)
2909 				np = realloc(np, a += 32);
2910 			if ((c = getach()) == 0) {
2911 				if (cbits(ch) == ' ') {
2912 					ch = 0;
2913 					c = ' ';
2914 				} else {
2915 					nodelim(delim);
2916 					break;
2917 				}
2918 			}
2919 			if (c == delim)
2920 				break;
2921 			np[i] = c;
2922 		}
2923 		np[i] = 0;
2924 	}
2925 	return np;
2926 }
2927 
2928 tchar
setanchor(void)2929 setanchor(void)
2930 {
2931 	static int	cnt;
2932 	struct ref	*rp;
2933 	char	*np;
2934 
2935 	if ((np = getref()) != NULL) {
2936 		rp = calloc(1, sizeof *rp);
2937 		rp->cnt = ++cnt;
2938 		rp->name = np;
2939 		rp->next = anchors;
2940 		anchors = rp;
2941 		return mkxfunc(ANCHOR, cnt);
2942 	} else
2943 		return mkxfunc(ANCHOR, 0);
2944 }
2945 
2946 static tchar
_setlink(struct ref ** rstart,int oncode,int offcode,int * cnt)2947 _setlink(struct ref **rstart, int oncode, int offcode, int *cnt)
2948 {
2949 	struct ref	*rp;
2950 	char	*np;
2951 	int	sv;
2952 
2953 	sv = linkin;
2954 	if ((linkin = !linkin)) {
2955 		if ((np = getref()) != NULL) {
2956 			rp = calloc(1, sizeof *rp);
2957 			rp->cnt = ++*cnt;
2958 			rp->name = np;
2959 			rp->next = *rstart;
2960 			*rstart = rp;
2961 			linkin = *cnt;
2962 			return mkxfunc(oncode, *cnt);
2963 		} else {
2964 			linkin = -1;
2965 			return mkxfunc(oncode, 0);
2966 		}
2967 	} else
2968 		return mkxfunc(offcode, sv > 0 ? sv : 0);
2969 }
2970 
2971 tchar
setlink(void)2972 setlink(void)
2973 {
2974 	static int	cnt;
2975 
2976 	return _setlink(&links, LINKON, LINKOFF, &cnt);
2977 }
2978 
2979 tchar
setulink(void)2980 setulink(void)
2981 {
2982 	static int	cnt;
2983 
2984 	return _setlink(&ulinks, ULINKON, ULINKOFF, &cnt);
2985 }
2986 
2987 int
pts2u(int p)2988 pts2u(int p)
2989 {
2990 	return p * INCH / 72;
2991 }
2992 
2993 double
u2pts(int u)2994 u2pts(int u)
2995 {
2996 	return u * 72.0 / INCH;
2997 }
2998 
2999 #define	psnprime	1021
3000 
3001 static struct psnnode {
3002 	struct psnnode	*next;
3003 	const char	*name;
3004 	int	code;
3005 } **psntable;
3006 
3007 static int
_ps2cc(const char * name,int create)3008 _ps2cc(const char *name, int create)
3009 {
3010 	struct psnnode	*pp;
3011 	unsigned	h;
3012 
3013 	if (psntable == NULL)
3014 		psntable = calloc(psnprime, sizeof *psntable);
3015 	h = pjw(name) % psnprime;
3016 	for (pp = psntable[h]; pp; pp = pp->next)
3017 		if (strcmp(name, pp->name) == 0)
3018 			return pp->code;
3019 	if (create == 0)
3020 		return 0;
3021 	pp = calloc(1, sizeof *pp);
3022 	pp->name = strdup(name);
3023 	pp->next = psntable[h];
3024 	psntable[h] = pp;
3025 	return pp->code = ++psmaxcode;
3026 }
3027 
3028 int
ps2cc(const char * name)3029 ps2cc(const char *name)
3030 {
3031 	return _ps2cc(name, 1);
3032 }
3033