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