2 /* Copyright (C) 1989-1992, 2000, 2001 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
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 2, 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 COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
62 extern "C" const char *Version_string
;
64 /* Values in the tfm file should be multiplied by this. */
68 struct char_info_word
{
69 unsigned char width_index
;
74 unsigned char remainder
;
77 struct lig_kern_command
{
78 unsigned char skip_byte
;
79 unsigned char next_char
;
80 unsigned char op_byte
;
81 unsigned char remainder
;
96 char_info_word
*char_info
;
101 lig_kern_command
*lig_kern
;
107 int load(const char *);
113 int get_param(int, int *);
115 int get_design_size();
116 int get_lig(unsigned char, unsigned char, unsigned char *);
117 friend class kern_iterator
;
120 class kern_iterator
{
125 kern_iterator(tfm
*);
126 int next(unsigned char *c1
, unsigned char *c2
, int *k
);
130 kern_iterator::kern_iterator(tfm
*p
)
131 : t(p
), c(t
->bc
), i(-1)
135 int kern_iterator::next(unsigned char *c1
, unsigned char *c2
, int *k
)
137 for (; c
<= t
->ec
; c
++)
138 if (t
->char_info
[c
- t
->bc
].tag
== 1) {
140 i
= t
->char_info
[c
- t
->bc
].remainder
;
141 if (t
->lig_kern
[i
].skip_byte
> 128)
142 i
= (256*t
->lig_kern
[i
].op_byte
143 + t
->lig_kern
[i
].remainder
);
146 int skip
= t
->lig_kern
[i
].skip_byte
;
147 if (skip
<= 128 && t
->lig_kern
[i
].op_byte
>= 128) {
149 *c2
= t
->lig_kern
[i
].next_char
;
150 *k
= t
->kern
[256*(t
->lig_kern
[i
].op_byte
- 128)
151 + t
->lig_kern
[i
].remainder
];
170 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
175 int tfm::get_lig(unsigned char c1
, unsigned char c2
, unsigned char *cp
)
177 if (contains(c1
) && char_info
[c1
- bc
].tag
== 1) {
178 int i
= char_info
[c1
- bc
].remainder
;
179 if (lig_kern
[i
].skip_byte
> 128)
180 i
= 256*lig_kern
[i
].op_byte
+ lig_kern
[i
].remainder
;
182 int skip
= lig_kern
[i
].skip_byte
;
185 // We are only interested in normal ligatures, for which
187 if (lig_kern
[i
].op_byte
== 0
188 && lig_kern
[i
].next_char
== c2
) {
189 *cp
= lig_kern
[i
].remainder
;
200 int tfm::contains(int i
)
202 return i
>= bc
&& i
<= ec
&& char_info
[i
- bc
].width_index
!= 0;
205 int tfm::get_width(int i
)
207 return width
[char_info
[i
- bc
].width_index
];
210 int tfm::get_height(int i
)
212 return height
[char_info
[i
- bc
].height_index
];
215 int tfm::get_depth(int i
)
217 return depth
[char_info
[i
- bc
].depth_index
];
220 int tfm::get_italic(int i
)
222 return italic
[char_info
[i
- bc
].italic_index
];
225 int tfm::get_param(int i
, int *p
)
227 if (i
<= 0 || i
> np
)
235 int tfm::get_checksum()
240 int tfm::get_design_size()
257 int read2(unsigned char *&s
)
265 int read4(unsigned char *&s
)
276 int tfm::load(const char *file
)
279 FILE *fp
= fopen(file
, FOPEN_RB
);
281 error("can't open `%1': %2", file
, strerror(errno
));
286 if (c1
== EOF
|| c2
== EOF
) {
288 error("unexpected end of file on `%1'", file
);
291 int lf
= (c1
<< 8) + c2
;
292 int toread
= lf
*4 - 2;
293 unsigned char *buf
= new unsigned char[toread
];
294 if (fread(buf
, 1, toread
, fp
) != (size_t)toread
) {
296 error("unexpected end of file on `%1'", file
);
298 error("error on file `%1'", file
);
305 error("bad tfm file `%1': impossibly short", file
);
309 unsigned char *ptr
= buf
;
321 if (6 + lh
+ (ec
- bc
+ 1) + nw
+ nh
+ nd
+ ni
+ nl
+ nk
+ ne
+ np
!= lf
) {
322 error("bad tfm file `%1': lengths do not sum", file
);
327 error("bad tfm file `%1': header too short", file
);
331 char_info
= new char_info_word
[ec
- bc
+ 1];
333 height
= new int[nh
];
335 italic
= new int[ni
];
336 lig_kern
= new lig_kern_command
[nl
];
343 for (i
= 0; i
< ec
- bc
+ 1; i
++) {
344 char_info
[i
].width_index
= *ptr
++;
345 unsigned char tem
= *ptr
++;
346 char_info
[i
].depth_index
= tem
& 0xf;
347 char_info
[i
].height_index
= tem
>> 4;
349 char_info
[i
].italic_index
= tem
>> 2;
350 char_info
[i
].tag
= tem
& 3;
351 char_info
[i
].remainder
= *ptr
++;
353 for (i
= 0; i
< nw
; i
++)
354 width
[i
] = read4(ptr
);
355 for (i
= 0; i
< nh
; i
++)
356 height
[i
] = read4(ptr
);
357 for (i
= 0; i
< nd
; i
++)
358 depth
[i
] = read4(ptr
);
359 for (i
= 0; i
< ni
; i
++)
360 italic
[i
] = read4(ptr
);
361 for (i
= 0; i
< nl
; i
++) {
362 lig_kern
[i
].skip_byte
= *ptr
++;
363 lig_kern
[i
].next_char
= *ptr
++;
364 lig_kern
[i
].op_byte
= *ptr
++;
365 lig_kern
[i
].remainder
= *ptr
++;
367 for (i
= 0; i
< nk
; i
++)
368 kern
[i
] = read4(ptr
);
370 for (i
= 0; i
< np
; i
++)
371 param
[i
] = read4(ptr
);
372 assert(ptr
== buf
+ lf
*4 - 2);
380 static int sread4(int *p
, FILE *fp
);
381 static int uread3(int *p
, FILE *fp
);
382 static int uread2(int *p
, FILE *fp
);
383 static int skip(int n
, FILE *fp
);
386 int load(const char *file
);
387 int get_left_adjustment(int i
) { return left
[i
]; }
388 int get_right_adjustment(int i
) { return right
[i
]; }
393 for (int i
= 0; i
< 256; i
++)
394 left
[i
] = right
[i
] = 0;
397 int gf::load(const char *file
)
414 int got_an_adjustment
= 0;
415 int pending_adjustment
= 0;
416 int left_adj
, right_adj
;
417 const int gf_id_byte
= 131;
419 FILE *fp
= fopen(file
, FOPEN_RB
);
421 error("can't open `%1': %2", file
, strerror(errno
));
424 if (getc(fp
) != pre
|| getc(fp
) != gf_id_byte
) {
425 error("bad gf file");
439 if ((op
>= paint_0
&& op
<= paint_0
+ 63)
440 || (op
>= new_row_0
&& op
<= new_row_0
+ 164))
465 if (!sread4(&code
, fp
))
467 if (pending_adjustment
) {
468 pending_adjustment
= 0;
469 left
[code
& 0377] = left_adj
;
470 right
[code
& 0377] = right_adj
;
481 if (pending_adjustment
) {
482 pending_adjustment
= 0;
483 left
[code
] = left_adj
;
484 right
[code
] = right_adj
;
496 if (fread(buf
, 1, len
, fp
) != (size_t)len
)
498 if (len
== 10 /* strlen("adjustment") */
499 && memcmp(buf
, "adjustment", len
) == 0) {
506 if (!sread4(&left_adj
, fp
))
514 if (!sread4(&right_adj
, fp
))
516 got_an_adjustment
= 1;
517 pending_adjustment
= 1;
522 if (!uread2(&n
, fp
) || !skip(n
, fp
))
526 if (!uread3(&n
, fp
) || !skip(n
, fp
))
530 if (!sread4(&n
, fp
) || !skip(n
, fp
))
538 fatal("unrecognized opcode `%1'", op
);
542 if (!got_an_adjustment
)
543 warning("no adjustment specials found in gf file");
546 error("unexpected end of file");
550 int gf::sread4(int *p
, FILE *fp
)
561 return !ferror(fp
) && !feof(fp
);
564 int gf::uread3(int *p
, FILE *fp
)
571 return !ferror(fp
) && !feof(fp
);
574 int gf::uread2(int *p
, FILE *fp
)
579 return !ferror(fp
) && !feof(fp
);
582 int gf::skip(int n
, FILE *fp
)
594 char_list(const char *, char_list
* = 0);
597 char_list::char_list(const char *s
, char_list
*p
) : ch(strsave(s
)), next(p
)
602 int read_map(const char *file
, char_list
**table
)
605 FILE *fp
= fopen(file
, "r");
607 error("can't open `%1': %2", file
, strerror(errno
));
610 for (int i
= 0; i
< 256; i
++)
614 while (fgets(buf
, int(sizeof(buf
)), fp
)) {
617 while (csspace(*ptr
))
619 if (*ptr
== '\0' || *ptr
== '#')
621 ptr
= strtok(ptr
, " \n\t");
625 if (sscanf(ptr
, "%d", &n
) != 1) {
626 error("%1:%2: bad map file", file
, lineno
);
630 if (n
< 0 || n
> 255) {
631 error("%1:%2: code out of range", file
, lineno
);
635 ptr
= strtok(0, " \n\t");
637 error("%1:%2: missing names", file
, lineno
);
641 for (; ptr
; ptr
= strtok(0, " \n\t"))
642 table
[n
] = new char_list(ptr
, table
[n
]);
649 /* Every character that can participate in a ligature appears in the
650 lig_chars table. `ch' gives the full-name of the character, `name'
651 gives the groff name of the character, `i' gives its index in
652 the encoding, which is filled in later (-1 if it does not appear). */
668 // Indices into lig_chars[].
670 enum { CH_f
, CH_i
, CH_l
, CH_ff
, CH_fi
, CH_fl
, CH_ffi
, CH_ffl
};
672 // Each possible ligature appears in this table.
675 unsigned char c1
, c2
, res
;
678 { CH_f
, CH_f
, CH_ff
, "ff" },
679 { CH_f
, CH_i
, CH_fi
, "fi" },
680 { CH_f
, CH_l
, CH_fl
, "fl" },
681 { CH_ff
, CH_i
, CH_ffi
, "ffi" },
682 { CH_ff
, CH_l
, CH_ffl
, "ffl" },
685 static void usage(FILE *stream
);
687 int main(int argc
, char **argv
)
689 program_name
= argv
[0];
690 int special_flag
= 0;
693 const char *gf_file
= 0;
694 static const struct option long_options
[] = {
695 { "help", no_argument
, 0, CHAR_MAX
+ 1 },
696 { "version", no_argument
, 0, 'v' },
699 while ((opt
= getopt_long(argc
, argv
, "svg:k:", long_options
, NULL
)) != EOF
)
710 long n
= strtol(optarg
, &ptr
, 0);
711 if ((n
== 0 && ptr
== optarg
)
715 error("invalid skewchar");
722 printf("GNU tfmtodit (groff) version %s\n", Version_string
);
726 case CHAR_MAX
+ 1: // --help
737 if (argc
- optind
!= 3) {
743 if (!g
.load(gf_file
))
746 const char *tfm_file
= argv
[optind
];
747 const char *map_file
= argv
[optind
+ 1];
748 const char *font_file
= argv
[optind
+ 2];
750 if (!t
.load(tfm_file
))
752 char_list
*table
[256];
753 if (!read_map(map_file
, table
))
756 if (!freopen(font_file
, "w", stdout
)) {
757 error("can't open `%1' for writing: %2", font_file
, strerror(errno
));
760 printf("name %s\n", font_file
);
762 fputs("special\n", stdout
);
763 char *internal_name
= strsave(argv
[optind
]);
764 int len
= strlen(internal_name
);
765 if (len
> 4 && strcmp(internal_name
+ len
- 4, ".tfm") == 0)
766 internal_name
[len
- 4] = '\0';
767 // DIR_SEPS[] are possible directory separator characters, see nonposix.h.
768 // We want the rightmost separator of all possible ones.
769 // Example: d:/foo\\bar.
770 const char *s
= strrchr(internal_name
, DIR_SEPS
[0]), *s1
;
771 const char *sep
= &DIR_SEPS
[1];
774 s1
= strrchr(internal_name
, *sep
);
775 if (s1
&& (!s
|| s1
> s
))
779 printf("internalname %s\n", s
? s
+ 1 : internal_name
);
781 if (t
.get_param(2, &n
)) {
783 printf("spacewidth %d\n", n
*MULTIPLIER
);
785 if (t
.get_param(1, &n
) && n
!= 0)
786 printf("slant %f\n", atan2(n
/double(1<<20), 1.0)*180.0/PI
);
788 if (!t
.get_param(5, &xheight
))
791 // Print the list of ligatures.
792 // First find the indices of each character that can participate in
794 for (i
= 0; i
< 256; i
++)
795 for (unsigned int j
= 0; j
< sizeof(lig_chars
)/sizeof(lig_chars
[0]); j
++)
796 for (char_list
*p
= table
[i
]; p
; p
= p
->next
)
797 if (strcmp(lig_chars
[j
].ch
, p
->ch
) == 0)
799 // For each possible ligature, if its participants all exist,
800 // and it appears as a ligature in the tfm file, include in
801 // the list of ligatures.
803 for (i
= 0; i
< sizeof(lig_table
)/sizeof(lig_table
[0]); i
++) {
804 int i1
= lig_chars
[lig_table
[i
].c1
].i
;
805 int i2
= lig_chars
[lig_table
[i
].c2
].i
;
806 int r
= lig_chars
[lig_table
[i
].res
].i
;
807 if (i1
>= 0 && i2
>= 0 && r
>= 0) {
809 if (t
.get_lig(i1
, i2
, &c
) && c
== r
) {
812 fputs("ligatures", stdout
);
814 printf(" %s", lig_table
[i
].ch
);
819 fputs(" 0\n", stdout
);
820 printf("checksum %d\n", t
.get_checksum());
821 printf("designsize %d\n", t
.get_design_size());
822 // Now print out the kerning information.
824 kern_iterator
iter(&t
);
825 unsigned char c1
, c2
;
827 while (iter
.next(&c1
, &c2
, &k
))
828 if (c2
!= skewchar
) {
830 char_list
*q
= table
[c2
];
831 for (char_list
*p1
= table
[c1
]; p1
; p1
= p1
->next
)
832 for (char_list
*p2
= q
; p2
; p2
= p2
->next
) {
834 printf("kernpairs\n");
837 printf("%s %s %d\n", p1
->ch
, p2
->ch
, k
);
841 char_list
unnamed("---");
842 for (i
= 0; i
< 256; i
++)
844 char_list
*p
= table
[i
] ? table
[i
] : &unnamed
;
846 m
[0] = t
.get_width(i
);
847 m
[1] = t
.get_height(i
);
848 m
[2] = t
.get_depth(i
);
849 m
[3] = t
.get_italic(i
);
850 m
[4] = g
.get_left_adjustment(i
);
851 m
[5] = g
.get_right_adjustment(i
);
852 printf("%s\t%d", p
->ch
, m
[0]*MULTIPLIER
);
854 for (j
= int(sizeof(m
)/sizeof(m
[0])) - 1; j
> 0; j
--)
857 for (k
= 1; k
<= j
; k
++)
858 printf(",%d", m
[k
]*MULTIPLIER
);
864 printf("\t%d\t%04o\n", type
, i
);
865 for (p
= p
->next
; p
; p
= p
->next
)
866 printf("%s\t\"\n", p
->ch
);
871 static void usage(FILE *stream
)
873 fprintf(stream
, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",