2 /* Copyright (C) 1989-1992, 2000, 2001, 2004 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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
61 extern "C" const char *Version_string;
63 /* Values in the tfm file should be multiplied by this. */
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;
95 char_info_word *char_info;
100 lig_kern_command *lig_kern;
106 int load(const char *);
112 int get_param(int, int *);
114 int get_design_size();
115 int get_lig(unsigned char, unsigned char, unsigned char *);
116 friend class kern_iterator;
119 class kern_iterator {
124 kern_iterator(tfm *);
125 int next(unsigned char *c1, unsigned char *c2, int *k);
129 kern_iterator::kern_iterator(tfm *p)
130 : t(p), c(t->bc), i(-1)
134 int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
136 for (; c <= t->ec; c++)
137 if (t->char_info[c - t->bc].tag == 1) {
139 i = t->char_info[c - t->bc].remainder;
140 if (t->lig_kern[i].skip_byte > 128)
141 i = (256*t->lig_kern[i].op_byte
142 + t->lig_kern[i].remainder);
145 int skip = t->lig_kern[i].skip_byte;
146 if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
148 *c2 = t->lig_kern[i].next_char;
149 *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
150 + t->lig_kern[i].remainder];
169 : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
174 int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
176 if (contains(c1) && char_info[c1 - bc].tag == 1) {
177 int i = char_info[c1 - bc].remainder;
178 if (lig_kern[i].skip_byte > 128)
179 i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
181 int skip = lig_kern[i].skip_byte;
184 // We are only interested in normal ligatures, for which
186 if (lig_kern[i].op_byte == 0
187 && lig_kern[i].next_char == c2) {
188 *cp = lig_kern[i].remainder;
199 int tfm::contains(int i)
201 return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
204 int tfm::get_width(int i)
206 return width[char_info[i - bc].width_index];
209 int tfm::get_height(int i)
211 return height[char_info[i - bc].height_index];
214 int tfm::get_depth(int i)
216 return depth[char_info[i - bc].depth_index];
219 int tfm::get_italic(int i)
221 return italic[char_info[i - bc].italic_index];
224 int tfm::get_param(int i, int *p)
226 if (i <= 0 || i > np)
234 int tfm::get_checksum()
239 int tfm::get_design_size()
256 int read2(unsigned char *&s)
264 int read4(unsigned char *&s)
275 int tfm::load(const char *file)
278 FILE *fp = fopen(file, FOPEN_RB);
280 error("can't open `%1': %2", file, strerror(errno));
285 if (c1 == EOF || c2 == EOF) {
287 error("unexpected end of file on `%1'", file);
290 int lf = (c1 << 8) + c2;
291 int toread = lf*4 - 2;
292 unsigned char *buf = new unsigned char[toread];
293 if (fread(buf, 1, toread, fp) != (size_t)toread) {
295 error("unexpected end of file on `%1'", file);
297 error("error on file `%1'", file);
304 error("bad tfm file `%1': impossibly short", file);
308 unsigned char *ptr = buf;
320 if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
321 error("bad tfm file `%1': lengths do not sum", file);
326 error("bad tfm file `%1': header too short", file);
330 char_info = new char_info_word[ec - bc + 1];
332 height = new int[nh];
334 italic = new int[ni];
335 lig_kern = new lig_kern_command[nl];
342 for (i = 0; i < ec - bc + 1; i++) {
343 char_info[i].width_index = *ptr++;
344 unsigned char tem = *ptr++;
345 char_info[i].depth_index = tem & 0xf;
346 char_info[i].height_index = tem >> 4;
348 char_info[i].italic_index = tem >> 2;
349 char_info[i].tag = tem & 3;
350 char_info[i].remainder = *ptr++;
352 for (i = 0; i < nw; i++)
353 width[i] = read4(ptr);
354 for (i = 0; i < nh; i++)
355 height[i] = read4(ptr);
356 for (i = 0; i < nd; i++)
357 depth[i] = read4(ptr);
358 for (i = 0; i < ni; i++)
359 italic[i] = read4(ptr);
360 for (i = 0; i < nl; i++) {
361 lig_kern[i].skip_byte = *ptr++;
362 lig_kern[i].next_char = *ptr++;
363 lig_kern[i].op_byte = *ptr++;
364 lig_kern[i].remainder = *ptr++;
366 for (i = 0; i < nk; i++)
367 kern[i] = read4(ptr);
369 for (i = 0; i < np; i++)
370 param[i] = read4(ptr);
371 assert(ptr == buf + lf*4 - 2);
379 static int sread4(int *p, FILE *fp);
380 static int uread3(int *p, FILE *fp);
381 static int uread2(int *p, FILE *fp);
382 static int skip(int n, FILE *fp);
385 int load(const char *file);
386 int get_left_adjustment(int i) { return left[i]; }
387 int get_right_adjustment(int i) { return right[i]; }
392 for (int i = 0; i < 256; i++)
393 left[i] = right[i] = 0;
396 int gf::load(const char *file)
413 int got_an_adjustment = 0;
414 int pending_adjustment = 0;
415 int left_adj = 0, right_adj = 0; // pacify compiler
416 const int gf_id_byte = 131;
418 FILE *fp = fopen(file, FOPEN_RB);
420 error("can't open `%1': %2", file, strerror(errno));
423 if (getc(fp) != pre || getc(fp) != gf_id_byte) {
424 error("bad gf file");
438 if ((op >= paint_0 && op <= paint_0 + 63)
439 || (op >= new_row_0 && op <= new_row_0 + 164))
464 if (!sread4(&code, fp))
466 if (pending_adjustment) {
467 pending_adjustment = 0;
468 left[code & 0377] = left_adj;
469 right[code & 0377] = right_adj;
480 if (pending_adjustment) {
481 pending_adjustment = 0;
482 left[code] = left_adj;
483 right[code] = right_adj;
495 if (fread(buf, 1, len, fp) != (size_t)len)
497 if (len == 10 /* strlen("adjustment") */
498 && memcmp(buf, "adjustment", len) == 0) {
505 if (!sread4(&left_adj, fp))
513 if (!sread4(&right_adj, fp))
515 got_an_adjustment = 1;
516 pending_adjustment = 1;
521 if (!uread2(&n, fp) || !skip(n, fp))
525 if (!uread3(&n, fp) || !skip(n, fp))
529 if (!sread4(&n, fp) || !skip(n, fp))
537 fatal("unrecognized opcode `%1'", op);
541 if (!got_an_adjustment)
542 warning("no adjustment specials found in gf file");
545 error("unexpected end of file");
549 int gf::sread4(int *p, FILE *fp)
560 return !ferror(fp) && !feof(fp);
563 int gf::uread3(int *p, FILE *fp)
570 return !ferror(fp) && !feof(fp);
573 int gf::uread2(int *p, FILE *fp)
578 return !ferror(fp) && !feof(fp);
581 int gf::skip(int n, FILE *fp)
593 char_list(const char *, char_list * = 0);
596 char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
601 int read_map(const char *file, char_list **table)
604 FILE *fp = fopen(file, "r");
606 error("can't open `%1': %2", file, strerror(errno));
609 for (int i = 0; i < 256; i++)
613 while (fgets(buf, int(sizeof(buf)), fp)) {
616 while (csspace(*ptr))
618 if (*ptr == '\0' || *ptr == '#')
620 ptr = strtok(ptr, " \n\t");
624 if (sscanf(ptr, "%d", &n) != 1) {
625 error("%1:%2: bad map file", file, lineno);
629 if (n < 0 || n > 255) {
630 error("%1:%2: code out of range", file, lineno);
634 ptr = strtok(0, " \n\t");
636 error("%1:%2: missing names", file, lineno);
640 for (; ptr; ptr = strtok(0, " \n\t"))
641 table[n] = new char_list(ptr, table[n]);
648 /* Every character that can participate in a ligature appears in the
649 lig_chars table. `ch' gives the full-name of the character, `name'
650 gives the groff name of the character, `i' gives its index in
651 the encoding, which is filled in later (-1 if it does not appear). */
667 // Indices into lig_chars[].
669 enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
671 // Each possible ligature appears in this table.
674 unsigned char c1, c2, res;
677 { CH_f, CH_f, CH_ff, "ff" },
678 { CH_f, CH_i, CH_fi, "fi" },
679 { CH_f, CH_l, CH_fl, "fl" },
680 { CH_ff, CH_i, CH_ffi, "ffi" },
681 { CH_ff, CH_l, CH_ffl, "ffl" },
684 static void usage(FILE *stream);
686 int main(int argc, char **argv)
688 program_name = argv[0];
689 int special_flag = 0;
692 const char *gf_file = 0;
693 static const struct option long_options[] = {
694 { "help", no_argument, 0, CHAR_MAX + 1 },
695 { "version", no_argument, 0, 'v' },
698 while ((opt = getopt_long(argc, argv, "svg:k:", long_options, NULL)) != EOF)
709 long n = strtol(optarg, &ptr, 0);
710 if ((n == 0 && ptr == optarg)
714 error("invalid skewchar");
721 printf("GNU tfmtodit (groff) version %s\n", Version_string);
725 case CHAR_MAX + 1: // --help
736 if (argc - optind != 3) {
742 if (!g.load(gf_file))
745 const char *tfm_file = argv[optind];
746 const char *map_file = argv[optind + 1];
747 const char *font_file = argv[optind + 2];
749 if (!t.load(tfm_file))
751 char_list *table[256];
752 if (!read_map(map_file, table))
755 if (!freopen(font_file, "w", stdout)) {
756 error("can't open `%1' for writing: %2", font_file, strerror(errno));
759 printf("name %s\n", font_file);
761 fputs("special\n", stdout);
762 char *internal_name = strsave(argv[optind]);
763 int len = strlen(internal_name);
764 if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
765 internal_name[len - 4] = '\0';
766 // DIR_SEPS[] are possible directory separator characters, see nonposix.h.
767 // We want the rightmost separator of all possible ones.
768 // Example: d:/foo\\bar.
769 const char *s = strrchr(internal_name, DIR_SEPS[0]), *s1;
770 const char *sep = &DIR_SEPS[1];
773 s1 = strrchr(internal_name, *sep);
774 if (s1 && (!s || s1 > s))
778 printf("internalname %s\n", s ? s + 1 : internal_name);
780 if (t.get_param(2, &n)) {
782 printf("spacewidth %d\n", n*MULTIPLIER);
784 if (t.get_param(1, &n) && n != 0)
785 printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/PI);
787 if (!t.get_param(5, &xheight))
790 // Print the list of ligatures.
791 // First find the indices of each character that can participate in
793 for (i = 0; i < 256; i++)
794 for (unsigned int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
795 for (char_list *p = table[i]; p; p = p->next)
796 if (strcmp(lig_chars[j].ch, p->ch) == 0)
798 // For each possible ligature, if its participants all exist,
799 // and it appears as a ligature in the tfm file, include in
800 // the list of ligatures.
802 for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
803 int i1 = lig_chars[lig_table[i].c1].i;
804 int i2 = lig_chars[lig_table[i].c2].i;
805 int r = lig_chars[lig_table[i].res].i;
806 if (i1 >= 0 && i2 >= 0 && r >= 0) {
808 if (t.get_lig(i1, i2, &c) && c == r) {
811 fputs("ligatures", stdout);
813 printf(" %s", lig_table[i].ch);
818 fputs(" 0\n", stdout);
819 printf("checksum %d\n", t.get_checksum());
820 printf("designsize %d\n", t.get_design_size());
821 // Now print out the kerning information.
823 kern_iterator iter(&t);
824 unsigned char c1, c2;
826 while (iter.next(&c1, &c2, &k))
827 if (c2 != skewchar) {
829 char_list *q = table[c2];
830 for (char_list *p1 = table[c1]; p1; p1 = p1->next)
831 for (char_list *p2 = q; p2; p2 = p2->next) {
833 printf("kernpairs\n");
836 printf("%s %s %d\n", p1->ch, p2->ch, k);
840 char_list unnamed("---");
841 for (i = 0; i < 256; i++)
843 char_list *p = table[i] ? table[i] : &unnamed;
845 m[0] = t.get_width(i);
846 m[1] = t.get_height(i);
847 m[2] = t.get_depth(i);
848 m[3] = t.get_italic(i);
849 m[4] = g.get_left_adjustment(i);
850 m[5] = g.get_right_adjustment(i);
851 printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
853 for (j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
856 for (k = 1; k <= j; k++)
857 printf(",%d", m[k]*MULTIPLIER);
863 printf("\t%d\t%04o\n", type, i);
864 for (p = p->next; p; p = p->next)
865 printf("%s\t\"\n", p->ch);
870 static void usage(FILE *stream)
872 fprintf(stream, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",