1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4 
5 This file is part of groff.
6 
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11 
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 
21 /* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
22 but I haven't tested them. */
23 
24 /* Groff requires more font metric information than TeX.  The reason
25 for this is that TeX has separate Math Italic fonts, whereas groff
26 uses normal italic fonts for math.  The two additional pieces of
27 information required by groff correspond to the two arguments to the
28 math_fit() macro in the Metafont programs for the CM fonts. In the
29 case of a font for which math_fitting is false, these two arguments
30 are normally ignored by Metafont. We need to get hold of these two
31 parameters and put them in the groff font file.
32 
33 We do this by loading this definition after cmbase when creating cm.base.
34 
35 def ignore_math_fit(expr left_adjustment,right_adjustment) =
36  special "adjustment";
37  numspecial left_adjustment*16/designsize;
38  numspecial right_adjustment*16/designsize;
39  enddef;
40 
41 This puts the two arguments to the math_fit macro into the gf file.
42 (They will appear in the gf file immediately before the character to
43 which they apply.)  We then create a gf file using this cm.base.  Then
44 we run tfmtodit and specify this gf file with the -g option.
45 
46 This need only be done for a font for which math_fitting is false;
47 When it's true, the left_correction and subscript_correction should
48 both be zero. */
49 
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <math.h>
54 #include <string.h>
55 #include <errno.h>
56 #include "lib.h"
57 #include "errarg.h"
58 #include "error.h"
59 #include "assert.h"
60 #include "cset.h"
61 
62 /* Values in the tfm file should be multiplied by this. */
63 
64 #define MULTIPLIER 1
65 
66 struct char_info_word {
67   unsigned char width_index;
68   char height_index;
69   char depth_index;
70   char italic_index;
71   char tag;
72   unsigned char remainder;
73 };
74 
75 struct lig_kern_command {
76   unsigned char skip_byte;
77   unsigned char next_char;
78   unsigned char op_byte;
79   unsigned char remainder;
80 };
81 
82 class tfm {
83   int bc;
84   int ec;
85   int nw;
86   int nh;
87   int nd;
88   int ni;
89   int nl;
90   int nk;
91   int np;
92   int cs;
93   int ds;
94   char_info_word *char_info;
95   int *width;
96   int *height;
97   int *depth;
98   int *italic;
99   lig_kern_command *lig_kern;
100   int *kern;
101   int *param;
102 public:
103   tfm();
104   ~tfm();
105   int load(const char *);
106   int contains(int);
107   int get_width(int);
108   int get_height(int);
109   int get_depth(int);
110   int get_italic(int);
111   int get_param(int, int *);
112   int get_checksum();
113   int get_design_size();
114   int get_lig(unsigned char, unsigned char, unsigned char *);
115   friend class kern_iterator;
116 };
117 
118 class kern_iterator {
119   tfm *t;
120   int c;
121   int i;
122 public:
123   kern_iterator(tfm *);
124   int next(unsigned char *c1, unsigned char *c2, int *k);
125 };
126 
127 
128 kern_iterator::kern_iterator(tfm *p)
129 : t(p), i(-1), c(t->bc)
130 {
131 }
132 
133 int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
134 {
135   for (; c <= t->ec; c++)
136     if (t->char_info[c - t->bc].tag == 1) {
137       if (i < 0) {
138 	i = t->char_info[c - t->bc].remainder;
139 	if (t->lig_kern[i].skip_byte > 128)
140 	  i = (256*t->lig_kern[i].op_byte
141 		   + t->lig_kern[i].remainder);
142       }
143       for (;;) {
144 	int skip = t->lig_kern[i].skip_byte;
145 	if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
146 	  *c1 = c;
147 	  *c2 = t->lig_kern[i].next_char;
148 	  *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
149 		       + t->lig_kern[i].remainder];
150 	  if (skip == 128) {
151 	    c++;
152 	    i = -1;
153 	  }
154 	  else
155 	    i += skip + 1;
156 	  return 1;
157 	}
158 	if (skip >= 128)
159 	  break;
160 	i += skip + 1;
161       }
162       i = -1;
163     }
164   return 0;
165 }
166 
167 tfm::tfm()
168 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
169   kern(0), param(0)
170 {
171 }
172 
173 int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
174 {
175   if (contains(c1) && char_info[c1 - bc].tag == 1) {
176     int i = char_info[c1 - bc].remainder;
177     if (lig_kern[i].skip_byte > 128)
178       i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
179     for (;;) {
180       int skip = lig_kern[i].skip_byte;
181       if (skip > 128)
182 	break;
183       // We are only interested in normal ligatures, for which
184       // op_byte == 0.
185       if (lig_kern[i].op_byte == 0
186 	  && lig_kern[i].next_char == c2) {
187 	*cp = lig_kern[i].remainder;
188 	return 1;
189       }
190       if (skip == 128)
191 	break;
192       i += skip + 1;
193     }
194   }
195   return 0;
196 }
197 
198 int tfm::contains(int i)
199 {
200   return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
201 }
202 
203 int tfm::get_width(int i)
204 {
205   return width[char_info[i - bc].width_index];
206 }
207 
208 int tfm::get_height(int i)
209 {
210   return height[char_info[i - bc].height_index];
211 }
212 
213 int tfm::get_depth(int i)
214 {
215   return depth[char_info[i - bc].depth_index];
216 }
217 
218 int tfm::get_italic(int i)
219 {
220   return italic[char_info[i - bc].italic_index];
221 }
222 
223 int tfm::get_param(int i, int *p)
224 {
225   if (i <= 0 || i > np)
226     return 0;
227   else {
228     *p = param[i - 1];
229     return 1;
230   }
231 }
232 
233 int tfm::get_checksum()
234 {
235   return cs;
236 }
237 
238 int tfm::get_design_size()
239 {
240   return ds;
241 }
242 
243 tfm::~tfm()
244 {
245   a_delete char_info;
246   a_delete width;
247   a_delete height;
248   a_delete depth;
249   a_delete italic;
250   a_delete lig_kern;
251   a_delete kern;
252   a_delete param;
253 }
254 
255 int read2(unsigned char *&s)
256 {
257   int n;
258   n = *s++ << 8;
259   n |= *s++;
260   return n;
261 }
262 
263 int read4(unsigned char *&s)
264 {
265   int n;
266   n = *s++ << 24;
267   n |= *s++ << 16;
268   n |= *s++ << 8;
269   n |= *s++;
270   return n;
271 }
272 
273 
274 int tfm::load(const char *file)
275 {
276   errno = 0;
277   FILE *fp = fopen(file, "r");
278   if (!fp) {
279     error("can't open `%1': %2", file, strerror(errno));
280     return 0;
281   }
282   int c1 = getc(fp);
283   int c2 = getc(fp);
284   if (c1 == EOF || c2 == EOF) {
285     fclose(fp);
286     error("unexpected end of file on `%1'", file);
287     return 0;
288   }
289   int lf = (c1 << 8) + c2;
290   int toread = lf*4 - 2;
291   unsigned char *buf = new unsigned char[toread];
292   if (fread(buf, 1, toread, fp) != toread) {
293     if (feof(fp))
294       error("unexpected end of file on `%1'", file);
295     else
296       error("error on file `%1'", file);
297     a_delete buf;
298     fclose(fp);
299     return 0;
300   }
301   fclose(fp);
302   if (lf < 6) {
303     error("bad tfm file `%1': impossibly short", file);
304     a_delete buf;
305     return 0;
306   }
307   unsigned char *ptr = buf;
308   int lh = read2(ptr);
309   bc = read2(ptr);
310   ec = read2(ptr);
311   nw = read2(ptr);
312   nh = read2(ptr);
313   nd = read2(ptr);
314   ni = read2(ptr);
315   nl = read2(ptr);
316   nk = read2(ptr);
317   int ne = read2(ptr);
318   np = read2(ptr);
319   if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
320     error("bad tfm file `%1': lengths do not sum", file);
321     a_delete buf;
322     return 0;
323   }
324   if (lh < 2) {
325     error("bad tfm file `%1': header too short", file);
326     a_delete buf;
327     return 0;
328   }
329   char_info = new char_info_word[ec - bc + 1];
330   width = new int[nw];
331   height = new int[nh];
332   depth = new int[nd];
333   italic = new int[ni];
334   lig_kern = new lig_kern_command[nl];
335   kern = new int[nk];
336   param = new int[np];
337   int i;
338   cs = read4(ptr);
339   ds = read4(ptr);
340   ptr += (lh-2)*4;
341   for (i = 0; i < ec - bc + 1; i++) {
342     char_info[i].width_index = *ptr++;
343     unsigned char tem = *ptr++;
344     char_info[i].depth_index = tem & 0xf;
345     char_info[i].height_index = tem >> 4;
346     tem = *ptr++;
347     char_info[i].italic_index = tem >> 2;
348     char_info[i].tag = tem & 3;
349     char_info[i].remainder = *ptr++;
350   }
351   for (i = 0; i < nw; i++)
352     width[i] = read4(ptr);
353   for (i = 0; i < nh; i++)
354     height[i] = read4(ptr);
355   for (i = 0; i < nd; i++)
356     depth[i] = read4(ptr);
357   for (i = 0; i < ni; i++)
358     italic[i] = read4(ptr);
359   for (i = 0; i < nl; i++) {
360     lig_kern[i].skip_byte = *ptr++;
361     lig_kern[i].next_char = *ptr++;
362     lig_kern[i].op_byte = *ptr++;
363     lig_kern[i].remainder = *ptr++;
364   }
365   for (i = 0; i < nk; i++)
366     kern[i] = read4(ptr);
367   ptr += ne*4;
368   for (i = 0; i < np; i++)
369     param[i] = read4(ptr);
370   assert(ptr == buf + lf*4 - 2);
371   a_delete buf;
372   return 1;
373 }
374 
375 class gf {
376   int left[256];
377   int right[256];
378   static int sread4(int *p, FILE *fp);
379   static int uread3(int *p, FILE *fp);
380   static int uread2(int *p, FILE *fp);
381   static int skip(int n, FILE *fp);
382 public:
383   gf();
384   int load(const char *file);
385   int get_left_adjustment(int i) { return left[i]; }
386   int get_right_adjustment(int i) { return right[i]; }
387 };
388 
389 gf::gf()
390 {
391   for (int i = 0; i < 256; i++)
392     left[i] = right[i] = 0;
393 }
394 
395 int gf::load(const char *file)
396 {
397   enum {
398     paint_0 = 0,
399     paint1 = 64,
400     boc = 67,
401     boc1 = 68,
402     eoc = 69,
403     skip0 = 70,
404     skip1 = 71,
405     new_row_0 = 74,
406     xxx1 = 239,
407     yyy = 243,
408     no_op = 244,
409     pre = 247,
410     post = 248
411   };
412   int got_an_adjustment = 0;
413   int pending_adjustment = 0;
414   int left_adj, right_adj;
415   const int gf_id_byte = 131;
416   errno = 0;
417   FILE *fp = fopen(file, "r");
418   if (!fp) {
419     error("can't open `%1': %2", file, strerror(errno));
420     return 0;
421   }
422   if (getc(fp) != pre || getc(fp) != gf_id_byte) {
423     error("bad gf file");
424     return 0;
425   }
426   int n = getc(fp);
427   if (n == EOF)
428     goto eof;
429   if (!skip(n, fp))
430     goto eof;
431   for (;;) {
432     int op = getc(fp);
433     if (op == EOF)
434       goto eof;
435     if (op == post)
436       break;
437     if ((op >= paint_0 && op <= paint_0 + 63)
438 	|| (op >= new_row_0 && op <= new_row_0 + 164))
439       continue;
440     switch (op) {
441     case no_op:
442     case eoc:
443     case skip0:
444       break;
445     case paint1:
446     case skip1:
447       if (!skip(1, fp))
448 	goto eof;
449       break;
450     case paint1 + 1:
451     case skip1 + 1:
452       if (!skip(2, fp))
453 	goto eof;
454       break;
455     case paint1 + 2:
456     case skip1 + 2:
457       if (!skip(3, fp))
458 	goto eof;
459       break;
460     case boc:
461       {
462 	int code;
463 	if (!sread4(&code, fp))
464 	  goto eof;
465 	if (pending_adjustment) {
466 	  pending_adjustment = 0;
467 	  left[code & 0377] = left_adj;
468 	  right[code & 0377] = right_adj;
469 	}
470 	if (!skip(20, fp))
471 	  goto eof;
472 	break;
473       }
474     case boc1:
475       {
476 	int code = getc(fp);
477 	if (code == EOF)
478 	  goto eof;
479 	if (pending_adjustment) {
480 	  pending_adjustment = 0;
481 	  left[code] = left_adj;
482 	  right[code] = right_adj;
483 	}
484 	if (!skip(4, fp))
485 	  goto eof;
486 	break;
487       }
488     case xxx1:
489       {
490 	int len = getc(fp);
491 	if (len == EOF)
492 	  goto eof;
493 	char buf[256];
494 	if (fread(buf, 1, len, fp) != len)
495 	  goto eof;
496 	if (len == 10 /* strlen("adjustment") */
497 	    && memcmp(buf, "adjustment", len) == 0) {
498 	  int c = getc(fp);
499 	  if (c != yyy) {
500 	    if (c != EOF)
501 	      ungetc(c, fp);
502 	    break;
503 	  }
504 	  if (!sread4(&left_adj, fp))
505 	    goto eof;
506 	  c = getc(fp);
507 	  if (c != yyy) {
508 	    if (c != EOF)
509 	      ungetc(c, fp);
510 	    break;
511 	  }
512 	  if (!sread4(&right_adj, fp))
513 	    goto eof;
514 	  got_an_adjustment = 1;
515 	  pending_adjustment = 1;
516 	}
517 	break;
518       }
519     case xxx1 + 1:
520       if (!uread2(&n, fp) || !skip(n, fp))
521 	goto eof;
522       break;
523     case xxx1 + 2:
524       if (!uread3(&n, fp) || !skip(n, fp))
525 	goto eof;
526       break;
527     case xxx1 + 3:
528       if (!sread4(&n, fp) || !skip(n, fp))
529 	goto eof;
530       break;
531     case yyy:
532       if (!skip(4, fp))
533 	goto eof;
534       break;
535     default:
536       fatal("unrecognized opcode `%1'", op);
537       break;
538     }
539   }
540   if (!got_an_adjustment)
541     warning("no adjustment specials found in gf file");
542   return 1;
543  eof:
544   error("unexpected end of file");
545   return 0;
546 }
547 
548 int gf::sread4(int *p, FILE *fp)
549 {
550   *p = getc(fp);
551   if (*p >= 128)
552     *p -= 256;
553   *p <<= 8;
554   *p |= getc(fp);
555   *p <<= 8;
556   *p |= getc(fp);
557   *p <<= 8;
558   *p |= getc(fp);
559   return !ferror(fp) && !feof(fp);
560 }
561 
562 int gf::uread3(int *p, FILE *fp)
563 {
564   *p = getc(fp);
565   *p <<= 8;
566   *p |= getc(fp);
567   *p <<= 8;
568   *p |= getc(fp);
569   return !ferror(fp) && !feof(fp);
570 }
571 
572 int gf::uread2(int *p, FILE *fp)
573 {
574   *p = getc(fp);
575   *p <<= 8;
576   *p |= getc(fp);
577   return !ferror(fp) && !feof(fp);
578 }
579 
580 int gf::skip(int n, FILE *fp)
581 {
582   while (--n >= 0)
583     if (getc(fp) == EOF)
584       return 0;
585   return 1;
586 }
587 
588 
589 struct char_list {
590   char *ch;
591   char_list *next;
592   char_list(const char *, char_list * = 0);
593 };
594 
595 char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
596 {
597 }
598 
599 
600 int read_map(const char *file, char_list **table)
601 {
602   errno = 0;
603   FILE *fp = fopen(file, "r");
604   if (!fp) {
605     error("can't open `%1': %2", file, strerror(errno));
606     return 0;
607   }
608   for (int i = 0; i < 256; i++)
609     table[i] = 0;
610   char buf[512];
611   int lineno = 0;
612   while (fgets(buf, int(sizeof(buf)), fp)) {
613     lineno++;
614     char *ptr = buf;
615     while (csspace(*ptr))
616       ptr++;
617     if (*ptr == '\0' || *ptr == '#')
618       continue;
619     ptr = strtok(ptr, " \n\t");
620     if (!ptr)
621       continue;
622     int n;
623     if (sscanf(ptr, "%d", &n) != 1) {
624       error("%1:%2: bad map file", file, lineno);
625       fclose(fp);
626       return 0;
627     }
628     if (n < 0 || n > 255) {
629       error("%1:%2: code out of range", file, lineno);
630       fclose(fp);
631       return 0;
632     }
633     ptr = strtok(0, " \n\t");
634     if (!ptr) {
635       error("%1:%2: missing names", file, lineno);
636       fclose(fp);
637       return 0;
638     }
639     for (; ptr; ptr = strtok(0, " \n\t"))
640       table[n] = new char_list(ptr, table[n]);
641   }
642   fclose(fp);
643   return 1;
644 }
645 
646 
647 /* Every character that can participate in a ligature appears in the
648 lig_chars table. `ch' gives the full-name of the character, `name'
649 gives the groff name of the character, `i' gives its index in
650 the encoding, which is filled in later  (-1 if it does not appear). */
651 
652 struct {
653   const char *ch;
654   int i;
655 } lig_chars[] = {
656   "f", -1,
657   "i", -1,
658   "l", -1,
659   "ff", -1,
660   "fi", -1,
661   "fl", -1,
662   "Fi", -1,
663   "Fl", -1,
664 };
665 
666 // Indices into lig_chars[].
667 
668 enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
669 
670 // Each possible ligature appears in this table.
671 
672 struct {
673   unsigned char c1, c2, res;
674   const char *ch;
675 } lig_table[] = {
676   CH_f, CH_f, CH_ff, "ff",
677   CH_f, CH_i, CH_fi, "fi",
678   CH_f, CH_l, CH_fl, "fl",
679   CH_ff, CH_i, CH_ffi, "ffi",
680   CH_ff, CH_l, CH_ffl, "ffl",
681   };
682 
683 static void usage();
684 
685 int main(int argc, char **argv)
686 {
687   program_name = argv[0];
688   int special_flag = 0;
689   int skewchar = -1;
690   int opt;
691   const char *gf_file = 0;
692   while ((opt = getopt(argc, argv, "svg:k:")) != EOF)
693     switch (opt) {
694     case 'g':
695       gf_file = optarg;
696       break;
697     case 's':
698       special_flag = 1;
699       break;
700     case 'k':
701       {
702 	char *ptr;
703 	long n = strtol(optarg, &ptr, 0);
704 	if ((n == 0 && ptr == optarg)
705 	    || *ptr != '\0'
706 	    || n < 0
707 	    || n > UCHAR_MAX)
708 	  error("invalid skewchar");
709 	else
710 	  skewchar = (int)n;
711 	break;
712       }
713     case 'v':
714       {
715 	extern const char *version_string;
716 	fprintf(stderr, "tfmtodit version %s\n", version_string);
717 	fflush(stderr);
718 	break;
719       }
720     case '?':
721       usage();
722       break;
723     case EOF:
724       assert(0);
725     }
726   if (argc - optind != 3)
727     usage();
728   gf g;
729   if (gf_file) {
730     if (!g.load(gf_file))
731       return 1;
732   }
733   const char *tfm_file = argv[optind];
734   const char *map_file = argv[optind + 1];
735   const char *font_file = argv[optind + 2];
736   tfm t;
737   if (!t.load(tfm_file))
738     return 1;
739   char_list *table[256];
740   if (!read_map(map_file, table))
741     return 1;
742   errno = 0;
743   if (!freopen(font_file, "w", stdout)) {
744     error("can't open `%1' for writing: %2", font_file, strerror(errno));
745     return 1;
746   }
747   printf("name %s\n", font_file);
748   if (special_flag)
749     fputs("special\n", stdout);
750   char *internal_name = strsave(argv[optind]);
751   int len = strlen(internal_name);
752   if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
753     internal_name[len - 4] = '\0';
754   char *s = strrchr(internal_name, '/');
755   printf("internalname %s\n", s ? s + 1 : internal_name);
756   int n;
757   if (t.get_param(2, &n)) {
758     if (n > 0)
759       printf("spacewidth %d\n", n*MULTIPLIER);
760   }
761   if (t.get_param(1, &n) && n != 0)
762     printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/M_PI);
763   int xheight;
764   if (!t.get_param(5, &xheight))
765     xheight = 0;
766   int i;
767   // Print the list of ligatures.
768   // First find the indices of each character that can participate in
769   // a ligature.
770   for (i = 0; i < 256; i++)
771     for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
772       for (char_list *p = table[i]; p; p = p->next)
773 	if (strcmp(lig_chars[j].ch, p->ch) == 0)
774 	  lig_chars[j].i = i;
775   // For each possible ligature, if its participants all exist,
776   // and it appears as a ligature in the tfm file, include in
777   // the list of ligatures.
778   int started = 0;
779   for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
780     int i1 = lig_chars[lig_table[i].c1].i;
781     int i2 = lig_chars[lig_table[i].c2].i;
782     int r = lig_chars[lig_table[i].res].i;
783     if (i1 >= 0 && i2 >= 0 && r >= 0) {
784       unsigned char c;
785       if (t.get_lig(i1, i2, &c) && c == r) {
786 	if (!started) {
787 	  started = 1;
788 	  fputs("ligatures", stdout);
789 	}
790 	printf(" %s", lig_table[i].ch);
791       }
792     }
793   }
794   if (started)
795     fputs(" 0\n", stdout);
796   printf("checksum %d\n", t.get_checksum());
797   printf("designsize %d\n", t.get_design_size());
798   // Now print out the kerning information.
799   int had_kern = 0;
800   kern_iterator iter(&t);
801   unsigned char c1, c2;
802   int k;
803   while (iter.next(&c1, &c2, &k))
804     if (c2 != skewchar) {
805       k *= MULTIPLIER;
806       char_list *q = table[c2];
807       for (char_list *p1 = table[c1]; p1; p1 = p1->next)
808 	for (char_list *p2 = q; p2; p2 = p2->next) {
809 	  if (!had_kern) {
810 	    printf("kernpairs\n");
811 	    had_kern = 1;
812 	  }
813 	  printf("%s %s %d\n", p1->ch, p2->ch, k);
814 	}
815     }
816   printf("charset\n");
817   char_list unnamed("---");
818   for (i = 0; i < 256; i++)
819     if (t.contains(i)) {
820       char_list *p = table[i] ? table[i] : &unnamed;
821       int m[6];
822       m[0] = t.get_width(i);
823       m[1] = t.get_height(i);
824       m[2] = t.get_depth(i);
825       m[3] = t.get_italic(i);
826       m[4] = g.get_left_adjustment(i);
827       m[5] = g.get_right_adjustment(i);
828       printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
829       for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
830 	if (m[j] != 0)
831 	  break;
832       for (int k = 1; k <= j; k++)
833 	printf(",%d", m[k]*MULTIPLIER);
834       int type = 0;
835       if (m[2] > 0)
836 	type = 1;
837       if (m[1] > xheight)
838 	type += 2;
839       printf("\t%d\t%04o\n", type, i);
840       for (p = p->next; p; p = p->next)
841 	printf("%s\t\"\n", p->ch);
842     }
843   return 0;
844 }
845 
846 static void usage()
847 {
848   fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
849 	  program_name);
850   exit(1);
851 }
852