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