4 /* Copyright (C) 1989-1992, 2000, 2001, 2004 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
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
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
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. */
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) =
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
63 extern "C" const char *Version_string
;
65 /* Values in the tfm file should be multiplied by this. */
69 struct char_info_word
{
70 unsigned char width_index
;
75 unsigned char remainder
;
78 struct lig_kern_command
{
79 unsigned char skip_byte
;
80 unsigned char next_char
;
81 unsigned char op_byte
;
82 unsigned char remainder
;
97 char_info_word
*char_info
;
102 lig_kern_command
*lig_kern
;
108 int load(const char *);
114 int get_param(int, int *);
116 int get_design_size();
117 int get_lig(unsigned char, unsigned char, unsigned char *);
118 friend class kern_iterator
;
121 class kern_iterator
{
126 kern_iterator(tfm
*);
127 int next(unsigned char *c1
, unsigned char *c2
, int *k
);
131 kern_iterator::kern_iterator(tfm
*p
)
132 : t(p
), c(t
->bc
), i(-1)
136 int kern_iterator::next(unsigned char *c1
, unsigned char *c2
, int *k
)
138 for (; c
<= t
->ec
; c
++)
139 if (t
->char_info
[c
- t
->bc
].tag
== 1) {
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
);
147 int skip
= t
->lig_kern
[i
].skip_byte
;
148 if (skip
<= 128 && t
->lig_kern
[i
].op_byte
>= 128) {
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
];
171 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
176 int tfm::get_lig(unsigned char c1
, unsigned char c2
, unsigned char *cp
)
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
;
183 int skip
= lig_kern
[i
].skip_byte
;
186 // We are only interested in normal ligatures, for which
188 if (lig_kern
[i
].op_byte
== 0
189 && lig_kern
[i
].next_char
== c2
) {
190 *cp
= lig_kern
[i
].remainder
;
201 int tfm::contains(int i
)
203 return i
>= bc
&& i
<= ec
&& char_info
[i
- bc
].width_index
!= 0;
206 int tfm::get_width(int i
)
208 return width
[char_info
[i
- bc
].width_index
];
211 int tfm::get_height(int i
)
213 return height
[char_info
[i
- bc
].height_index
];
216 int tfm::get_depth(int i
)
218 return depth
[char_info
[i
- bc
].depth_index
];
221 int tfm::get_italic(int i
)
223 return italic
[char_info
[i
- bc
].italic_index
];
226 int tfm::get_param(int i
, int *p
)
228 if (i
<= 0 || i
> np
)
236 int tfm::get_checksum()
241 int tfm::get_design_size()
258 int read2(unsigned char *&s
)
266 int read4(unsigned char *&s
)
277 int tfm::load(const char *file
)
280 FILE *fp
= fopen(file
, FOPEN_RB
);
282 error("can't open `%1': %2", file
, strerror(errno
));
287 if (c1
== EOF
|| c2
== EOF
) {
289 error("unexpected end of file on `%1'", file
);
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
) {
297 error("unexpected end of file on `%1'", file
);
299 error("error on file `%1'", file
);
306 error("bad tfm file `%1': impossibly short", file
);
310 unsigned char *ptr
= buf
;
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
);
328 error("bad tfm file `%1': header too short", file
);
332 char_info
= new char_info_word
[ec
- bc
+ 1];
334 height
= new int[nh
];
336 italic
= new int[ni
];
337 lig_kern
= new lig_kern_command
[nl
];
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;
350 char_info
[i
].italic_index
= tem
>> 2;
351 char_info
[i
].tag
= tem
& 3;
352 char_info
[i
].remainder
= *ptr
++;
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
++;
368 for (i
= 0; i
< nk
; i
++)
369 kern
[i
] = read4(ptr
);
371 for (i
= 0; i
< np
; i
++)
372 param
[i
] = read4(ptr
);
373 assert(ptr
== buf
+ lf
*4 - 2);
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
);
387 int load(const char *file
);
388 int get_left_adjustment(int i
) { return left
[i
]; }
389 int get_right_adjustment(int i
) { return right
[i
]; }
394 for (int i
= 0; i
< 256; i
++)
395 left
[i
] = right
[i
] = 0;
398 int gf::load(const char *file
)
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;
420 FILE *fp
= fopen(file
, FOPEN_RB
);
422 error("can't open `%1': %2", file
, strerror(errno
));
425 if (getc(fp
) != pre
|| getc(fp
) != gf_id_byte
) {
426 error("bad gf file");
440 if ((op
>= paint_0
&& op
<= paint_0
+ 63)
441 || (op
>= new_row_0
&& op
<= new_row_0
+ 164))
466 if (!sread4(&code
, fp
))
468 if (pending_adjustment
) {
469 pending_adjustment
= 0;
470 left
[code
& 0377] = left_adj
;
471 right
[code
& 0377] = right_adj
;
482 if (pending_adjustment
) {
483 pending_adjustment
= 0;
484 left
[code
] = left_adj
;
485 right
[code
] = right_adj
;
497 if (fread(buf
, 1, len
, fp
) != (size_t)len
)
499 if (len
== 10 /* strlen("adjustment") */
500 && memcmp(buf
, "adjustment", len
) == 0) {
507 if (!sread4(&left_adj
, fp
))
515 if (!sread4(&right_adj
, fp
))
517 got_an_adjustment
= 1;
518 pending_adjustment
= 1;
523 if (!uread2(&n
, fp
) || !skip(n
, fp
))
527 if (!uread3(&n
, fp
) || !skip(n
, fp
))
531 if (!sread4(&n
, fp
) || !skip(n
, fp
))
539 fatal("unrecognized opcode `%1'", op
);
543 if (!got_an_adjustment
)
544 warning("no adjustment specials found in gf file");
547 error("unexpected end of file");
551 int gf::sread4(int *p
, FILE *fp
)
562 return !ferror(fp
) && !feof(fp
);
565 int gf::uread3(int *p
, FILE *fp
)
572 return !ferror(fp
) && !feof(fp
);
575 int gf::uread2(int *p
, FILE *fp
)
580 return !ferror(fp
) && !feof(fp
);
583 int gf::skip(int n
, FILE *fp
)
595 char_list(const char *, char_list
* = 0);
598 char_list::char_list(const char *s
, char_list
*p
) : ch(strsave(s
)), next(p
)
603 int read_map(const char *file
, char_list
**table
)
606 FILE *fp
= fopen(file
, "r");
608 error("can't open `%1': %2", file
, strerror(errno
));
611 for (int i
= 0; i
< 256; i
++)
615 while (fgets(buf
, int(sizeof(buf
)), fp
)) {
618 while (csspace(*ptr
))
620 if (*ptr
== '\0' || *ptr
== '#')
622 ptr
= strtok(ptr
, " \n\t");
626 if (sscanf(ptr
, "%d", &n
) != 1) {
627 error("%1:%2: bad map file", file
, lineno
);
631 if (n
< 0 || n
> 255) {
632 error("%1:%2: code out of range", file
, lineno
);
636 ptr
= strtok(0, " \n\t");
638 error("%1:%2: missing names", file
, lineno
);
642 for (; ptr
; ptr
= strtok(0, " \n\t"))
643 table
[n
] = new char_list(ptr
, table
[n
]);
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). */
669 // Indices into lig_chars[].
671 enum { CH_f
, CH_i
, CH_l
, CH_ff
, CH_fi
, CH_fl
, CH_ffi
, CH_ffl
};
673 // Each possible ligature appears in this table.
676 unsigned char c1
, c2
, res
;
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" },
686 static void usage(FILE *stream
);
688 int main(int argc
, char **argv
)
690 program_name
= argv
[0];
691 int special_flag
= 0;
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' },
700 while ((opt
= getopt_long(argc
, argv
, "svg:k:", long_options
, NULL
)) != EOF
)
711 long n
= strtol(optarg
, &ptr
, 0);
712 if ((n
== 0 && ptr
== optarg
)
716 error("invalid skewchar");
723 printf("GNU tfmtodit (groff) version %s\n", Version_string
);
727 case CHAR_MAX
+ 1: // --help
738 if (argc
- optind
!= 3) {
744 if (!g
.load(gf_file
))
747 const char *tfm_file
= argv
[optind
];
748 const char *map_file
= argv
[optind
+ 1];
749 const char *font_file
= argv
[optind
+ 2];
751 if (!t
.load(tfm_file
))
753 char_list
*table
[256];
754 if (!read_map(map_file
, table
))
757 if (!freopen(font_file
, "w", stdout
)) {
758 error("can't open `%1' for writing: %2", font_file
, strerror(errno
));
761 printf("name %s\n", font_file
);
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];
775 s1
= strrchr(internal_name
, *sep
);
776 if (s1
&& (!s
|| s1
> s
))
780 printf("internalname %s\n", s
? s
+ 1 : internal_name
);
782 if (t
.get_param(2, &n
)) {
784 printf("spacewidth %d\n", n
*MULTIPLIER
);
786 if (t
.get_param(1, &n
) && n
!= 0)
787 printf("slant %f\n", atan2(n
/double(1<<20), 1.0)*180.0/PI
);
789 if (!t
.get_param(5, &xheight
))
792 // Print the list of ligatures.
793 // First find the indices of each character that can participate in
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)
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.
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) {
810 if (t
.get_lig(i1
, i2
, &c
) && c
== r
) {
813 fputs("ligatures", stdout
);
815 printf(" %s", lig_table
[i
].ch
);
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.
825 kern_iterator
iter(&t
);
826 unsigned char c1
, c2
;
828 while (iter
.next(&c1
, &c2
, &k
))
829 if (c2
!= skewchar
) {
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
) {
835 printf("kernpairs\n");
838 printf("%s %s %d\n", p1
->ch
, p2
->ch
, k
);
842 char_list
unnamed("---");
843 for (i
= 0; i
< 256; i
++)
845 char_list
*p
= table
[i
] ? table
[i
] : &unnamed
;
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
);
855 for (j
= int(sizeof(m
)/sizeof(m
[0])) - 1; j
> 0; j
--)
858 for (k
= 1; k
<= j
; k
++)
859 printf(",%d", m
[k
]*MULTIPLIER
);
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
);
872 static void usage(FILE *stream
)
874 fprintf(stream
, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",