2 /* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.uucp)
5 This file is part of groff.
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 1, or (at your option) any later
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
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file LICENSE. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
22 but I haven't tested them. */
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.
33 We do this by loading this definition after cmbase when creating cm.base.
35 def ignore_math_fit(expr left_adjustment,right_adjustment) =
37 numspecial left_adjustment*16/designsize;
38 numspecial right_adjustment*16/designsize;
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.
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
60 /* Values in the tfm file should be multiplied by this. */
64 struct char_info_word
{
65 unsigned char width_index
;
70 unsigned char remainder
;
73 struct lig_kern_command
{
74 unsigned char skip_byte
;
75 unsigned char next_char
;
76 unsigned char op_byte
;
77 unsigned char remainder
;
92 char_info_word
*char_info
;
97 lig_kern_command
*lig_kern
;
103 int load(const char *);
109 int get_param(int, int *);
111 int get_design_size();
112 int get_lig(unsigned char, unsigned char, unsigned char *);
113 friend class kern_iterator
;
116 class kern_iterator
{
121 kern_iterator(tfm
*);
122 int next(unsigned char *c1
, unsigned char *c2
, int *k
);
126 kern_iterator::kern_iterator(tfm
*p
)
127 : t(p
), i(-1), c(t
->bc
)
131 int kern_iterator::next(unsigned char *c1
, unsigned char *c2
, int *k
)
133 for (; c
<= t
->ec
; c
++)
134 if (t
->char_info
[c
- t
->bc
].tag
== 1) {
136 i
= t
->char_info
[c
- t
->bc
].remainder
;
137 if (t
->lig_kern
[i
].skip_byte
> 128)
138 i
= (256*t
->lig_kern
[i
].op_byte
139 + t
->lig_kern
[i
].remainder
);
142 int skip
= t
->lig_kern
[i
].skip_byte
;
143 if (skip
<= 128 && t
->lig_kern
[i
].op_byte
>= 128) {
145 *c2
= t
->lig_kern
[i
].next_char
;
146 *k
= t
->kern
[256*(t
->lig_kern
[i
].op_byte
- 128)
147 + t
->lig_kern
[i
].remainder
];
166 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
171 int tfm::get_lig(unsigned char c1
, unsigned char c2
, unsigned char *cp
)
173 if (contains(c1
) && char_info
[c1
- bc
].tag
== 1) {
174 int i
= char_info
[c1
- bc
].remainder
;
175 if (lig_kern
[i
].skip_byte
> 128)
176 i
= 256*lig_kern
[i
].op_byte
+ lig_kern
[i
].remainder
;
178 int skip
= lig_kern
[i
].skip_byte
;
181 // We are only interested in normal ligatures, for which
183 if (lig_kern
[i
].op_byte
== 0
184 && lig_kern
[i
].next_char
== c2
) {
185 *cp
= lig_kern
[i
].remainder
;
196 int tfm::contains(int i
)
198 return i
>= bc
&& i
<= ec
&& char_info
[i
- bc
].width_index
!= 0;
201 int tfm::get_width(int i
)
203 return width
[char_info
[i
- bc
].width_index
];
206 int tfm::get_height(int i
)
208 return height
[char_info
[i
- bc
].height_index
];
211 int tfm::get_depth(int i
)
213 return depth
[char_info
[i
- bc
].depth_index
];
216 int tfm::get_italic(int i
)
218 return italic
[char_info
[i
- bc
].italic_index
];
221 int tfm::get_param(int i
, int *p
)
223 if (i
<= 0 || i
> np
)
231 int tfm::get_checksum()
236 int tfm::get_design_size()
253 int read2(unsigned char *&s
)
261 int read4(unsigned char *&s
)
272 int tfm::load(const char *file
)
274 FILE *fp
= fopen(file
, "r");
276 error("can't open `%1': %2", file
, strerror(errno
));
281 if (c1
== EOF
|| c2
== EOF
) {
283 error("unexpected end of file on `%1'", file
);
286 int lf
= (c1
<< 8) + c2
;
287 int toread
= lf
*4 - 2;
288 unsigned char *buf
= new unsigned char[toread
];
289 if (fread(buf
, 1, toread
, fp
) != toread
) {
291 error("unexpected end of file on `%1'", file
);
293 error("error on file `%1'", file
);
300 error("bad tfm file `%1': impossibly short", file
);
304 unsigned char *ptr
= buf
;
316 if (6 + lh
+ (ec
- bc
+ 1) + nw
+ nh
+ nd
+ ni
+ nl
+ nk
+ ne
+ np
!= lf
) {
317 error("bad tfm file `%1': lengths do not sum", file
);
322 error("bad tfm file `%1': header too short", file
);
326 char_info
= new char_info_word
[ec
- bc
+ 1];
328 height
= new int[nh
];
330 italic
= new int[ni
];
331 lig_kern
= new lig_kern_command
[nl
];
338 for (i
= 0; i
< ec
- bc
+ 1; i
++) {
339 char_info
[i
].width_index
= *ptr
++;
340 unsigned char tem
= *ptr
++;
341 char_info
[i
].depth_index
= tem
& 0xf;
342 char_info
[i
].height_index
= tem
>> 4;
344 char_info
[i
].italic_index
= tem
>> 2;
345 char_info
[i
].tag
= tem
& 3;
346 char_info
[i
].remainder
= *ptr
++;
348 for (i
= 0; i
< nw
; i
++)
349 width
[i
] = read4(ptr
);
350 for (i
= 0; i
< nh
; i
++)
351 height
[i
] = read4(ptr
);
352 for (i
= 0; i
< nd
; i
++)
353 depth
[i
] = read4(ptr
);
354 for (i
= 0; i
< ni
; i
++)
355 italic
[i
] = read4(ptr
);
356 for (i
= 0; i
< nl
; i
++) {
357 lig_kern
[i
].skip_byte
= *ptr
++;
358 lig_kern
[i
].next_char
= *ptr
++;
359 lig_kern
[i
].op_byte
= *ptr
++;
360 lig_kern
[i
].remainder
= *ptr
++;
362 for (i
= 0; i
< nk
; i
++)
363 kern
[i
] = read4(ptr
);
365 for (i
= 0; i
< np
; i
++)
366 param
[i
] = read4(ptr
);
367 assert(ptr
== buf
+ lf
*4 - 2);
375 static int sread4(int *p
, FILE *fp
);
376 static int uread3(int *p
, FILE *fp
);
377 static int uread2(int *p
, FILE *fp
);
378 static int skip(int n
, FILE *fp
);
381 int load(const char *file
);
382 int get_left_adjustment(int i
) { return left
[i
]; }
383 int get_right_adjustment(int i
) { return right
[i
]; }
388 for (int i
= 0; i
< 256; i
++)
389 left
[i
] = right
[i
] = 0;
392 int gf::load(const char *file
)
409 int got_an_adjustment
= 0;
410 int pending_adjustment
= 0;
411 int left_adj
, right_adj
;
412 const int gf_id_byte
= 131;
413 FILE *fp
= fopen(file
, "r");
415 error("can't open `%1': %2", file
, strerror(errno
));
418 if (getc(fp
) != pre
|| getc(fp
) != gf_id_byte
) {
419 error("bad gf file");
433 if ((op
>= paint_0
&& op
<= paint_0
+ 63)
434 || (op
>= new_row_0
&& op
<= new_row_0
+ 164))
459 if (!sread4(&code
, fp
))
461 if (pending_adjustment
) {
462 pending_adjustment
= 0;
463 left
[code
& 0377] = left_adj
;
464 right
[code
& 0377] = right_adj
;
475 if (pending_adjustment
) {
476 pending_adjustment
= 0;
477 left
[code
] = left_adj
;
478 right
[code
] = right_adj
;
490 if (fread(buf
, 1, len
, fp
) != len
)
492 if (len
== 10 /* strlen("adjustment") */
493 && memcmp(buf
, "adjustment", len
) == 0) {
500 if (!sread4(&left_adj
, fp
))
508 if (!sread4(&right_adj
, fp
))
510 got_an_adjustment
= 1;
511 pending_adjustment
= 1;
516 if (!uread2(&n
, fp
) || !skip(n
, fp
))
520 if (!uread3(&n
, fp
) || !skip(n
, fp
))
524 if (!sread4(&n
, fp
) || !skip(n
, fp
))
532 fatal("unrecognized opcode `%1'", op
);
536 if (!got_an_adjustment
)
537 warning("no adjustment specials found in gf file");
540 error("unexpected end of file");
544 int gf::sread4(int *p
, FILE *fp
)
555 return !ferror(fp
) && !feof(fp
);
558 int gf::uread3(int *p
, FILE *fp
)
565 return !ferror(fp
) && !feof(fp
);
568 int gf::uread2(int *p
, FILE *fp
)
573 return !ferror(fp
) && !feof(fp
);
576 int gf::skip(int n
, FILE *fp
)
588 char_list(const char *, char_list
* = 0);
591 char_list::char_list(const char *s
, char_list
*p
) : ch(strsave(s
)), next(p
)
596 int read_map(const char *file
, char_list
**table
)
598 FILE *fp
= fopen(file
, "r");
600 error("can't open `%1': %2", file
, strerror(errno
));
603 for (int i
= 0; i
< 256; i
++)
607 while (fgets(buf
, int(sizeof(buf
)), fp
)) {
610 while (csspace(*ptr
))
612 if (*ptr
== '\0' || *ptr
== '#')
614 ptr
= strtok(ptr
, " \n\t");
618 if (sscanf(ptr
, "%d", &n
) != 1) {
619 error("%1:%2: bad map file", file
, lineno
);
623 if (n
< 0 || n
> 255) {
624 error("%1:%2: code out of range", file
, lineno
);
628 ptr
= strtok(0, " \n\t");
630 error("%1:%2: missing names", file
, lineno
);
634 for (; ptr
; ptr
= strtok(0, " \n\t"))
635 table
[n
] = new char_list(ptr
, table
[n
]);
642 /* Every character that can participate in a ligature appears in the
643 lig_chars table. `ch' gives the full-name of the character, `name'
644 gives the groff name of the character, `i' gives its index in
645 the encoding, which is filled in later (-1 if it does not appear). */
661 // Indices into lig_chars[].
663 enum { CH_f
, CH_i
, CH_l
, CH_ff
, CH_fi
, CH_fl
, CH_ffi
, CH_ffl
};
665 // Each possible ligature appears in this table.
668 unsigned char c1
, c2
, res
;
671 CH_f
, CH_f
, CH_ff
, "ff",
672 CH_f
, CH_i
, CH_fi
, "fi",
673 CH_f
, CH_l
, CH_fl
, "fl",
674 CH_ff
, CH_i
, CH_ffi
, "ffi",
675 CH_ff
, CH_l
, CH_ffl
, "ffl",
680 int main(int argc
, char **argv
)
682 program_name
= argv
[0];
683 int special_flag
= 0;
686 const char *gf_file
= 0;
687 while ((opt
= getopt(argc
, argv
, "svg:k:")) != EOF
)
698 long n
= strtol(optarg
, &ptr
, 0);
699 if ((n
== 0 && ptr
== optarg
)
703 error("invalid skewchar");
710 extern const char *version_string
;
711 fprintf(stderr
, "tfmtodit version %s\n", version_string
);
721 if (argc
- optind
!= 3)
725 if (!g
.load(gf_file
))
728 const char *tfm_file
= argv
[optind
];
729 const char *map_file
= argv
[optind
+ 1];
730 const char *font_file
= argv
[optind
+ 2];
732 if (!t
.load(tfm_file
))
734 char_list
*table
[256];
735 if (!read_map(map_file
, table
))
737 if (!freopen(font_file
, "w", stdout
)) {
738 error("can't open `%1' for writing: %2", font_file
, strerror(errno
));
741 printf("name %s\n", font_file
);
743 fputs("special\n", stdout
);
744 char *internal_name
= strsave(argv
[optind
]);
745 int len
= strlen(internal_name
);
746 if (len
> 4 && strcmp(internal_name
+ len
- 4, ".tfm") == 0)
747 internal_name
[len
- 4] = '\0';
748 char *s
= strrchr(internal_name
, '/');
749 printf("internalname %s\n", s
? s
+ 1 : internal_name
);
751 if (t
.get_param(2, &n
)) {
753 printf("spacewidth %d\n", n
*MULTIPLIER
);
755 if (t
.get_param(1, &n
) && n
!= 0)
756 printf("slant %f\n", atan2(n
/double(1<<20), 1.0)*180.0/M_PI
);
758 if (!t
.get_param(5, &xheight
))
761 // Print the list of ligatures.
762 // First find the indices of each character that can participate in
764 for (i
= 0; i
< 256; i
++)
765 for (int j
= 0; j
< sizeof(lig_chars
)/sizeof(lig_chars
[0]); j
++)
766 for (char_list
*p
= table
[i
]; p
; p
= p
->next
)
767 if (strcmp(lig_chars
[j
].ch
, p
->ch
) == 0)
769 // For each possible ligature, if its participants all exist,
770 // and it appears as a ligature in the tfm file, include in
771 // the list of ligatures.
773 for (i
= 0; i
< sizeof(lig_table
)/sizeof(lig_table
[0]); i
++) {
774 int i1
= lig_chars
[lig_table
[i
].c1
].i
;
775 int i2
= lig_chars
[lig_table
[i
].c2
].i
;
776 int r
= lig_chars
[lig_table
[i
].res
].i
;
777 if (i1
>= 0 && i2
>= 0 && r
>= 0) {
779 if (t
.get_lig(i1
, i2
, &c
) && c
== r
) {
782 fputs("ligatures", stdout
);
784 printf(" %s", lig_table
[i
].ch
);
789 fputs(" 0\n", stdout
);
790 printf("checksum %d\n", t
.get_checksum());
791 printf("designsize %d\n", t
.get_design_size());
792 // Now print out the kerning information.
794 kern_iterator
iter(&t
);
795 unsigned char c1
, c2
;
797 while (iter
.next(&c1
, &c2
, &k
))
798 if (c2
!= skewchar
) {
800 char_list
*q
= table
[c2
];
801 for (char_list
*p1
= table
[c1
]; p1
; p1
= p1
->next
)
802 for (char_list
*p2
= q
; p2
; p2
= p2
->next
) {
804 printf("kernpairs\n");
807 printf("%s %s %d\n", p1
->ch
, p2
->ch
, k
);
811 char_list
unnamed("---");
812 for (i
= 0; i
< 256; i
++)
814 char_list
*p
= table
[i
] ? table
[i
] : &unnamed
;
816 m
[0] = t
.get_width(i
);
817 m
[1] = t
.get_height(i
);
818 m
[2] = t
.get_depth(i
);
819 m
[3] = t
.get_italic(i
);
820 m
[4] = g
.get_left_adjustment(i
);
821 m
[5] = g
.get_right_adjustment(i
);
822 printf("%s\t%d", p
->ch
, m
[0]*MULTIPLIER
);
823 for (int j
= int(sizeof(m
)/sizeof(m
[0])) - 1; j
> 0; j
--)
826 for (int k
= 1; k
<= j
; k
++)
827 printf(",%d", m
[k
]*MULTIPLIER
);
833 printf("\t%d\t%04o\n", type
, i
);
834 for (p
= p
->next
; p
; p
= p
->next
)
835 printf("%s\t\"\n", p
->ch
);
842 fprintf(stderr
, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",