1 /* $Id: afm2tfm.c 36523 2015-03-15 22:47:12Z kakuto $ */
2
3 /* Public domain, originally written by Tom Rokicki.
4 * This program converts AFM files to TeX TFM files, and optionally
5 * to TeX VPL files that retain all kerning and ligature information.
6 * Both files make the characters not normally encoded by TeX available
7 * by character codes greater than 127.
8 */
9
10 /* (Modified by Don Knuth from Tom Rokicki's pre-VPL version.) */
11 /* VM/CMS port by J. Hafner (hafner@almaden.ibm.com), based on
12 * the port by Alessio Guglielmi (guglielmi@ipisnsib.bitnet)
13 * and Marco Prevedelli (prevedelli@ipisnsva.bitnet).
14 * This port is still in test state. No guarantees.
15 * 11/3/92: more corrections to VM/CMS port. Now it looks correct
16 * and will be supported by J. Hafner.
17 *
18 */
19 /*
20 * More changes, primarily from Karl Berry, enough for a new version
21 * number to 8.0; 1 December 1996. Note that this version computes
22 * checksums differently (more intelligently).
23 */
24
25 #ifdef KPATHSEA
26 #include "config.h"
27 #include <kpathsea/c-ctype.h>
28 #include <kpathsea/progname.h>
29 #include <kpathsea/version.h>
30 #include <math.h>
31 #else /* ! KPATHSEA */
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #if defined(SYSV) || defined(VMS) || defined(__THINK__) || defined(MSDOS) || defined(OS2) || defined(ATARIST) || defined(WIN32)
36 #include <string.h>
37 #else
38 #include <strings.h>
39 #endif
40 #include <math.h>
41 #ifdef ATARIST
42 #include <float.h>
43 #endif
44 #endif /* KPATHSEA */
45
46 /* JLH: added these to make the code easier to read and remove some
47 ascii<->ebcdic dependencies */
48 #define ASCII_A 65
49 #define ASCII_Z 90
50 #define ASCII_a 97
51 #define ASCII_z 122
52 #define ASCII_0 48
53 #define ASCII_9 57
54
55 #ifdef VMCMS
56 #define interesting lookstr /* for 8 character truncation conflicts */
57 #include "dvipscms.h"
58 extern FILE *cmsfopen();
59 extern char ebcdic2ascii[];
60 extern char ascii2ebcdic[];
61 #ifdef fopen
62 #undef fopen
63 #endif
64 #define fopen cmsfopen
65 #endif /* VMCMS */
66
67 #include "dvips.h"
68 /* debug.h redefines fopen to my_real_fopen, but it's still a FILE * */
69 #ifdef fopen
70 #undef fopen
71 extern FILE *fopen ();
72 #endif
73
74 struct encoding {
75 const char *name;
76 const char *vec[256];
77 };
78 struct encoding staticencoding = {
79 "TeX text",
80 {"Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
81 "Upsilon", "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
82 "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", "acute",
83 "caron", "breve", "macron", "ring", "cedilla", "germandbls", "ae", "oe",
84 "oslash", "AE", "OE", "Oslash", "space", "exclam", "quotedbl", "numbersign",
85 "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
86 "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
87 "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
88 "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
89 "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
90 "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
91 "bracketright", "circumflex", "underscore", "quoteleft", "a", "b", "c", "d",
92 "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
93 "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
94 "tilde", "dieresis", "", "", "", "", "", "", "", "", "", "", "", "", "",
95 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
96 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
97 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
98 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
99 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
100 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
101 "", "", "", "", "", "", "" } };
102 /*
103 * It's easier to put this in static storage and parse it as we go
104 * than to build the structures ourselves.
105 */
106 const char *staticligkern[] = {
107 "% LIGKERN space l =: lslash ; space L =: Lslash ;",
108 "% LIGKERN question quoteleft =: questiondown ;",
109 "% LIGKERN exclam quoteleft =: exclamdown ;",
110 "% LIGKERN hyphen hyphen =: endash ; endash hyphen =: emdash ;",
111 "% LIGKERN quoteleft quoteleft =: quotedblleft ;",
112 "% LIGKERN quoteright quoteright =: quotedblright ;",
113 "% LIGKERN space {} * ; * {} space ; zero {} * ; * {} zero ;",
114 "% LIGKERN one {} * ; * {} one ; two {} * ; * {} two ;",
115 "% LIGKERN three {} * ; * {} three ; four {} * ; * {} four ;",
116 "% LIGKERN five {} * ; * {} five ; six {} * ; * {} six ;",
117 "% LIGKERN seven {} * ; * {} seven ; eight {} * ; * {} eight ;",
118 "% LIGKERN nine {} * ; * {} nine ;",
119 /* Kern accented characters the same way as their base. */
120 "% LIGKERN Aacute <> A ; aacute <> a ;",
121 "% LIGKERN Acircumflex <> A ; acircumflex <> a ;",
122 "% LIGKERN Adieresis <> A ; adieresis <> a ;",
123 "% LIGKERN Agrave <> A ; agrave <> a ;",
124 "% LIGKERN Aring <> A ; aring <> a ;",
125 "% LIGKERN Atilde <> A ; atilde <> a ;",
126 "% LIGKERN Ccedilla <> C ; ccedilla <> c ;",
127 "% LIGKERN Eacute <> E ; eacute <> e ;",
128 "% LIGKERN Ecircumflex <> E ; ecircumflex <> e ;",
129 "% LIGKERN Edieresis <> E ; edieresis <> e ;",
130 "% LIGKERN Egrave <> E ; egrave <> e ;",
131 "% LIGKERN Iacute <> I ; iacute <> i ;",
132 "% LIGKERN Icircumflex <> I ; icircumflex <> i ;",
133 "% LIGKERN Idieresis <> I ; idieresis <> i ;",
134 "% LIGKERN Igrave <> I ; igrave <> i ;",
135 "% LIGKERN Ntilde <> N ; ntilde <> n ;",
136 "% LIGKERN Oacute <> O ; oacute <> o ;",
137 "% LIGKERN Ocircumflex <> O ; ocircumflex <> o ;",
138 "% LIGKERN Odieresis <> O ; odieresis <> o ;",
139 "% LIGKERN Ograve <> O ; ograve <> o ;",
140 "% LIGKERN Oslash <> O ; oslash <> o ;",
141 "% LIGKERN Otilde <> O ; otilde <> o ;",
142 "% LIGKERN Scaron <> S ; scaron <> s ;",
143 "% LIGKERN Uacute <> U ; uacute <> u ;",
144 "% LIGKERN Ucircumflex <> U ; ucircumflex <> u ;",
145 "% LIGKERN Udieresis <> U ; udieresis <> u ;",
146 "% LIGKERN Ugrave <> U ; ugrave <> u ;",
147 "% LIGKERN Yacute <> Y ; yacute <> y ;",
148 "% LIGKERN Ydieresis <> Y ; ydieresis <> y ;",
149 "% LIGKERN Zcaron <> Z ; zcaron <> z ;",
150 /*
151 * These next are only included for deficient afm files that
152 * have the lig characters but not the lig commands.
153 */
154 "% LIGKERN f i =: fi ; f l =: fl ; f f =: ff ; ff i =: ffi ;",
155 "% LIGKERN ff l =: ffl ;",
156 0 };
157 /*
158 * The above layout corresponds to TeX Typewriter Type and is compatible
159 * with TeX Text because the position of ligatures is immaterial.
160 */
161 struct encoding *outencoding = 0;
162 struct encoding *inencoding = 0;
163 char *outenname = NULL,
164 *inenname = NULL;/* the file names for input and output encodings */
165 int boundarychar = -1; /* the boundary character */
166 int ignoreligkern; /* do we look at ligkern info in the encoding? */
167 /*
168 * This is what we store Adobe data in.
169 */
170 struct adobeinfo {
171 struct adobeinfo *next;
172 int adobenum, texnum, width;
173 const char *adobename;
174 int llx, lly, urx, ury;
175 struct lig *ligs;
176 struct kern *kerns;
177 struct adobeptr *kern_equivs;
178 struct pcc *pccs;
179 int wptr, hptr, dptr, iptr;
180 } *adobechars, *adobeptrs[256], *texptrs[256],
181 *uppercase[256], *lowercase[256];
182 int nexttex[256]; /* for characters encoded multiple times in output */
183 /*
184 * These are the eight ligature ops, in VPL terms and in METAFONT terms.
185 */
186 const char *vplligops[] = {
187 "LIG", "/LIG", "/LIG>", "LIG/", "LIG/>", "/LIG/", "/LIG/>", "/LIG/>>", 0
188 };
189 const char *encligops[] = {
190 "=:", "|=:", "|=:>", "=:|", "=:|>", "|=:|", "|=:|>", "|=:|>>", 0
191 };
192 struct lig {
193 struct lig *next;
194 const char *succ, *sub;
195 short op, boundleft;
196 };
197 struct kern {
198 struct kern *next;
199 const char *succ;
200 int delta;
201 };
202 struct adobeptr {
203 struct adobeptr *next;
204 struct adobeinfo *ch;
205 };
206 struct pcc {
207 struct pcc *next;
208 const char * partname;
209 int xoffset, yoffset;
210 };
211
212 FILE *afmin, *vplout, *tfmout;
213 char inname[200], outname[200]; /* names of input and output files */
214 char tmpstr[200]; /* a buffer for one string */
215 #define INBUFSIZE 1024
216 char buffer[INBUFSIZE+10]; /* input buffer (modified while parsing) */
217 char obuffer[INBUFSIZE+10]; /* unmodified copy of input buffer */
218 char *param; /* current position in input buffer */
219 const char *fontname = "Unknown";
220 const char *codingscheme = "Unspecified";
221 #ifdef VMCMS
222 char *ebfontname;
223 char *ebcodingscheme;
224 #endif
225 float italicangle = 0.0;
226 char fixedpitch;
227 char makevpl;
228 char pedantic;
229 int xheight = 400;
230 int fontspace;
231 int bc, ec;
232 long cksum;
233 float efactor = 1.0, slant = 0.0;
234 float capheight = 0.8;
235 char *efactorparam, *slantparam;
236 double newslant;
237 char titlebuf[500];
238
239 static void
error(const char * s)240 error(const char *s)
241 {
242 fprintf(stderr, "%s\n", s);
243 if (obuffer[0]) {
244 fprintf(stderr, "%s\n", obuffer);
245 while (param > buffer) {
246 fprintf(stderr, " ");
247 param--;
248 }
249 fprintf(stderr, "^\n");
250 }
251 if (*s == '!')
252 exit(1);
253 }
254
255 static int
transform(register int x,register int y)256 transform(register int x, register int y)
257 {
258 register double acc;
259 acc = efactor * x + slant *y;
260 return (int)(acc>=0? floor(acc+0.5) : ceil(acc-0.5) );
261 }
262
263 static int
texlive_getline(void)264 texlive_getline(void) {
265 register char *p;
266 register int c;
267
268 param = buffer;
269 for (p=buffer; (c=getc(afmin)) != EOF;) {
270 if (p - buffer >= INBUFSIZE)
271 error("! input line too long; perhaps input file is malformed?");
272 *p++ = c;
273 if (c == '\r') {
274 c = getc(afmin);
275 if (c != EOF) {
276 if (c == '\n') {
277 *p++ = c;
278 } else {
279 ungetc(c, afmin);
280 }
281 }
282 break;
283 } else if (c == '\n') {
284 break;
285 }
286 }
287 *p = 0;
288 strcpy(obuffer, buffer);
289 if (p == buffer && c == EOF)
290 return(0);
291 else
292 return(1);
293 }
294
295 const char *interesting[] = { "FontName", "ItalicAngle", "IsFixedPitch",
296 "XHeight", "C", "KPX", "CC", "EncodingScheme", NULL};
297 #define FontName (0)
298 #define ItalicAngle (1)
299 #define IsFixedPitch (2)
300 #define XHeight (3)
301 #define C (4)
302 #define KPX (5)
303 #define CC (6)
304 #define EncodingScheme (7)
305 #define NONE (-1)
306 static int
interest(const char * s)307 interest(const char *s)
308 {
309 register const char **p;
310 register int n;
311
312 for (p=interesting, n=0; *p; p++, n++)
313 if (strcmp(s, *p)==0)
314 return(n);
315 return(NONE);
316 }
317
318 static char *
mymalloc(unsigned long len)319 mymalloc(unsigned long len)
320 {
321 register char *p;
322 int i;
323
324 #ifdef SMALLMALLOC
325 if (len > 65500L)
326 error("! can't allocate more than 64K!");
327 #endif
328 p = (char *) malloc((unsigned)len);
329 if (p==NULL)
330 error("! out of memory");
331 for (i=0; i<len; i++)
332 p[i] = 0;
333 return(p);
334 }
335
336 static char *
newstring(char * s)337 newstring(char *s)
338 {
339 char *q = mymalloc((unsigned long)(strlen(s) + 1));
340 strcpy(q, s);
341 return q;
342 }
343
344 static char *
paramnewstring(void)345 paramnewstring(void) {
346 register char *p, *q;
347
348 p = param;
349 while (*p > ' ')
350 p++;
351 if (*p != 0)
352 *p++ = 0;
353 q = newstring(param);
354 while (*p && *p <= ' ')
355 p++;
356 param = p;
357 return(q);
358 }
359
360 static char *
paramstring(void)361 paramstring(void) {
362 register char *p, *q;
363
364 p = param;
365 while (*p > ' ')
366 p++;
367 q = param;
368 if (*p != 0)
369 *p++ = 0;
370 while (*p && *p <= ' ')
371 p++;
372 param = p;
373 return(q);
374 }
375
376 static int
paramnum(void)377 paramnum(void) {
378 register char *p;
379 int i;
380
381 p = paramstring();
382 if (sscanf(p, "%d", &i) != 1)
383 error("! integer expected");
384 return(i);
385 }
386
387 static float
paramfloat(void)388 paramfloat(void) {
389 register char *p;
390 float i;
391
392 p = paramstring();
393 if (sscanf(p, "%f", &i) != 1)
394 error("! number expected");
395 return(i);
396 }
397
398 static struct adobeinfo *
newchar(void)399 newchar(void) {
400 register struct adobeinfo *ai;
401
402 ai = (struct adobeinfo *)mymalloc((unsigned long)sizeof(struct adobeinfo));
403 ai->adobenum = -1;
404 ai->texnum = -1;
405 ai->width = -1;
406 ai->adobename = NULL;
407 ai->llx = -1;
408 ai->lly = -1;
409 ai->urx = -1;
410 ai->ury = -1;
411 ai->ligs = NULL;
412 ai->kerns = NULL;
413 ai->kern_equivs = NULL;
414 ai->pccs = NULL;
415 ai->next = adobechars;
416 adobechars = ai;
417 return(ai);
418 }
419
420 static struct kern *
newkern(void)421 newkern(void) {
422 register struct kern *nk;
423
424 nk = (struct kern *)mymalloc((unsigned long)sizeof(struct kern));
425 nk->next = NULL;
426 nk->succ = NULL;
427 nk->delta = 0;
428 return(nk);
429 }
430
431 static struct pcc *
newpcc(void)432 newpcc(void) {
433 register struct pcc *np;
434
435 np = (struct pcc *)mymalloc((unsigned long)sizeof(struct pcc));
436 np->next = NULL;
437 np->partname = NULL;
438 np->xoffset = 0;
439 np->yoffset = 0;
440 return(np);
441 }
442
443 static struct lig *
newlig(void)444 newlig(void) {
445 register struct lig *nl;
446
447 nl = (struct lig *)mymalloc((unsigned long)sizeof(struct lig));
448 nl->next = NULL;
449 nl->succ = NULL;
450 nl->sub = NULL;
451 nl->op = 0; /* the default =: op */
452 nl->boundleft = 0;
453 return(nl);
454 }
455
456 static void
expect(const char * s)457 expect(const char *s)
458 {
459 if (strcmp(paramstring(), s) != 0) {
460 fprintf(stderr, "%s expected: ", s);
461 error("! syntax error");
462 }
463 }
464
465 static void
handlechar(void)466 handlechar(void) { /* an input line beginning with C */
467 register struct adobeinfo *ai;
468 register struct lig *nl;
469
470 ai = newchar();
471 ai->adobenum = paramnum();
472 expect(";");
473 expect("WX");
474 ai->width = transform(paramnum(),0);
475 if (ai->adobenum >= 0 && ai->adobenum < 256) {
476 adobeptrs[ai->adobenum] = ai;
477 }
478 expect(";");
479 /* Ignore vertical metrics information */
480 if (*param == 'W' && *(param + 1) == 'Y') {
481 expect("WY");
482 paramnum();
483 expect(";");
484 }
485 expect("N");
486 ai->adobename = paramnewstring();
487 expect(";");
488 expect("B");
489 ai->llx = paramnum();
490 ai->lly = paramnum();
491 ai->llx = transform(ai->llx, ai->lly);
492 ai->urx = paramnum();
493 ai->ury = paramnum();
494 ai->urx = transform(ai->urx, ai->ury);
495 /* We need to avoid negative heights or depths. They break accents in
496 math mode, among other things. */
497 if (ai->lly > 0)
498 ai->lly = 0;
499 if (ai->ury < 0)
500 ai->ury = 0;
501 expect(";");
502 /* Now look for ligatures (which aren't present in fixedpitch fonts) */
503 while (*param == 'L' && !fixedpitch) {
504 expect("L");
505 nl = newlig();
506 nl->succ = paramnewstring();
507 nl->sub = paramnewstring();
508 nl->next = ai->ligs;
509 ai->ligs = nl;
510 expect(";");
511 }
512 }
513
514 static struct adobeinfo *
findadobe(const char * p)515 findadobe(const char *p)
516 {
517 register struct adobeinfo *ai;
518
519 for (ai=adobechars; ai; ai = ai->next)
520 if (strcmp(p, ai->adobename)==0)
521 return(ai);
522 return(NULL);
523 }
524
525
526 /*
527 * The following comment no longer applies; we rely on the LIGKERN
528 * entries to kill space kerns. Also, the same applies to numbers.
529 *
530 * We ignore kerns before and after space characters, because (1) TeX
531 * is using the space only for Polish ligatures, and (2) TeX's
532 * boundarychar mechanisms are not oriented to kerns (they apply
533 * to both spaces and punctuation) so we don't want to use them.
534 */
535 static void
handlekern(void)536 handlekern(void) { /* an input line beginning with KPX */
537 register struct adobeinfo *ai;
538 register char *p;
539 register struct kern *nk;
540
541 p = paramstring();
542 ai = findadobe(p);
543 if (ai == NULL)
544 error("kern char not found");
545 else {
546 nk = newkern();
547 nk->succ = paramnewstring();
548 nk->delta = transform(paramnum(),0);
549 nk->next = ai->kerns;
550 ai->kerns = nk;
551 }
552 }
553
554 static void
handleconstruct(void)555 handleconstruct(void) { /* an input line beginning with CC */
556 register struct adobeinfo *ai;
557 register char *p;
558 register struct pcc *np;
559 register int n;
560 struct pcc *npp = NULL;
561
562 p = paramstring();
563 ai = findadobe(p);
564 if (ai == NULL)
565 error("! composite character name not found");
566 n = paramnum();
567 expect(";");
568 while (n--) {
569 if (strcmp(paramstring(),"PCC") != 0) return;
570 /* maybe I should expect("PCC") instead, but I'm playing it safe */
571 np = newpcc();
572 np->partname = paramnewstring();
573 if (findadobe(np->partname)==NULL) return;
574 np->xoffset = paramnum();
575 np->yoffset = paramnum();
576 np->xoffset = transform(np->xoffset, np->yoffset);
577 if (npp) npp->next = np;
578 else ai->pccs = np;
579 npp = np;
580 expect(";");
581 }
582 }
583
584 static struct encoding *readencoding(char *);
585
586 #if 0
587 /* Not used */
588 static void
589 makeaccentligs(void) {
590 register struct adobeinfo *ai, *aci;
591 register char *p;
592 register struct lig *nl;
593 for (ai=adobechars; ai; ai=ai->next) {
594 p = ai->adobename;
595 if (strlen(p)>2)
596 if ((aci=findadobe(p+1)) && (aci->adobenum > 127)) {
597 nl = newlig();
598 nl->succ = mymalloc((unsigned long)2);
599 *(nl->succ + 1) = 0;
600 *(nl->succ) = *p;
601 nl->sub = ai->adobename;
602 nl->next = aci->ligs;
603 aci->ligs = nl;
604 }
605 }
606 }
607 #endif
608
609 static void
readadobe(void)610 readadobe(void) {
611 struct adobeinfo *ai;
612 #ifdef VMCMS
613 int i;
614 #endif
615
616 /*
617 * We allocate a placeholder boundary char.
618 */
619 ai = newchar();
620 ai->adobenum = -1;
621 ai->adobename = "||"; /* boundary character name */
622 while (texlive_getline()) {
623 switch(interest(paramstring())) {
624 case FontName:
625 fontname = paramnewstring();
626 #ifdef VMCMS
627 /* fontname comes in as ebcdic but we need it asciified for tfm file
628 so we save it in ebfontname and change it in fontname */
629 ebfontname = newstring(fontname);
630 i=0;
631 while(fontname[i] != '\0') {
632 fontname[i]=ebcdic2ascii[fontname[i]];
633 i++;
634 };
635 #endif
636 break;
637 case EncodingScheme:
638 codingscheme = paramnewstring();
639 #ifdef VMCMS
640 /* for codingscheme, we do the same as we did for fontname */
641 ebcodingscheme = newstring(codingscheme);
642 i=0;
643 while(codingscheme[i] != '\0') {
644 codingscheme[i]=ebcdic2ascii[codingscheme[i]];
645 i++;
646 }
647 #endif
648 break;
649 case ItalicAngle:
650 italicangle = paramfloat();
651 break;
652 case IsFixedPitch:
653 if (*param == 't' || *param == 'T')
654 fixedpitch = 1;
655 else
656 fixedpitch = 0;
657 break;
658 case XHeight:
659 xheight = paramnum();
660 break;
661 case C:
662 handlechar();
663 break;
664 case KPX:
665 handlekern();
666 break;
667 case CC:
668 handleconstruct();
669 break;
670 default:
671 break;
672 }
673 }
674 fclose(afmin);
675 afmin = 0;
676 }
677 /*
678 * Re-encode the adobe font. Assumes that the header file will
679 * also contain the appropriate instructions!
680 */
681 static void
handlereencoding(void)682 handlereencoding(void) {
683 if (inenname) {
684 int i;
685 struct adobeinfo *ai;
686 const char *p;
687
688 ignoreligkern = 1;
689 inencoding = readencoding(inenname);
690 for (i=0; i<256; i++)
691 if (0 != (ai=adobeptrs[i])) {
692 ai->adobenum = -1;
693 adobeptrs[i] = NULL;
694 }
695 for (i=0; i<256; i++) {
696 p = inencoding->vec[i];
697 if (p && *p && strcmp(p, ".notdef") != 0 && 0 != (ai = findadobe(p))) {
698 ai->adobenum = i;
699 adobeptrs[i] = ai;
700 }
701 }
702 codingscheme = inencoding->name;
703 }
704 ignoreligkern = 0;
705 if (outenname) {
706 outencoding = readencoding(outenname);
707 } else {
708 outencoding = readencoding((char *)0);
709 }
710 }
711
712 /*
713 * This routine reverses a list. We use it because we accumulate the
714 * adobeinfo list in reverse order, but when we go to map the
715 * characters, we would prefer to use the original ordering. It just
716 * makes more sense.
717 */
718 static struct adobeinfo *
revlist(struct adobeinfo * p)719 revlist (struct adobeinfo *p)
720 {
721 struct adobeinfo *q = 0, *t;
722
723 while (p) {
724 t = p->next;
725 p->next = q;
726 q = p;
727 p = t;
728 }
729 return q;
730 }
731
732 static void
assignchars(void)733 assignchars(void) {
734 register const char **p;
735 register int i, j;
736 register struct adobeinfo *ai, *pai;
737 int nextfree = 128;
738 struct pcc *pcp;
739
740 /*
741 * First, we assign all those that match perfectly.
742 */
743 for (i=0, p=outencoding->vec; i<256; i++, p++)
744 if (*p && strcmp(*p, ".notdef") != 0 &&
745 (ai=findadobe(*p)) && (ai->adobenum >= 0 || ai->pccs != NULL)) {
746 if (ai->texnum >= 0)
747 nexttex[i] = ai->texnum; /* linked list */
748 ai->texnum = i;
749 texptrs[i] = ai;
750 }
751 if (pedantic)
752 return;
753 /*
754 * Next, we assign all the others, retaining the adobe positions, possibly
755 * multiply assigning characters. Unless the output encoding was
756 * precisely specified.
757 */
758 for (ai=adobechars; ai; ai=ai->next)
759 if (ai->adobenum >= 0 && ai->adobenum <256
760 && ai->texnum < 0 && texptrs[ai->adobenum] == 0) {
761 ai->texnum = ai->adobenum;
762 texptrs[ai->adobenum] = ai;
763 }
764 /*
765 * Finally, we map all remaining characters into free locations beginning
766 * with 128, if we know how to construct those characters. We need to
767 * make sure the component pieces are mapped.
768 */
769 adobechars = revlist(adobechars);
770 for (ai=adobechars; ai; ai=ai->next)
771 if (ai->texnum<0 && (ai->adobenum>=0 || ai->pccs != NULL)) {
772 while (texptrs[nextfree]) {
773 nextfree=(nextfree+1)&255;
774 if (nextfree==128) goto finishup; /* all slots full */
775 }
776 ai->texnum = nextfree;
777 texptrs[nextfree] = ai;
778 }
779 finishup:
780 /*
781 * We now check all of the composite characters. If any of the
782 * components are not mapped, we unmap the composite character.
783 */
784 for (i=0; i<256; i++) {
785 ai = texptrs[i];
786 if (ai && ai->pccs != NULL && ai->texnum >= 0) {
787 for (pcp = ai->pccs; pcp; pcp = pcp->next) {
788 pai = findadobe(pcp->partname);
789 if (pai == NULL || pai->texnum < 0) {
790 texptrs[ai->texnum] = 0;
791 ai->texnum = -1;
792 break;
793 }
794 }
795 }
796 }
797 /*
798 * Now, if any of the characters are encoded multiple times, we want
799 * ai->texnum to be the first one assigned, since that is most likely
800 * to be the most important one. So we reverse the above lists.
801 */
802 for (ai=adobechars; ai; ai=ai->next)
803 if (ai->texnum >= 0 && ai->texnum < 256) {
804 j = -1;
805 while (nexttex[ai->texnum] >= 0) {
806 i = nexttex[ai->texnum];
807 nexttex[ai->texnum] = j;
808 j = ai->texnum;
809 ai->texnum = i;
810 }
811 nexttex[ai->texnum] = j;
812 }
813 }
814
815 static void
upmap(void)816 upmap(void) { /* Compute uppercase mapping, when making a small caps font */
817 register struct adobeinfo *ai, *Ai;
818 register const char *p;
819 register char *q;
820 register struct pcc *np, *nq;
821 int i;
822 char lwr[50];
823
824 /* JLH: changed some lines below to be ascii<->ebcdic independent
825 any reason we don't use 'isupper'?.
826 Looks like we should use isupper to me --karl. */
827 for (Ai=adobechars; Ai; Ai=Ai->next) {
828 p = Ai->adobename;
829 if (isupper ((unsigned char)*p)) {
830 q = lwr;
831 for (; *p; p++)
832 *q++ = TOLOWER (*p);
833 *q = '\0'; /* changed this too! */
834
835 if (0 != (ai=findadobe(lwr))) {
836 for (i = ai->texnum; i >= 0; i = nexttex[i])
837 uppercase[i] = Ai;
838 for (i = Ai->texnum; i >= 0; i = nexttex[i])
839 lowercase[i] = ai;
840 }
841 }
842 }
843 /* Note that, contrary to the normal true/false conventions,
844 * uppercase[i] is NULL and lowercase[i] is non-NULL when i is the
845 * ASCII code of an uppercase letter; and vice versa for lowercase letters */
846
847 if (0 != (ai=findadobe("germandbls")))
848 if (0 != (Ai=findadobe("S"))) { /* we also construct SS */
849 for (i=ai->texnum; i >= 0; i = nexttex[i])
850 uppercase[i] = ai;
851 ai->adobenum = -1;
852 ai->width = Ai->width << 1;
853 ai->llx = Ai->llx;
854 ai->lly = Ai->lly;
855 ai->urx = Ai->width + Ai->urx;
856 ai->ury = Ai->ury;
857 ai->kerns = Ai->kerns;
858 np = newpcc();
859 np->partname = "S";
860 nq = newpcc();
861 nq->partname = "S";
862 nq->xoffset = Ai->width;
863 np->next = nq;
864 ai->pccs = np;
865 }
866 if ((ai=findadobe("dotlessi")))
867 for (i=ai->texnum; i >= 0; i = nexttex[i])
868 uppercase[i] = findadobe("I");
869 if ((ai=findadobe("dotlessj")))
870 for (i=ai->texnum; i >= 0; i = nexttex[i])
871 uppercase[i] = findadobe("J");
872 }
873 /* The logic above seems to work well enough, but it leaves useless characters
874 * like `fi' and `fl' in the font if they were present initially,
875 * and it omits characters like `dotlessj' if they are absent initially */
876
877 /* Now we turn to computing the TFM file */
878
879 int lf, lh, nw, nh, nd, ni, nl, nk, ne, np;
880
881 static void
write16(register short what)882 write16(register short what)
883 {
884 fputc(what >> 8, tfmout);
885 fputc(what & 255, tfmout);
886 }
887
888 static void
writearr(register long * p,register int n)889 writearr(register long *p, register int n)
890 {
891 while (n) {
892 write16((short)(*p >> 16));
893 write16((short)(*p & 65535));
894 p++;
895 n--;
896 }
897 }
898
899 static void
makebcpl(register long * p,register const char * s,register int n)900 makebcpl(register long *p, register const char *s, register int n)
901 {
902 register long t;
903 register long sc;
904
905 if (strlen(s) < n)
906 n = strlen(s);
907 t = ((long)n) << 24;
908 sc = 16;
909 while (n > 0) {
910 t |= ((long)(*(unsigned const char *)s++)) << sc;
911 sc -= 8;
912 if (sc < 0) {
913 *p++ = t;
914 t = 0;
915 sc = 24;
916 }
917 n--;
918 }
919 *p++ = t;
920 }
921
922 int source[257];
923 int unsort[257];
924
925 /*
926 * Next we need a routine to reduce the number of distinct dimensions
927 * in a TFM file. Given an array what[0]...what[oldn-1], we want to
928 * group its elements into newn clusters, in such a way that the maximum
929 * difference between elements of a cluster is as small as possible.
930 * Furthermore, what[0]=0, and this value must remain in a cluster by
931 * itself. Data such as `0 4 6 7 9' with newn=3 shows that an iterative
932 * scheme in which 6 is first clustered with 7 will not work. So we
933 * borrow a neat algorithm from METAFONT to find the true optimum.
934 * Memory location what[oldn] is set to 0x7fffffffL for convenience.
935 */
936 long nextd; /* smallest value that will give a different mincover */
937 static int
mincover(long * what,register long d)938 mincover(long *what,
939 register long d) /* tells how many clusters result, given max difference d */
940 {
941 register int m;
942 register long l;
943 register long *p;
944
945 nextd = 0x7fffffffL;
946 p = what+1;
947 m = 1;
948 while (*p<0x7fffffffL) {
949 m++;
950 l = *p;
951 while (*++p <= l+d);
952 if (*p-l < nextd) nextd = *p-l;
953 }
954 return (m);
955 }
956
957 static void
remap(long * what,int oldn,int newn)958 remap(long * what, int oldn, int newn)
959 {
960 register int i, j;
961 register long d, l;
962
963 what[oldn] = 0x7fffffffL;
964 for (i=oldn-1; i>0; i--) {
965 d = what[i];
966 for (j=i; what[j+1]<d; j++) {
967 what[j] = what[j+1];
968 source[j] = source[j+1];
969 }
970 what[j] = d;
971 source[j] = i;
972 } /* Tom, don't let me ever catch you using bubblesort again! -- Don */
973
974 i = mincover(what, 0L);
975 d = nextd;
976 while (mincover(what,d+d)>newn) d += d;
977 while (mincover(what,d)>newn) d = nextd;
978
979 i = 1;
980 j = 0;
981 while (i<oldn) {
982 j++;
983 l = what[i];
984 unsort[source[i]] = j;
985 while (what[++i] <= l+d) {
986 unsort[source[i]] = j;
987 if (i-j == oldn-newn) d = 0;
988 }
989 what[j] = (l+what[i-1])/2;
990 }
991 }
992
993 static long
checksum(void)994 checksum(void) {
995 int i;
996 unsigned long s1 = 0, s2 = 0;
997 const char *p;
998 struct adobeinfo *ai;
999
1000 for (i=0; i<256; i++)
1001 if (0 != (ai=adobeptrs[i])) {
1002 s1 = ((s1 << 1) ^ (s1>>31)) ^ ai->width; /* cyclic left shift */
1003 s1 &= 0xffffffff; /* in case we're on a 64-bit machine */
1004 for (p=ai->adobename; *p; p++)
1005 #ifndef VMCMS
1006 s2 = (s2 * 3) + *p;
1007 #else
1008 s2 = (s2 * 3) + ebcdic2ascii[*p];
1009 #endif
1010 }
1011 s1 = (s1 << 1) ^ s2;
1012 return s1;
1013 }
1014
1015 /*
1016 * The next routine simply scales something.
1017 * Input is in 1000ths of an em. Output is in FIXFACTORths of 1000.
1018 */
1019 #define FIXFACTOR (0x100000L) /* 2^{20}, the unit fixnum */
1020 static long
scale(long what)1021 scale(long what)
1022 {
1023 return(((what / 1000) << 20) +
1024 (((what % 1000) << 20) + 500) / 1000);
1025 }
1026
1027 long *header, *charinfo, *width, *height, *depth, *ligkern, *kern, *tparam,
1028 *italic;
1029 long *tfmdata;
1030
1031 static void
buildtfm(void)1032 buildtfm(void) {
1033 register int i, j;
1034 register struct adobeinfo *ai;
1035
1036 header = tfmdata;
1037 cksum = checksum();
1038 header[0] = cksum;
1039 header[1] = 0xa00000; /* 10pt design size */
1040 makebcpl(header+2, codingscheme, 39);
1041 makebcpl(header+12, fontname, 19);
1042 lh = 17;
1043 charinfo = header + lh;
1044
1045 for (i=0; i<256 && adobeptrs[i]==NULL; i++);
1046 bc = i;
1047 for (i=255; i>=0 && adobeptrs[i]==NULL; i--);
1048 ec = i;
1049 if (ec < bc)
1050 error("! no Adobe characters");
1051
1052 width = charinfo + (ec - bc + 1);
1053 width[0] = 0;
1054 nw++;
1055 for (i=bc; i<=ec; i++)
1056 if (0 != (ai=adobeptrs[i])) {
1057 width[nw]=ai->width;
1058 for (j=1; width[j]!=ai->width; j++);
1059 ai->wptr = j;
1060 if (j==nw)
1061 nw++;
1062 }
1063 if (nw>256)
1064 error("! 256 chars with different widths");
1065 depth = width + nw;
1066 depth[0] = 0;
1067 nd = 1;
1068 for (i=bc; i<=ec; i++)
1069 if (0 != (ai=adobeptrs[i])) {
1070 depth[nd] = -ai->lly;
1071 for (j=0; depth[j]!=-ai->lly; j++);
1072 ai->dptr = j;
1073 if (j==nd)
1074 nd++;
1075 }
1076 if (nd > 16) {
1077 remap(depth, nd, 16);
1078 nd = 16;
1079 for (i=bc; i<=ec; i++)
1080 if (0 != (ai=adobeptrs[i]))
1081 ai->dptr = unsort[ai->dptr];
1082 }
1083 height = depth + nd;
1084 height[0] = 0;
1085 nh = 1;
1086 for (i=bc; i<=ec; i++)
1087 if (0 != (ai=adobeptrs[i])) {
1088 height[nh]=ai->ury;
1089 for (j=0; height[j]!=ai->ury; j++);
1090 ai->hptr = j;
1091 if (j==nh)
1092 nh++;
1093 }
1094 if (nh > 16) {
1095 remap(height, nh, 16);
1096 nh = 16;
1097 for (i=bc; i<=ec; i++)
1098 if (0 != (ai=adobeptrs[i]))
1099 ai->hptr = unsort[ai->hptr];
1100 }
1101 italic = height + nh;
1102 italic[0] = 0;
1103 ni = 1;
1104 for (i=bc; i<=ec; i++)
1105 if (0 != (ai=adobeptrs[i])) {
1106 italic[ni] = ai->urx - ai->width;
1107 if (italic[ni]<0)
1108 italic[ni] = 0;
1109 for (j=0; italic[j]!=italic[ni]; j++);
1110 ai->iptr = j;
1111 if (j==ni)
1112 ni++;
1113 }
1114 if (ni > 64) {
1115 remap(italic, ni, 64);
1116 ni = 64;
1117 for (i=bc; i<=ec; i++)
1118 if (0 != (ai=adobeptrs[i]))
1119 ai->iptr = unsort[ai->iptr];
1120 }
1121
1122 for (i=bc; i<=ec; i++)
1123 if (0 != (ai=adobeptrs[i]))
1124 charinfo[i-bc] = ((long)(ai->wptr)<<24) +
1125 ((long)(ai->hptr)<<20) +
1126 ((long)(ai->dptr)<<16) +
1127 ((long)(ai->iptr)<<10);
1128
1129 ligkern = italic + ni;
1130 nl = 0; /* ligatures and kerns omitted from raw Adobe font */
1131 kern = ligkern + nl;
1132 nk = 0;
1133
1134 newslant = (double)slant - efactor * tan(italicangle*(3.1415926535/180.0));
1135 tparam = kern + nk;
1136 tparam[0] = (long)(FIXFACTOR * newslant + 0.5);
1137 tparam[1] = scale((long)fontspace);
1138 tparam[2] = (fixedpitch ? 0 : scale((long)(300*efactor+0.5)));
1139 tparam[3] = (fixedpitch ? 0 : scale((long)(100*efactor+0.5)));
1140 tparam[4] = scale((long)xheight);
1141 tparam[5] = scale((long)(1000*efactor+0.5));
1142 np = 6;
1143 }
1144
1145 static void
writesarr(long * what,int len)1146 writesarr(long *what, int len)
1147 {
1148 register long *p;
1149 int i;
1150
1151 p = what;
1152 i = len;
1153 while (i) {
1154 *p = scale(*p);
1155 scale(*p); /* need this kludge for some compilers */
1156 p++;
1157 i--;
1158 }
1159 writearr(what, len);
1160 }
1161
1162 static void
writetfm(void)1163 writetfm(void) {
1164 lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np;
1165 write16((short)lf);
1166 write16((short)lh);
1167 write16((short)bc);
1168 write16((short)ec);
1169 write16((short)nw);
1170 write16((short)nh);
1171 write16((short)nd);
1172 write16((short)ni);
1173 write16((short)nl);
1174 write16((short)nk);
1175 write16((short)ne);
1176 write16((short)np);
1177 writearr(header, lh);
1178 writearr(charinfo, ec-bc+1);
1179 writesarr(width, nw);
1180 writesarr(height, nh);
1181 writesarr(depth, nd);
1182 writesarr(italic, ni);
1183 writearr(ligkern, nl);
1184 writesarr(kern, nk);
1185 writearr(tparam, np);
1186 }
1187
1188 /* OK, the TFM file is done! Now for our next trick, the VPL file. */
1189
1190 /* For TeX we want to compute a character height that works properly
1191 * with accents. The following list of accents doesn't need to be complete. */
1192 /*
1193 * We only do this if the xheight has a reasonable value.
1194 * (>50)
1195 */
1196 const char *accents[] = { "acute", "tilde", "caron", "dieresis", NULL};
1197 static int
texheight(register struct adobeinfo * ai)1198 texheight(register struct adobeinfo *ai)
1199 {
1200 register const char **p;
1201 register struct adobeinfo *aci, *acci;
1202 if (xheight <= 50 || *(ai->adobename + 1)) return (ai->ury);
1203 /* that was the simple case */
1204 for (p=accents; *p; p++) /* otherwise we look for accented letters */
1205 if (0 != (aci=findadobe(*p))) {
1206 strcpy(buffer,ai->adobename);
1207 strcat(buffer,*p);
1208 if (0 != (acci=findadobe(buffer)))
1209 return (acci->ury - aci->ury + xheight);
1210 }
1211 return (ai->ury);
1212 }
1213
1214 /* modified tgr to eliminate varargs problems */
1215
1216 #define vout(s) fprintf(vplout, s)
1217 int level; /* the depth of parenthesis nesting in VPL file being written */
1218 static void
vlevout(void)1219 vlevout(void)
1220 {
1221 register int l = level;
1222 while (l--) vout(" ");
1223 }
1224 static void
vlevnlout(void)1225 vlevnlout(void)
1226 {
1227 vout("\n");
1228 vlevout();
1229 }
1230 #define voutln(str) {fprintf(vplout,"%s\n",str);vlevout();}
1231 #define voutln2(f,s) {fprintf(vplout,f,s);vlevnlout();}
1232 #define voutln3(f,a,b) {fprintf(vplout,f,a,b);vlevnlout();}
1233 #define voutln4(f,a,b,c) {fprintf(vplout,f,a,b,c);vlevnlout();}
1234 static void
vleft(void)1235 vleft(void)
1236 {
1237 level++;
1238 vout("(");
1239 }
1240
1241 static void
vright(void)1242 vright(void)
1243 {
1244 level--;
1245 voutln(")");
1246 }
1247
1248 int forceoctal = 0;
1249
1250 char vcharbuf[100];
1251 static char *
vchar(int c)1252 vchar(int c)
1253 {
1254 if (forceoctal == 0 && ISALNUM (c))
1255 sprintf(vcharbuf,"C %c",
1256 #ifndef VMCMS
1257 c);
1258 #else
1259 ascii2ebcdic[c]);
1260 #endif
1261 else sprintf(vcharbuf,"O %o", (unsigned)c);
1262 return vcharbuf;
1263 }
1264
1265 char vnamebuf[1000];
1266 static char *
vname(int c)1267 vname(int c)
1268 {
1269 if (!forceoctal && ISALNUM (c)) {
1270 vnamebuf[0] = 0;
1271 } else if (c >= 0 && c < 256) {
1272 snprintf (vnamebuf, sizeof (vnamebuf),
1273 " (comment %s)", texptrs[c]->adobename);
1274 }
1275 return vnamebuf;
1276 }
1277
1278 static void
writevpl(void)1279 writevpl(void)
1280 {
1281 register int i, j, k;
1282 register struct adobeinfo *ai;
1283 register struct lig *nlig;
1284 register struct kern *nkern;
1285 register struct pcc *npcc;
1286 struct adobeinfo *asucc, *asub, *api;
1287 struct adobeptr *kern_eq;
1288 int xoff, yoff, ht;
1289 char unlabeled;
1290
1291 voutln2("(VTITLE Created by %s)", titlebuf);
1292 voutln("(COMMENT Please edit that VTITLE if you edit this file)");
1293 snprintf(obuffer, sizeof(obuffer), "TeX-%s%s%s%s", outname,
1294 (efactor==1.0? "" : "-E"), (slant==0.0? "" : "-S"),
1295 (makevpl==1? "" : "-CSC"));
1296 if (strlen(obuffer)>19) { /* too long, will retain first 9 and last 10 */
1297 register char *p, *q;
1298 for (p = &obuffer[9], q = &obuffer[strlen(obuffer)-10]; p<&obuffer[19];
1299 p++, q++) *p = *q;
1300 obuffer[19] = '\0';
1301 }
1302 voutln2("(FAMILY %s)" , obuffer);
1303 {
1304 char tbuf[300];
1305 const char *base_encoding =
1306 #ifndef VMCMS
1307 codingscheme;
1308 #else
1309 ebcodingscheme;
1310 #endif
1311
1312 if (strcmp (outencoding->name, base_encoding) == 0) {
1313 snprintf(tbuf, sizeof(tbuf), "%s", outencoding->name);
1314 } else {
1315 snprintf(tbuf, sizeof(tbuf), "%s + %s", base_encoding,
1316 outencoding->name);
1317 }
1318
1319 if (strlen(tbuf) > 39) {
1320 error("Coding scheme too long; shortening to 39 characters.");
1321 tbuf[39] = 0;
1322 }
1323 voutln2("(CODINGSCHEME %s)", tbuf);
1324 }
1325 voutln("(DESIGNSIZE R 10.0)");
1326 voutln("(DESIGNUNITS R 1000)");
1327 voutln("(COMMENT DESIGNSIZE (1 em) IS IN POINTS)");
1328 voutln("(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/1000)");
1329 /* Let vptovf compute the checksum. */
1330 /* voutln2("(CHECKSUM O %lo)",cksum ^ 0xffffffff); */
1331 if (boundarychar >= 0)
1332 voutln2("(BOUNDARYCHAR O %lo)", (unsigned long)boundarychar);
1333 vleft(); voutln("FONTDIMEN");
1334 if (newslant)
1335 voutln2("(SLANT R %f)", newslant);
1336 voutln2("(SPACE D %d)", fontspace);
1337 if (! fixedpitch) {
1338 voutln2("(STRETCH D %d)", transform(200,0));
1339 voutln2("(SHRINK D %d)", transform(100,0));
1340 }
1341 voutln2("(XHEIGHT D %d)", xheight);
1342 voutln2("(QUAD D %d)", transform(1000,0));
1343 voutln2("(EXTRASPACE D %d)", fixedpitch ? fontspace : transform(111, 0));
1344 vright();
1345 vleft(); voutln("MAPFONT D 0");
1346 voutln2("(FONTNAME %s)", outname);
1347 /* voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum); */
1348 vright();
1349 if (makevpl>1) {
1350 vleft(); voutln("MAPFONT D 1");
1351 voutln2("(FONTNAME %s)", outname);
1352 voutln2("(FONTAT D %d)", (int)(1000.0*capheight+0.5));
1353 /* voutln2("(FONTCHECKSUM O %lo)", (unsigned long)cksum); */
1354 vright();
1355 }
1356
1357 for (i=0; i<256 && texptrs[i]==NULL; i++);
1358 bc = i;
1359 for (i=255; i>=0 && texptrs[i]==NULL; i--);
1360 ec = i;
1361
1362 vleft(); voutln("LIGTABLE");
1363 ai = findadobe("||");
1364 unlabeled = 1;
1365 for (nlig=ai->ligs; nlig; nlig=nlig->next)
1366 if (0 != (asucc=findadobe(nlig->succ))) {
1367 if (0 != (asub=findadobe(nlig->sub)))
1368 if (asucc->texnum>=0)
1369 if (asub->texnum>=0) {
1370 if (unlabeled) {
1371 voutln("(LABEL BOUNDARYCHAR)");
1372 unlabeled = 0;
1373 }
1374 for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
1375 voutln4("(%s %s O %o)", vplligops[nlig->op],
1376 vchar(j), (unsigned)asub->texnum);
1377 }
1378 }
1379 }
1380 if (! unlabeled) voutln("(STOP)");
1381 for (i=bc; i<=ec; i++)
1382 if ((ai=texptrs[i]) && ai->texnum == i) {
1383 unlabeled = 1;
1384 if (uppercase[i]==NULL) /* omit ligatures from smallcap lowercase */
1385 for (nlig=ai->ligs; nlig; nlig=nlig->next)
1386 if (0 != (asucc=findadobe(nlig->succ)))
1387 if (0 != (asub=findadobe(nlig->sub)))
1388 if (asucc->texnum>=0)
1389 if (asub->texnum>=0) {
1390 if (unlabeled) {
1391 for (j = ai->texnum; j >= 0; j = nexttex[j])
1392 voutln3("(LABEL %s)%s", vchar(j), vname(j));
1393 unlabeled = 0;
1394 }
1395 for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
1396 voutln4("(%s %s O %o)", vplligops[nlig->op],
1397 vchar(j), (unsigned)asub->texnum);
1398 if (nlig->boundleft)
1399 break;
1400 }
1401 }
1402 for (nkern = (uppercase[i] ? uppercase[i]->kerns : ai->kerns);
1403 nkern; nkern=nkern->next)
1404 if (0 != (asucc=findadobe(nkern->succ)))
1405 for (j = asucc->texnum; j >= 0; j = nexttex[j]) {
1406 if (uppercase[j]==NULL) {
1407 if (unlabeled) {
1408 for (k = ai->texnum; k >= 0; k = nexttex[k])
1409 voutln3("(LABEL %s)%s", vchar(k), vname(k));
1410 unlabeled = 0;
1411 }
1412 /* If other characters have the same kerns as this
1413 one, output the label here. This makes the TFM
1414 file much smaller than if we output all the
1415 kerns again under a different label. */
1416 for (kern_eq = ai->kern_equivs; kern_eq;
1417 kern_eq = kern_eq->next) {
1418 k = kern_eq->ch->texnum;
1419 if (k >= 0 && k < 256)
1420 voutln3("(LABEL %s)%s", vchar(k), vname(k));
1421 }
1422 ai->kern_equivs = 0; /* Only output those labels once. */
1423 if (uppercase[i]) {
1424 if (lowercase[j]) {
1425 for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
1426 voutln4("(KRN %s R %.1f)%s", vchar(k),
1427 capheight*nkern->delta, vname(k));
1428 } else voutln4("(KRN %s R %.1f)%s",
1429 vchar(j), capheight*nkern->delta, vname(j));
1430 } else {
1431 voutln4("(KRN %s R %d)%s", vchar(j),
1432 nkern->delta, vname(j));
1433 if (lowercase[j])
1434 for (k=lowercase[j]->texnum; k >= 0; k = nexttex[k])
1435 voutln4("(KRN %s R %.1f)%s", vchar(k),
1436 capheight*nkern->delta, vname(k));
1437 }
1438 }
1439 }
1440 if (! unlabeled) voutln("(STOP)");
1441 }
1442 vright();
1443
1444 for (i=bc; i<=ec; i++)
1445 if (0 != (ai=texptrs[i])) {
1446 vleft(); fprintf(vplout, "CHARACTER %s", vchar(i));
1447 if (*vcharbuf=='C') {
1448 voutln("");
1449 } else
1450 voutln2(" (comment %s)", ai->adobename);
1451 if (uppercase[i]) {
1452 ai=uppercase[i];
1453 voutln2("(CHARWD R %.1f)", capheight * (ai->width));
1454 if (0 != (ht=texheight(ai)))
1455 voutln2("(CHARHT R %.1f)", capheight * ht);
1456 if (ai->lly)
1457 voutln2("(CHARDP R %.1f)", -capheight * ai->lly);
1458 if (ai->urx > ai->width)
1459 voutln2("(CHARIC R %.1f)", capheight * (ai->urx - ai->width));
1460 } else {
1461 voutln2("(CHARWD R %d)", ai->width);
1462 if (0 != (ht=texheight(ai)))
1463 voutln2("(CHARHT R %d)", ht);
1464 if (ai->lly)
1465 voutln2("(CHARDP R %d)", -ai->lly);
1466 if (ai->urx > ai->width)
1467 voutln2("(CHARIC R %d)", ai->urx - ai->width);
1468 }
1469 if (ai->adobenum != i || uppercase[i]) {
1470 vleft(); voutln("MAP");
1471 if (uppercase[i]) voutln("(SELECTFONT D 1)");
1472 if (ai->pccs && ai->adobenum < 0) {
1473 xoff = 0; yoff = 0;
1474 for (npcc = ai->pccs; npcc; npcc=npcc->next)
1475 if (0 != (api=findadobe(npcc->partname)))
1476 if (api->texnum>=0) {
1477 if (npcc->xoffset != xoff) {
1478 if (uppercase[i]) {
1479 voutln2("(MOVERIGHT R %.1f)",
1480 capheight * (npcc->xoffset - xoff));
1481 } else voutln2("(MOVERIGHT R %d)",
1482 npcc->xoffset - xoff);
1483 xoff = npcc->xoffset;
1484 }
1485 if (npcc->yoffset != yoff) {
1486 if (uppercase[i]) {
1487 voutln2("(MOVEUP R %.1f)",
1488 capheight * (npcc->yoffset - yoff));
1489 } else voutln2("(MOVEUP R %d)",
1490 npcc->yoffset - yoff);
1491 yoff = npcc->yoffset;
1492 }
1493 voutln2("(SETCHAR O %o)", (unsigned)api->adobenum);
1494 xoff += texptrs[api->texnum]->width;
1495 }
1496 } else voutln2("(SETCHAR O %o)", (unsigned)ai->adobenum);
1497 vright();
1498 }
1499 vright();
1500 }
1501 if (level) error("! I forgot to match the parentheses");
1502 }
1503
1504 #ifdef KPATHSEA
1505 static void
version(FILE * f)1506 version(FILE *f)
1507 {
1508 fputs ("afm2tfm(k) (dvips(k) 5.995) 8.3\n", f);
1509 fprintf (f, "%s\n", kpathsea_version_string);
1510 fputs ("Copyright 2015 Radical Eye Software.\n\
1511 There is NO warranty. You may redistribute this software\n\
1512 under the terms of the GNU General Public License\n\
1513 and the Dvips copyright.\n\
1514 For more information about these matters, see the files\n\
1515 named COPYING and afm2tfm.c.\n\
1516 Original author of afm2tfm: T. Rokicki.\n", f);
1517 }
1518
1519 #define USAGE "\
1520 Convert an Adobe font metric file to TeX font metric format.\n\
1521 \n\
1522 -c REAL use REAL for height of small caps made with -V [0.8]\n\
1523 -e REAL widen (extend) characters by a factor of REAL\n\
1524 -O use octal for all character codes in the vpl file\n\
1525 -p ENCFILE read/download ENCFILE for the PostScript encoding\n\
1526 -s REAL oblique (slant) characters by REAL, generally <<1\n\
1527 -t ENCFILE read ENCFILE for the encoding of the vpl file\n\
1528 -T ENCFILE equivalent to -p ENCFILE -t ENCFILE\n\
1529 -u output only characters from encodings, nothing extra\n\
1530 -v FILE[.vpl] make a VPL file for conversion to VF\n\
1531 -V SCFILE[.vpl] like -v, but synthesize smallcaps as lowercase\n\
1532 --help print this message and exit.\n\
1533 --version print version number and exit.\n\
1534 "
1535
1536 static void
usage(FILE * f)1537 usage(FILE *f)
1538 {
1539 fputs ("Usage: afm2tfm FILE[.afm] [OPTION]... [FILE[.tfm]]\n", f);
1540 fputs (USAGE, f);
1541 putc ('\n', f);
1542 fputs (kpse_bug_address, f);
1543 }
1544 #else /* ! KPATHSEA */
1545 static void
usage(FILE * f)1546 usage(FILE *f)
1547 {
1548 fprintf(f,
1549 "afm2tfm 8.1, Copyright 1990-97 by Radical Eye Software\n");
1550 fprintf(f,
1551 "Usage: afm2tfm foo[.afm] [-O] [-u] [-v|-V bar[.vpl]]\n");
1552 fprintf(f,
1553 " [-e expansion] [-s slant] [-c capheight]\n");
1554 fprintf(f,
1555 " [-p|-t|-T encodingfile] [foo[.tfm]]\n");
1556 }
1557 #endif
1558
1559 #define CHECKARG3 if (argc < 4) { usage(stderr); exit(1); }
1560
1561 static void
openfiles(int argc,char ** argv)1562 openfiles(int argc, char **argv)
1563 {
1564 #ifndef KPATHSEA
1565 register int lastext;
1566 #else
1567 const char *q;
1568 #endif
1569 register int i;
1570 const char *p;
1571 int arginc;
1572
1573 tfmout = (FILE *)NULL;
1574
1575 if (argc == 1) {
1576 usage(stdout);
1577 exit(0);
1578 }
1579
1580 #if defined(MSDOS) || defined(OS2) || defined(ATARIST)
1581 /* Make VPL file identical to that created under Unix */
1582 snprintf(titlebuf, sizeof(titlebuf), "afm2tfm %s", argv[1]);
1583 #else
1584 #ifdef VMCMS
1585 /* Make VPL file identical to that created under Unix */
1586 snprintf(titlebuf, sizeof(titlebuf), "afm2tfm %s", argv[1]);
1587 #else
1588 snprintf(titlebuf, sizeof(titlebuf), "%s %s", argv[0], argv[1]);
1589 #endif
1590 #endif
1591 strcpy(inname, argv[1]);
1592 #ifdef KPATHSEA
1593 if (find_suffix(inname) == NULL)
1594 strcat(inname, ".afm");
1595 #else
1596 lastext = -1;
1597 for (i=0; inname[i]; i++)
1598 if (inname[i] == '.')
1599 lastext = i;
1600 else if (inname[i] == '/' || inname[i] == ':')
1601 lastext = -1;
1602 if (lastext == -1) strcat(inname, ".afm");
1603 #endif
1604 while (argc>2 && *argv[2]=='-') {
1605 arginc = 2;
1606 i = argv[2][1];
1607 if (i == '/')
1608 i = argv[2][2] - 32; /* /a ==> A for VMS */
1609 switch (i) {
1610 case 'V': makevpl++;
1611 case 'v': makevpl++;
1612 CHECKARG3
1613 strcpy(outname, argv[3]);
1614 #ifdef KPATHSEA
1615 if (find_suffix(outname) == NULL)
1616 strcat(outname, ".vpl");
1617 #else
1618 lastext = -1;
1619 for (i=0; outname[i]; i++)
1620 if (outname[i] == '.')
1621 lastext = i;
1622 else if (outname[i] == '/' || outname[i] == ':')
1623 lastext = -1;
1624 if (lastext == -1) strcat(outname, ".vpl");
1625 #endif
1626 #ifndef VMCMS
1627 #ifndef ATARIST
1628 if ((vplout=fopen(outname, WRITEBIN))==NULL)
1629 #else
1630 if ((vplout=fopen(outname, "w"))==NULL)
1631 #endif
1632 #else
1633 if ((vplout=fopen(outname, "w"))==NULL)
1634 #endif
1635 error("! can't open vpl output file");
1636 break;
1637 case 'e': CHECKARG3
1638 if (sscanf(argv[3], "%f", &efactor)==0 || efactor<0.01)
1639 error("! Bad extension factor");
1640 efactorparam = argv[3];
1641 break;
1642 case 'c':
1643 CHECKARG3
1644 if (sscanf(argv[3], "%f", &capheight)==0 || capheight<0.01)
1645 error("! Bad small caps height");
1646 break;
1647 case 's':
1648 CHECKARG3
1649 if (sscanf(argv[3], "%f", &slant)==0)
1650 error("! Bad slant parameter");
1651 slantparam = argv[3];
1652 break;
1653 case 'P':
1654 case 'p':
1655 CHECKARG3
1656 inenname = argv[3];
1657 break;
1658 case 'T':
1659 CHECKARG3
1660 inenname = outenname = argv[3];
1661 break;
1662 case 't':
1663 CHECKARG3
1664 outenname = argv[3];
1665 break;
1666 case 'O':
1667 forceoctal = 1;
1668 arginc = 1;
1669 break;
1670 case 'u':
1671 pedantic = 1;
1672 arginc = 1;
1673 break;
1674 default: fprintf(stderr, "Unknown option %s %s ignored.\n", argv[2], argv[3]);
1675 }
1676 for (i=0; i<arginc; i++) {
1677 snprintf(titlebuf + strlen(titlebuf),
1678 sizeof(titlebuf) - strlen(titlebuf), " %s", argv[2]);
1679 argv++;
1680 argc--;
1681 }
1682 }
1683
1684 #ifdef KPATHSEA
1685 afmin = kpse_open_file (inname, kpse_afm_format);
1686 #else /* ! KPATHSEA */
1687 if ((afmin=fopen(inname, "r"))==NULL)
1688 error("! can't open afm input file");
1689 #endif /* KPATHSEA */
1690 SET_BINARY(fileno(afmin));
1691
1692 if (argc>3 || (argc==3 && *argv[2]=='-')) {
1693 error("! need at most two non-option arguments");
1694 usage(stderr);
1695 }
1696
1697 if (argc == 2) strcpy(outname, inname);
1698 else strcpy(outname, argv[2]);
1699
1700 #ifdef KPATHSEA
1701 if ((p = find_suffix(outname)) != NULL)
1702 outname[p-outname-1] = 0;
1703 strcat(outname, ".tfm");
1704 if (tfmout == NULL && (tfmout=fopen(outname, WRITEBIN))==NULL)
1705 error("! can't open tfm output file");
1706 /*
1707 * Now we strip off any directory information, so we only use the
1708 * base name in the vf file.
1709 */
1710 if (p == NULL)
1711 p = find_suffix(outname);
1712 outname[p-outname-1] = 0;
1713
1714 q = xbasename(outname);
1715 strcpy(tmpstr, q); /* be careful, q and outname are overlapping */
1716 strcpy(outname, tmpstr);
1717 #else
1718 lastext = -1;
1719 for (i=0; outname[i]; i++)
1720 if (outname[i] == '.')
1721 lastext = i;
1722 else if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
1723 lastext = -1;
1724 if (argc == 2) {
1725 outname[lastext] = 0;
1726 lastext = -1;
1727 }
1728 if (lastext == -1) {
1729 lastext = strlen(outname);
1730 strcat(outname, ".tfm");
1731 }
1732 if (tfmout == NULL && (tfmout=fopen(outname, WRITEBIN))==NULL)
1733 error("! can't open tfm output file");
1734 outname[lastext] = 0;
1735 /*
1736 * Now we strip off any directory information, so we only use the
1737 * base name in the vf file. We accept any of /, :, or \ as directory
1738 * delimiters, so none of these are available for use inside the
1739 * base name; this shouldn't be a problem.
1740 */
1741 for (i=0, lastext=0; outname[i]; i++)
1742 if (outname[i] == '/' || outname[i] == ':' || outname[i] == '\\')
1743 lastext = i + 1;
1744 if (lastext)
1745 strcpy(outname, outname + lastext);
1746 #endif
1747 }
1748 /*
1749 * Some routines to remove kerns that match certain patterns.
1750 */
1751 static struct kern *
rmkernmatch(struct kern * k,char * s)1752 rmkernmatch(struct kern *k, char *s)
1753 {
1754 struct kern *nkern;
1755
1756 while (k && strcmp(k->succ, s)==0)
1757 k = k->next;
1758 if (k) {
1759 for (nkern = k; nkern; nkern = nkern->next)
1760 while (nkern->next && strcmp(nkern->next->succ, s)==0)
1761 nkern->next = nkern->next->next;
1762 }
1763 return k;
1764 }
1765 /*
1766 * Recursive to one level.
1767 */
1768 static void
rmkern(char * s1,char * s2,struct adobeinfo * ai)1769 rmkern(char *s1, char *s2, struct adobeinfo *ai)
1770 {
1771 if (ai == 0) {
1772 if (strcmp(s1, "*") == 0) {
1773 for (ai=adobechars; ai; ai = ai->next)
1774 rmkern(s1, s2, ai);
1775 return;
1776 } else {
1777 ai = findadobe(s1);
1778 if (ai == 0)
1779 return;
1780 }
1781 }
1782 if (strcmp(s2, "*")==0)
1783 ai->kerns = 0; /* drop them on the floor */
1784 else
1785 ai->kerns = rmkernmatch(ai->kerns, s2);
1786 }
1787
1788 /* Make the kerning for character S1 equivalent to that for S2.
1789 If either S1 or S2 do not exist, do nothing.
1790 If S1 already has kerning, do nothing. */
1791 static void
addkern(char * s1,char * s2)1792 addkern(char *s1, char *s2)
1793 {
1794 struct adobeinfo *ai1 = findadobe (s1);
1795 struct adobeinfo *ai2 = findadobe (s2);
1796 if (ai1 && ai2 && !ai1->kerns) {
1797 /* Put the new one at the head of the list, since order is immaterial. */
1798 struct adobeptr *ap
1799 = (struct adobeptr *) mymalloc((unsigned long)sizeof(struct adobeptr));
1800 ap->next = ai2->kern_equivs;
1801 ap->ch = ai1;
1802 ai2->kern_equivs = ap;
1803 }
1804 }
1805 int sawligkern;
1806 /*
1807 * Reads a ligkern line, if this is one. Assumes the first character
1808 * passed is `%'.
1809 */
1810 static void
checkligkern(char * s)1811 checkligkern(char *s)
1812 {
1813 char *oparam = param;
1814 char *mlist[5];
1815 int n;
1816
1817 s++;
1818 while (*s && *s <= ' ')
1819 s++;
1820 if (strncmp(s, "LIGKERN", 7)==0) {
1821 sawligkern = 1;
1822 s += 7;
1823 while (*s && *s <= ' ')
1824 s++;
1825 param = s;
1826 while (*param) {
1827 for (n=0; n<5;) {
1828 if (*param == 0)
1829 break;
1830 mlist[n] = paramstring();
1831 if (strcmp(mlist[n], ";") == 0)
1832 break;
1833 n++;
1834 }
1835 if (n > 4)
1836 error("! too many parameters in lig kern data");
1837 if (n < 3)
1838 error("! too few parameters in lig kern data");
1839 if (n == 3 && strcmp(mlist[1], "{}") == 0) { /* rmkern command */
1840 rmkern(mlist[0], mlist[2], (struct adobeinfo *)0);
1841 } else if (n == 3 && strcmp(mlist[1], "<>") == 0) { /* addkern */
1842 addkern(mlist[0], mlist[2]);
1843 } else if (n == 3 && strcmp(mlist[0], "||") == 0 &&
1844 strcmp(mlist[1], "=") == 0) { /* bc command */
1845 struct adobeinfo *ai = findadobe("||");
1846
1847 if (boundarychar != -1)
1848 error("! multiple boundary character commands?");
1849 if (sscanf(mlist[2], "%d", &n) != 1)
1850 error("! expected number assignment for boundary char");
1851 if (n < 0 || n > 255)
1852 error("! boundary character number must be 0..255");
1853 boundarychar = n;
1854 if (ai == 0)
1855 error("! internal error: boundary char");
1856 ai->texnum = n; /* prime the pump, so to speak, for lig/kerns */
1857 } else if (n == 4) {
1858 int op = -1;
1859 struct adobeinfo *ai;
1860
1861 for (n=0; encligops[n]; n++)
1862 if (strcmp(mlist[2], encligops[n])==0) {
1863 op = n;
1864 break;
1865 }
1866 if (op < 0)
1867 error("! bad ligature op specified");
1868 if (0 != (ai = findadobe(mlist[0]))) {
1869 struct lig *lig;
1870
1871 if (findadobe(mlist[2])) /* remove coincident kerns */
1872 rmkern(mlist[0], mlist[1], ai);
1873 if (strcmp(mlist[3], "||") == 0)
1874 error("! you can't lig to the boundary character!");
1875 if (! fixedpitch) { /* fixed pitch fonts get *0* ligs */
1876 for (lig=ai->ligs; lig; lig = lig->next)
1877 if (strcmp(lig->succ, mlist[1]) == 0)
1878 break; /* we'll re-use this structure */
1879 if (lig == 0) {
1880 lig = newlig();
1881 lig->succ = newstring(mlist[1]);
1882 lig->next = ai->ligs;
1883 ai->ligs = lig;
1884 }
1885 lig->sub = newstring(mlist[3]);
1886 lig->op = op;
1887 if (strcmp(mlist[1], "||")==0) {
1888 lig->boundleft = 1;
1889 if (strcmp(mlist[0], "||")==0)
1890 error("! you can't lig boundarychar boundarychar!");
1891 } else
1892 lig->boundleft = 0;
1893 }
1894 }
1895 } else
1896 error("! bad form in LIGKERN command");
1897 }
1898 }
1899 param = oparam;
1900 }
1901 /*
1902 * Here we get a token from the AFM file. We parse just as much PostScript
1903 * as we expect to find in an encoding file. We allow commented lines and
1904 * names like 0, .notdef, _foo_. We do not allow //abc.
1905 */
1906 char smbuffer[100]; /* for tokens */
1907 static char *
gettoken(void)1908 gettoken(void) {
1909 char *p, *q;
1910
1911 while (1) {
1912 while (param == 0 || *param == 0) {
1913 if (texlive_getline() == 0)
1914 error("! premature end in encoding file");
1915 for (p=buffer; *p; p++)
1916 if (*p == '%') {
1917 if (ignoreligkern == 0)
1918 checkligkern(p);
1919 *p = 0;
1920 break;
1921 }
1922 }
1923 while (*param && *param <= ' ')
1924 param++;
1925 if (*param) {
1926 if (*param == '[' || *param == ']' ||
1927 *param == '{' || *param == '}') {
1928 smbuffer[0] = *param++;
1929 smbuffer[1] = 0;
1930 return smbuffer;
1931 } else if (*param == '/' || *param == '-' || *param == '_' ||
1932 *param == '.' ||
1933 ('0' <= *param && *param <= '9') ||
1934 ('a' <= *param && *param <= 'z') ||
1935 ('A' <= *param && *param <= 'Z')) {
1936 smbuffer[0] = *param;
1937 for (p=param+1, q=smbuffer+1;
1938 *p == '-' || *p == '_' || *p == '.' ||
1939 ('0' <= *p && *p <= '9') ||
1940 ('a' <= *p && *p <= 'z') ||
1941 ('A' <= *p && *p <= 'Z'); p++, q++)
1942 *q = *p;
1943 *q = 0;
1944 param = p;
1945 return smbuffer;
1946 }
1947 }
1948 }
1949 }
1950 static void
getligkerndefaults(void)1951 getligkerndefaults(void) {
1952 int i;
1953
1954 for (i=0; staticligkern[i]; i++) {
1955 strcpy(buffer, staticligkern[i]);
1956 strcpy(obuffer, staticligkern[i]);
1957 param = buffer;
1958 checkligkern(buffer);
1959 }
1960 }
1961 /*
1962 * This routine reads in an encoding file, given the name. It returns
1963 * the final total structure. It performs a number of consistency checks.
1964 */
1965 static struct encoding *
readencoding(char * enc)1966 readencoding(char *enc)
1967 {
1968 char *p;
1969 int i;
1970 struct encoding *e =
1971 (struct encoding *)mymalloc((unsigned long)sizeof(struct encoding));
1972
1973 sawligkern = 0;
1974 if (afmin)
1975 error("! oops; internal afmin error");
1976 if (enc) {
1977 #ifdef KPATHSEA
1978 afmin = kpse_open_file(enc, kpse_enc_format);
1979 #else
1980 afmin = fopen(enc, "r");
1981 #endif
1982 SET_BINARY(fileno(afmin));
1983 param = 0;
1984 if (afmin == 0)
1985 #ifdef KPATHSEA
1986 FATAL1 ("couldn't open encoding file `%s'", enc);
1987 #else
1988 error("! couldn't open that encoding file");
1989 #endif
1990 p = gettoken();
1991 if (*p != '/' || p[1] == 0)
1992 error("! first token in encoding must be literal encoding name");
1993 e->name = newstring(p+1);
1994 p = gettoken();
1995 if (strcmp(p, "["))
1996 error("! second token in encoding must be mark ([) token");
1997 for (i=0; i<256; i++) {
1998 p = gettoken();
1999 if (*p != '/' || p[1] == 0)
2000 error("! tokens 3 to 257 in encoding must be literal names");
2001 e->vec[i] = newstring(p+1);
2002 }
2003 p = gettoken();
2004 if (strcmp(p, "]"))
2005 error("! token 258 in encoding must be make-array (])");
2006 while (texlive_getline()) {
2007 for (p=buffer; *p; p++)
2008 if (*p == '%') {
2009 if (ignoreligkern == 0)
2010 checkligkern(p);
2011 *p = 0;
2012 break;
2013 }
2014 }
2015 fclose(afmin);
2016 afmin = 0;
2017 if (ignoreligkern == 0 && sawligkern == 0)
2018 getligkerndefaults();
2019 } else {
2020 e = &staticencoding;
2021 getligkerndefaults();
2022 }
2023 param = 0;
2024 return e;
2025 }
2026 /*
2027 * This routine prints out the line that needs to be added to psfonts.map.
2028 */
2029 static void
conspsfonts(void)2030 conspsfonts(void) {
2031 #ifndef VMCMS
2032 printf("%s %s", outname,
2033 fontname);
2034 #else /* VM/CMS: fontname is ascii, so we use ebfontname */
2035 printf("%s %s", outname,
2036 ebfontname);
2037 #endif
2038 if (slantparam || efactorparam || inenname) {
2039 printf(" \"");
2040 if (slantparam)
2041 printf(" %s SlantFont", slantparam);
2042 if (efactorparam)
2043 printf(" %s ExtendFont", efactorparam);
2044 if (inenname)
2045 printf(" %s ReEncodeFont", inencoding->name);
2046 printf(" \"");
2047 if (inenname)
2048 printf(" <%s", inenname);
2049 }
2050 printf("\n");
2051 }
2052 #ifndef VMS
2053 int
2054 #endif
main(int argc,char ** argv)2055 main(int argc, char **argv)
2056 {
2057 int i;
2058
2059 #ifdef KPATHSEA
2060 kpse_set_program_name (argv[0], "afm2tfm");
2061
2062 if (argc == 1) {
2063 fputs ("afm2tfm: Need at least one file argument.\n", stderr);
2064 fputs ("Try `afm2tfm --help' for more information.\n", stderr);
2065 exit(1);
2066 }
2067 if (argc == 2) {
2068 if (strcmp (argv[1], "--help") == 0) {
2069 usage (stdout);
2070 exit (0);
2071 } else if (strcmp (argv[1], "--version") == 0) {
2072 version (stdout);
2073 exit (0);
2074 }
2075 }
2076 #endif /* KPATHSEA */
2077 for (i=0; i<256; i++)
2078 nexttex[i] = -1; /* encoding chains have length 0 */
2079 tfmdata = (long *)mymalloc((unsigned long)40000L);
2080 openfiles(argc, argv);
2081 readadobe();
2082 if (fontspace == 0) {
2083 struct adobeinfo *ai;
2084
2085 if (0 != (ai = findadobe("space")))
2086 fontspace = ai->width;
2087 else if (adobeptrs[32])
2088 fontspace = adobeptrs[32]->width;
2089 else
2090 fontspace = transform(500, 0);
2091 }
2092 handlereencoding();
2093 buildtfm();
2094 writetfm();
2095 conspsfonts();
2096 if (makevpl) {
2097 assignchars();
2098 if (makevpl>1) upmap();
2099 writevpl();
2100 }
2101 return 0;
2102 /*NOTREACHED*/
2103 }
2104
2105