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",