2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2000, 2001, 2004 Free Software Foundation, Inc.
5 * Written by James Clark (jjc@jclark.com)
7 * This 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
12 * This 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 COPYING. If not, write to the Free Software
19 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
23 * I have tried to incorporate the changes needed for TeX 3.0 tfm files,
24 * but I haven't tested them.
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.
35 * We do this by loading this definition after cmbase when creating cm.base.
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;
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.
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
54 #include "tfmtodit-config.h"
67 struct char_info_word
{
68 unsigned char width_index
;
73 unsigned char remainder
;
76 struct lig_kern_command
{
77 unsigned char skip_byte
;
78 unsigned char next_char
;
79 unsigned char op_byte
;
80 unsigned char remainder
;
85 friend class kern_iterator
;
98 char_info_word
*char_info
;
103 lig_kern_command
*lig_kern
;
110 int load(const char *);
116 int get_param(int, int *);
118 int get_design_size();
119 int get_lig(unsigned char, unsigned char, unsigned char *);
129 kern_iterator(tfm
*);
130 int next(unsigned char *c1
, unsigned char *c2
, int *k
);
134 kern_iterator::kern_iterator(tfm
*p
)
135 : t(p
), c(t
->bc
), i(-1)
139 int kern_iterator::next(unsigned char *c1
, unsigned char *c2
, int *k
)
141 for (; c
<= t
->ec
; c
++)
142 if (t
->char_info
[c
- t
->bc
].tag
== 1) {
144 i
= t
->char_info
[c
- t
->bc
].remainder
;
145 if (t
->lig_kern
[i
].skip_byte
> 128)
146 i
= (256*t
->lig_kern
[i
].op_byte
147 + t
->lig_kern
[i
].remainder
);
150 int skip
= t
->lig_kern
[i
].skip_byte
;
151 if (skip
<= 128 && t
->lig_kern
[i
].op_byte
>= 128) {
153 *c2
= t
->lig_kern
[i
].next_char
;
154 *k
= t
->kern
[256*(t
->lig_kern
[i
].op_byte
- 128)
155 + t
->lig_kern
[i
].remainder
];
174 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
179 int tfm::get_lig(unsigned char c1
, unsigned char c2
, unsigned char *cp
)
181 if (contains(c1
) && char_info
[c1
- bc
].tag
== 1) {
182 int i
= char_info
[c1
- bc
].remainder
;
183 if (lig_kern
[i
].skip_byte
> 128)
184 i
= 256*lig_kern
[i
].op_byte
+ lig_kern
[i
].remainder
;
186 int skip
= lig_kern
[i
].skip_byte
;
189 // We are only interested in normal ligatures, for which
191 if (lig_kern
[i
].op_byte
== 0
192 && lig_kern
[i
].next_char
== c2
) {
193 *cp
= lig_kern
[i
].remainder
;
204 int tfm::contains(int i
)
206 return i
>= bc
&& i
<= ec
&& char_info
[i
- bc
].width_index
!= 0;
209 int tfm::get_width(int i
)
211 return width
[char_info
[i
- bc
].width_index
];
214 int tfm::get_height(int i
)
216 return height
[char_info
[i
- bc
].height_index
];
219 int tfm::get_depth(int i
)
221 return depth
[char_info
[i
- bc
].depth_index
];
224 int tfm::get_italic(int i
)
226 return italic
[char_info
[i
- bc
].italic_index
];
229 int tfm::get_param(int i
, int *p
)
231 if (i
<= 0 || i
> np
)
239 int tfm::get_checksum()
244 int tfm::get_design_size()
261 int read2(unsigned char *&s
)
269 int read4(unsigned char *&s
)
279 int tfm::load(const char *file
)
282 FILE *fp
= fopen(file
, FOPEN_RB
);
284 error("can't open `%1': %2", file
, strerror(errno
));
289 if (c1
== EOF
|| c2
== EOF
) {
291 error("unexpected end of file on `%1'", file
);
294 int lf
= (c1
<< 8) + c2
;
295 int toread
= lf
*4 - 2;
296 unsigned char *buf
= new unsigned char[toread
];
297 if (fread(buf
, 1, toread
, fp
) != (size_t)toread
) {
299 error("unexpected end of file on `%1'", file
);
301 error("error on file `%1'", file
);
308 error("bad tfm file `%1': impossibly short", file
);
312 unsigned char *ptr
= buf
;
324 if (6 + lh
+ (ec
- bc
+ 1) + nw
+ nh
+ nd
+ ni
+ nl
+ nk
+ ne
+ np
!= lf
) {
325 error("bad tfm file `%1': lengths do not sum", file
);
330 error("bad tfm file `%1': header too short", file
);
334 char_info
= new char_info_word
[ec
- bc
+ 1];
336 height
= new int[nh
];
338 italic
= new int[ni
];
339 lig_kern
= new lig_kern_command
[nl
];
346 for (i
= 0; i
< ec
- bc
+ 1; i
++) {
347 char_info
[i
].width_index
= *ptr
++;
348 unsigned char tem
= *ptr
++;
349 char_info
[i
].depth_index
= tem
& 0xf;
350 char_info
[i
].height_index
= tem
>> 4;
352 char_info
[i
].italic_index
= tem
>> 2;
353 char_info
[i
].tag
= tem
& 3;
354 char_info
[i
].remainder
= *ptr
++;
356 for (i
= 0; i
< nw
; i
++)
357 width
[i
] = read4(ptr
);
358 for (i
= 0; i
< nh
; i
++)
359 height
[i
] = read4(ptr
);
360 for (i
= 0; i
< nd
; i
++)
361 depth
[i
] = read4(ptr
);
362 for (i
= 0; i
< ni
; i
++)
363 italic
[i
] = read4(ptr
);
364 for (i
= 0; i
< nl
; i
++) {
365 lig_kern
[i
].skip_byte
= *ptr
++;
366 lig_kern
[i
].next_char
= *ptr
++;
367 lig_kern
[i
].op_byte
= *ptr
++;
368 lig_kern
[i
].remainder
= *ptr
++;
370 for (i
= 0; i
< nk
; i
++)
371 kern
[i
] = read4(ptr
);
373 for (i
= 0; i
< np
; i
++)
374 param
[i
] = read4(ptr
);
375 assert(ptr
== buf
+ lf
*4 - 2);
382 static int sread4(int *p
, FILE *fp
);
383 static int uread3(int *p
, FILE *fp
);
384 static int uread2(int *p
, FILE *fp
);
385 static int skip(int n
, FILE *fp
);
392 int load(const char *file
);
393 int get_left_adjustment(int i
) { return left
[i
]; }
394 int get_right_adjustment(int i
) { return right
[i
]; }
399 for (int i
= 0; i
< 256; i
++)
400 left
[i
] = right
[i
] = 0;
403 int gf::load(const char *file
)
420 int got_an_adjustment
= 0;
421 int pending_adjustment
= 0;
422 int left_adj
= 0, right_adj
= 0; // pacify compiler
423 const int gf_id_byte
= 131;
425 FILE *fp
= fopen(file
, FOPEN_RB
);
427 error("can't open `%1': %2", file
, strerror(errno
));
430 if (getc(fp
) != pre
|| getc(fp
) != gf_id_byte
) {
431 error("bad gf file");
445 if ((op
>= paint_0
&& op
<= paint_0
+ 63)
446 || (op
>= new_row_0
&& op
<= new_row_0
+ 164))
471 if (!sread4(&code
, fp
))
473 if (pending_adjustment
) {
474 pending_adjustment
= 0;
475 left
[code
& 0377] = left_adj
;
476 right
[code
& 0377] = right_adj
;
487 if (pending_adjustment
) {
488 pending_adjustment
= 0;
489 left
[code
] = left_adj
;
490 right
[code
] = right_adj
;
502 if (fread(buf
, 1, len
, fp
) != (size_t)len
)
504 if (len
== 10 /* strlen("adjustment") */
505 && memcmp(buf
, "adjustment", len
) == 0) {
512 if (!sread4(&left_adj
, fp
))
520 if (!sread4(&right_adj
, fp
))
522 got_an_adjustment
= 1;
523 pending_adjustment
= 1;
528 if (!uread2(&n
, fp
) || !skip(n
, fp
))
532 if (!uread3(&n
, fp
) || !skip(n
, fp
))
536 if (!sread4(&n
, fp
) || !skip(n
, fp
))
544 fatal("unrecognized opcode `%1'", op
);
548 if (!got_an_adjustment
)
549 warning("no adjustment specials found in gf file");
552 error("unexpected end of file");
556 int gf::sread4(int *p
, FILE *fp
)
567 return !ferror(fp
) && !feof(fp
);
570 int gf::uread3(int *p
, FILE *fp
)
577 return !ferror(fp
) && !feof(fp
);
580 int gf::uread2(int *p
, FILE *fp
)
585 return !ferror(fp
) && !feof(fp
);
588 int gf::skip(int n
, FILE *fp
)
602 char_list(const char *, char_list
* = 0);
605 char_list::char_list(const char *s
, char_list
*p
) : ch(strsave(s
)), next(p
)
609 int read_map(const char *file
, char_list
**table
)
612 FILE *fp
= fopen(file
, "r");
614 error("can't open `%1': %2", file
, strerror(errno
));
617 for (int i
= 0; i
< 256; i
++)
621 while (fgets(buf
, int(sizeof(buf
)), fp
)) {
624 while (csspace(*ptr
))
626 if (*ptr
== '\0' || *ptr
== '#')
628 ptr
= strtok(ptr
, " \n\t");
632 if (sscanf(ptr
, "%d", &n
) != 1) {
633 error("%1:%2: bad map file", file
, lineno
);
637 if (n
< 0 || n
> 255) {
638 error("%1:%2: code out of range", file
, lineno
);
642 ptr
= strtok(0, " \n\t");
644 error("%1:%2: missing names", file
, lineno
);
648 for (; ptr
; ptr
= strtok(0, " \n\t"))
649 table
[n
] = new char_list(ptr
, table
[n
]);
656 * Every character that can participate in a ligature appears in the
657 * lig_chars table. `ch' gives the full-name of the character, `name'
658 * gives the groff name of the character, `i' gives its index in
659 * the encoding, which is filled in later (-1 if it does not appear).
665 } lig_chars
[] = { // FIXME const
676 // Indices into lig_chars[].
678 enum { CH_f
, CH_i
, CH_l
, CH_ff
, CH_fi
, CH_fl
, CH_ffi
, CH_ffl
};
680 // Each possible ligature appears in this table.
683 unsigned char c1
, c2
, res
;
685 } lig_table
[] = { // FIXME const
686 { CH_f
, CH_f
, CH_ff
, "ff" },
687 { CH_f
, CH_i
, CH_fi
, "fi" },
688 { CH_f
, CH_l
, CH_fl
, "fl" },
689 { CH_ff
, CH_i
, CH_ffi
, "ffi" },
690 { CH_ff
, CH_l
, CH_ffl
, "ffl" },
693 static void usage(FILE *stream
);
695 int main(int argc
, char **argv
)
697 program_name
= argv
[0];
698 int special_flag
= 0;
701 const char *gf_file
= 0;
702 static const struct option long_options
[] = {
703 { "help", no_argument
, 0, CHAR_MAX
+ 1 },
704 { "version", no_argument
, 0, 'v' },
707 while ((opt
= getopt_long(argc
, argv
, "svg:k:", long_options
, NULL
)) != EOF
)
718 long n
= strtol(optarg
, &ptr
, 0);
719 if ((n
== 0 && ptr
== optarg
)
723 error("invalid skewchar");
730 printf(L_TFMTODIT
" (" T_ROFF
") v" VERSION
);
734 case CHAR_MAX
+ 1: // --help
745 if (argc
- optind
!= 3) {
751 if (!g
.load(gf_file
))
754 const char *tfm_file
= argv
[optind
];
755 const char *map_file
= argv
[optind
+ 1];
756 const char *font_file
= argv
[optind
+ 2];
758 if (!t
.load(tfm_file
))
760 char_list
*table
[256];
761 if (!read_map(map_file
, table
))
764 if (!freopen(font_file
, "w", stdout
)) {
765 error("can't open `%1' for writing: %2", font_file
, strerror(errno
));
768 printf("name %s\n", font_file
);
770 fputs("special\n", stdout
);
771 char *internal_name
= strsave(argv
[optind
]);
772 int len
= strlen(internal_name
);
773 if (len
> 4 && strcmp(internal_name
+ len
- 4, ".tfm") == 0)
774 internal_name
[len
- 4] = '\0';
775 // DIR_SEPS[] are possible directory separator characters, see nonposix.h.
776 // We want the rightmost separator of all possible ones.
777 // Example: d:/foo\\bar.
778 const char *s
= strrchr(internal_name
, DIR_SEPS
[0]), *s1
;
779 const char *sep
= &DIR_SEPS
[1];
782 s1
= strrchr(internal_name
, *sep
);
783 if (s1
&& (!s
|| s1
> s
))
787 printf("internalname %s\n", s
? s
+ 1 : internal_name
);
789 if (t
.get_param(2, &n
)) {
791 printf("spacewidth %d\n", n
*MULTIPLIER
);
793 if (t
.get_param(1, &n
) && n
!= 0)
794 printf("slant %f\n", atan2(n
/double(1<<20), 1.0)*180.0/PI
);
796 if (!t
.get_param(5, &xheight
))
799 // Print the list of ligatures.
800 // First find the indices of each character that can participate in
802 for (i
= 0; i
< 256; i
++)
803 for (unsigned int j
= 0; j
< sizeof(lig_chars
)/sizeof(lig_chars
[0]); j
++)
804 for (char_list
*p
= table
[i
]; p
; p
= p
->next
)
805 if (strcmp(lig_chars
[j
].ch
, p
->ch
) == 0)
807 // For each possible ligature, if its participants all exist,
808 // and it appears as a ligature in the tfm file, include in
809 // the list of ligatures.
811 for (i
= 0; i
< sizeof(lig_table
)/sizeof(lig_table
[0]); i
++) {
812 int i1
= lig_chars
[lig_table
[i
].c1
].i
;
813 int i2
= lig_chars
[lig_table
[i
].c2
].i
;
814 int r
= lig_chars
[lig_table
[i
].res
].i
;
815 if (i1
>= 0 && i2
>= 0 && r
>= 0) {
817 if (t
.get_lig(i1
, i2
, &c
) && c
== r
) {
820 fputs("ligatures", stdout
);
822 printf(" %s", lig_table
[i
].ch
);
827 fputs(" 0\n", stdout
);
828 printf("checksum %d\n", t
.get_checksum());
829 printf("designsize %d\n", t
.get_design_size());
830 // Now print out the kerning information.
832 kern_iterator
iter(&t
);
833 unsigned char c1
, c2
;
835 while (iter
.next(&c1
, &c2
, &k
))
836 if (c2
!= skewchar
) {
838 char_list
*q
= table
[c2
];
839 for (char_list
*p1
= table
[c1
]; p1
; p1
= p1
->next
)
840 for (char_list
*p2
= q
; p2
; p2
= p2
->next
) {
842 printf("kernpairs\n");
845 printf("%s %s %d\n", p1
->ch
, p2
->ch
, k
);
849 char_list
unnamed("---");
850 for (i
= 0; i
< 256; i
++)
852 char_list
*p
= table
[i
] ? table
[i
] : &unnamed
;
854 m
[0] = t
.get_width(i
);
855 m
[1] = t
.get_height(i
);
856 m
[2] = t
.get_depth(i
);
857 m
[3] = t
.get_italic(i
);
858 m
[4] = g
.get_left_adjustment(i
);
859 m
[5] = g
.get_right_adjustment(i
);
860 printf("%s\t%d", p
->ch
, m
[0]*MULTIPLIER
);
862 for (j
= int(sizeof(m
)/sizeof(m
[0])) - 1; j
> 0; j
--)
865 for (k
= 1; k
<= j
; k
++)
866 printf(",%d", m
[k
]*MULTIPLIER
);
872 printf("\t%d\t%04o\n", type
, i
);
873 for (p
= p
->next
; p
; p
= p
->next
)
874 printf("%s\t\"\n", p
->ch
);
879 static void usage(FILE *stream
)
882 "Synopsis: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",