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