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
kern_iterator(tfm * p)128 kern_iterator::kern_iterator(tfm *p)
129 : t(p), i(-1), c(t->bc)
130 {
131 }
132
next(unsigned char * c1,unsigned char * c2,int * k)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
tfm()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
get_lig(unsigned char c1,unsigned char c2,unsigned char * cp)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
contains(int i)198 int tfm::contains(int i)
199 {
200 return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
201 }
202
get_width(int i)203 int tfm::get_width(int i)
204 {
205 return width[char_info[i - bc].width_index];
206 }
207
get_height(int i)208 int tfm::get_height(int i)
209 {
210 return height[char_info[i - bc].height_index];
211 }
212
get_depth(int i)213 int tfm::get_depth(int i)
214 {
215 return depth[char_info[i - bc].depth_index];
216 }
217
get_italic(int i)218 int tfm::get_italic(int i)
219 {
220 return italic[char_info[i - bc].italic_index];
221 }
222
get_param(int i,int * p)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
get_checksum()233 int tfm::get_checksum()
234 {
235 return cs;
236 }
237
get_design_size()238 int tfm::get_design_size()
239 {
240 return ds;
241 }
242
~tfm()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
read2(unsigned char * & s)255 int read2(unsigned char *&s)
256 {
257 int n;
258 n = *s++ << 8;
259 n |= *s++;
260 return n;
261 }
262
read4(unsigned char * & s)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
load(const char * file)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);
get_left_adjustment(int i)385 int get_left_adjustment(int i) { return left[i]; }
get_right_adjustment(int i)386 int get_right_adjustment(int i) { return right[i]; }
387 };
388
gf()389 gf::gf()
390 {
391 for (int i = 0; i < 256; i++)
392 left[i] = right[i] = 0;
393 }
394
load(const char * file)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
sread4(int * p,FILE * fp)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
uread3(int * p,FILE * fp)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
uread2(int * p,FILE * fp)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
skip(int n,FILE * fp)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
char_list(const char * s,char_list * p)595 char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
596 {
597 }
598
599
read_map(const char * file,char_list ** table)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
main(int argc,char ** argv)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
usage()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