169491Sbostic // -*- C++ -*-
269491Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
369491Sbostic Written by James Clark (jjc@jclark.com)
469491Sbostic
569491Sbostic This file is part of groff.
669491Sbostic
769491Sbostic groff is free software; you can redistribute it and/or modify it under
869491Sbostic the terms of the GNU General Public License as published by the Free
969491Sbostic Software Foundation; either version 2, or (at your option) any later
1069491Sbostic version.
1169491Sbostic
1269491Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
1369491Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
1469491Sbostic FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1569491Sbostic for more details.
1669491Sbostic
1769491Sbostic You should have received a copy of the GNU General Public License along
1869491Sbostic with groff; see the file COPYING. If not, write to the Free Software
1969491Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
2069491Sbostic
2169491Sbostic /* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
2269491Sbostic but I haven't tested them. */
2369491Sbostic
2469491Sbostic /* Groff requires more font metric information than TeX. The reason
2569491Sbostic for this is that TeX has separate Math Italic fonts, whereas groff
2669491Sbostic uses normal italic fonts for math. The two additional pieces of
2769491Sbostic information required by groff correspond to the two arguments to the
2869491Sbostic math_fit() macro in the Metafont programs for the CM fonts. In the
2969491Sbostic case of a font for which math_fitting is false, these two arguments
3069491Sbostic are normally ignored by Metafont. We need to get hold of these two
3169491Sbostic parameters and put them in the groff font file.
3269491Sbostic
3369491Sbostic We do this by loading this definition after cmbase when creating cm.base.
3469491Sbostic
3569491Sbostic def ignore_math_fit(expr left_adjustment,right_adjustment) =
3669491Sbostic special "adjustment";
3769491Sbostic numspecial left_adjustment*16/designsize;
3869491Sbostic numspecial right_adjustment*16/designsize;
3969491Sbostic enddef;
4069491Sbostic
4169491Sbostic This puts the two arguments to the math_fit macro into the gf file.
4269491Sbostic (They will appear in the gf file immediately before the character to
4369491Sbostic which they apply.) We then create a gf file using this cm.base. Then
4469491Sbostic we run tfmtodit and specify this gf file with the -g option.
4569491Sbostic
4669491Sbostic This need only be done for a font for which math_fitting is false;
4769491Sbostic When it's true, the left_correction and subscript_correction should
4869491Sbostic both be zero. */
4969491Sbostic
5069491Sbostic #include <stdio.h>
51*69504Sbostic #include <unistd.h>
5269491Sbostic #include <stdlib.h>
5369491Sbostic #include <math.h>
5469491Sbostic #include <string.h>
5569491Sbostic #include <errno.h>
5669491Sbostic #include "lib.h"
5769491Sbostic #include "errarg.h"
5869491Sbostic #include "error.h"
5969491Sbostic #include "assert.h"
6069491Sbostic #include "cset.h"
6169491Sbostic
6269491Sbostic /* Values in the tfm file should be multiplied by this. */
6369491Sbostic
6469491Sbostic #define MULTIPLIER 1
6569491Sbostic
6669491Sbostic struct char_info_word {
6769491Sbostic unsigned char width_index;
6869491Sbostic char height_index;
6969491Sbostic char depth_index;
7069491Sbostic char italic_index;
7169491Sbostic char tag;
7269491Sbostic unsigned char remainder;
7369491Sbostic };
7469491Sbostic
7569491Sbostic struct lig_kern_command {
7669491Sbostic unsigned char skip_byte;
7769491Sbostic unsigned char next_char;
7869491Sbostic unsigned char op_byte;
7969491Sbostic unsigned char remainder;
8069491Sbostic };
8169491Sbostic
8269491Sbostic class tfm {
8369491Sbostic int bc;
8469491Sbostic int ec;
8569491Sbostic int nw;
8669491Sbostic int nh;
8769491Sbostic int nd;
8869491Sbostic int ni;
8969491Sbostic int nl;
9069491Sbostic int nk;
9169491Sbostic int np;
9269491Sbostic int cs;
9369491Sbostic int ds;
9469491Sbostic char_info_word *char_info;
9569491Sbostic int *width;
9669491Sbostic int *height;
9769491Sbostic int *depth;
9869491Sbostic int *italic;
9969491Sbostic lig_kern_command *lig_kern;
10069491Sbostic int *kern;
10169491Sbostic int *param;
10269491Sbostic public:
10369491Sbostic tfm();
10469491Sbostic ~tfm();
10569491Sbostic int load(const char *);
10669491Sbostic int contains(int);
10769491Sbostic int get_width(int);
10869491Sbostic int get_height(int);
10969491Sbostic int get_depth(int);
11069491Sbostic int get_italic(int);
11169491Sbostic int get_param(int, int *);
11269491Sbostic int get_checksum();
11369491Sbostic int get_design_size();
11469491Sbostic int get_lig(unsigned char, unsigned char, unsigned char *);
11569491Sbostic friend class kern_iterator;
11669491Sbostic };
11769491Sbostic
11869491Sbostic class kern_iterator {
11969491Sbostic tfm *t;
12069491Sbostic int c;
12169491Sbostic int i;
12269491Sbostic public:
12369491Sbostic kern_iterator(tfm *);
12469491Sbostic int next(unsigned char *c1, unsigned char *c2, int *k);
12569491Sbostic };
12669491Sbostic
12769491Sbostic
kern_iterator(tfm * p)12869491Sbostic kern_iterator::kern_iterator(tfm *p)
12969491Sbostic : t(p), i(-1), c(t->bc)
13069491Sbostic {
13169491Sbostic }
13269491Sbostic
next(unsigned char * c1,unsigned char * c2,int * k)13369491Sbostic int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
13469491Sbostic {
13569491Sbostic for (; c <= t->ec; c++)
13669491Sbostic if (t->char_info[c - t->bc].tag == 1) {
13769491Sbostic if (i < 0) {
13869491Sbostic i = t->char_info[c - t->bc].remainder;
13969491Sbostic if (t->lig_kern[i].skip_byte > 128)
14069491Sbostic i = (256*t->lig_kern[i].op_byte
14169491Sbostic + t->lig_kern[i].remainder);
14269491Sbostic }
14369491Sbostic for (;;) {
14469491Sbostic int skip = t->lig_kern[i].skip_byte;
14569491Sbostic if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
14669491Sbostic *c1 = c;
14769491Sbostic *c2 = t->lig_kern[i].next_char;
14869491Sbostic *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
14969491Sbostic + t->lig_kern[i].remainder];
15069491Sbostic if (skip == 128) {
15169491Sbostic c++;
15269491Sbostic i = -1;
15369491Sbostic }
15469491Sbostic else
15569491Sbostic i += skip + 1;
15669491Sbostic return 1;
15769491Sbostic }
15869491Sbostic if (skip >= 128)
15969491Sbostic break;
16069491Sbostic i += skip + 1;
16169491Sbostic }
16269491Sbostic i = -1;
16369491Sbostic }
16469491Sbostic return 0;
16569491Sbostic }
16669491Sbostic
tfm()16769491Sbostic tfm::tfm()
16869491Sbostic : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
16969491Sbostic kern(0), param(0)
17069491Sbostic {
17169491Sbostic }
17269491Sbostic
get_lig(unsigned char c1,unsigned char c2,unsigned char * cp)17369491Sbostic int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
17469491Sbostic {
17569491Sbostic if (contains(c1) && char_info[c1 - bc].tag == 1) {
17669491Sbostic int i = char_info[c1 - bc].remainder;
17769491Sbostic if (lig_kern[i].skip_byte > 128)
17869491Sbostic i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
17969491Sbostic for (;;) {
18069491Sbostic int skip = lig_kern[i].skip_byte;
18169491Sbostic if (skip > 128)
18269491Sbostic break;
18369491Sbostic // We are only interested in normal ligatures, for which
18469491Sbostic // op_byte == 0.
18569491Sbostic if (lig_kern[i].op_byte == 0
18669491Sbostic && lig_kern[i].next_char == c2) {
18769491Sbostic *cp = lig_kern[i].remainder;
18869491Sbostic return 1;
18969491Sbostic }
19069491Sbostic if (skip == 128)
19169491Sbostic break;
19269491Sbostic i += skip + 1;
19369491Sbostic }
19469491Sbostic }
19569491Sbostic return 0;
19669491Sbostic }
19769491Sbostic
contains(int i)19869491Sbostic int tfm::contains(int i)
19969491Sbostic {
20069491Sbostic return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
20169491Sbostic }
20269491Sbostic
get_width(int i)20369491Sbostic int tfm::get_width(int i)
20469491Sbostic {
20569491Sbostic return width[char_info[i - bc].width_index];
20669491Sbostic }
20769491Sbostic
get_height(int i)20869491Sbostic int tfm::get_height(int i)
20969491Sbostic {
21069491Sbostic return height[char_info[i - bc].height_index];
21169491Sbostic }
21269491Sbostic
get_depth(int i)21369491Sbostic int tfm::get_depth(int i)
21469491Sbostic {
21569491Sbostic return depth[char_info[i - bc].depth_index];
21669491Sbostic }
21769491Sbostic
get_italic(int i)21869491Sbostic int tfm::get_italic(int i)
21969491Sbostic {
22069491Sbostic return italic[char_info[i - bc].italic_index];
22169491Sbostic }
22269491Sbostic
get_param(int i,int * p)22369491Sbostic int tfm::get_param(int i, int *p)
22469491Sbostic {
22569491Sbostic if (i <= 0 || i > np)
22669491Sbostic return 0;
22769491Sbostic else {
22869491Sbostic *p = param[i - 1];
22969491Sbostic return 1;
23069491Sbostic }
23169491Sbostic }
23269491Sbostic
get_checksum()23369491Sbostic int tfm::get_checksum()
23469491Sbostic {
23569491Sbostic return cs;
23669491Sbostic }
23769491Sbostic
get_design_size()23869491Sbostic int tfm::get_design_size()
23969491Sbostic {
24069491Sbostic return ds;
24169491Sbostic }
24269491Sbostic
~tfm()24369491Sbostic tfm::~tfm()
24469491Sbostic {
24569491Sbostic a_delete char_info;
24669491Sbostic a_delete width;
24769491Sbostic a_delete height;
24869491Sbostic a_delete depth;
24969491Sbostic a_delete italic;
25069491Sbostic a_delete lig_kern;
25169491Sbostic a_delete kern;
25269491Sbostic a_delete param;
25369491Sbostic }
25469491Sbostic
read2(unsigned char * & s)25569491Sbostic int read2(unsigned char *&s)
25669491Sbostic {
25769491Sbostic int n;
25869491Sbostic n = *s++ << 8;
25969491Sbostic n |= *s++;
26069491Sbostic return n;
26169491Sbostic }
26269491Sbostic
read4(unsigned char * & s)26369491Sbostic int read4(unsigned char *&s)
26469491Sbostic {
26569491Sbostic int n;
26669491Sbostic n = *s++ << 24;
26769491Sbostic n |= *s++ << 16;
26869491Sbostic n |= *s++ << 8;
26969491Sbostic n |= *s++;
27069491Sbostic return n;
27169491Sbostic }
27269491Sbostic
27369491Sbostic
load(const char * file)27469491Sbostic int tfm::load(const char *file)
27569491Sbostic {
27669491Sbostic errno = 0;
27769491Sbostic FILE *fp = fopen(file, "r");
27869491Sbostic if (!fp) {
27969491Sbostic error("can't open `%1': %2", file, strerror(errno));
28069491Sbostic return 0;
28169491Sbostic }
28269491Sbostic int c1 = getc(fp);
28369491Sbostic int c2 = getc(fp);
28469491Sbostic if (c1 == EOF || c2 == EOF) {
28569491Sbostic fclose(fp);
28669491Sbostic error("unexpected end of file on `%1'", file);
28769491Sbostic return 0;
28869491Sbostic }
28969491Sbostic int lf = (c1 << 8) + c2;
29069491Sbostic int toread = lf*4 - 2;
29169491Sbostic unsigned char *buf = new unsigned char[toread];
29269491Sbostic if (fread(buf, 1, toread, fp) != toread) {
29369491Sbostic if (feof(fp))
29469491Sbostic error("unexpected end of file on `%1'", file);
29569491Sbostic else
29669491Sbostic error("error on file `%1'", file);
29769491Sbostic a_delete buf;
29869491Sbostic fclose(fp);
29969491Sbostic return 0;
30069491Sbostic }
30169491Sbostic fclose(fp);
30269491Sbostic if (lf < 6) {
30369491Sbostic error("bad tfm file `%1': impossibly short", file);
30469491Sbostic a_delete buf;
30569491Sbostic return 0;
30669491Sbostic }
30769491Sbostic unsigned char *ptr = buf;
30869491Sbostic int lh = read2(ptr);
30969491Sbostic bc = read2(ptr);
31069491Sbostic ec = read2(ptr);
31169491Sbostic nw = read2(ptr);
31269491Sbostic nh = read2(ptr);
31369491Sbostic nd = read2(ptr);
31469491Sbostic ni = read2(ptr);
31569491Sbostic nl = read2(ptr);
31669491Sbostic nk = read2(ptr);
31769491Sbostic int ne = read2(ptr);
31869491Sbostic np = read2(ptr);
31969491Sbostic if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
32069491Sbostic error("bad tfm file `%1': lengths do not sum", file);
32169491Sbostic a_delete buf;
32269491Sbostic return 0;
32369491Sbostic }
32469491Sbostic if (lh < 2) {
32569491Sbostic error("bad tfm file `%1': header too short", file);
32669491Sbostic a_delete buf;
32769491Sbostic return 0;
32869491Sbostic }
32969491Sbostic char_info = new char_info_word[ec - bc + 1];
33069491Sbostic width = new int[nw];
33169491Sbostic height = new int[nh];
33269491Sbostic depth = new int[nd];
33369491Sbostic italic = new int[ni];
33469491Sbostic lig_kern = new lig_kern_command[nl];
33569491Sbostic kern = new int[nk];
33669491Sbostic param = new int[np];
33769491Sbostic int i;
33869491Sbostic cs = read4(ptr);
33969491Sbostic ds = read4(ptr);
34069491Sbostic ptr += (lh-2)*4;
34169491Sbostic for (i = 0; i < ec - bc + 1; i++) {
34269491Sbostic char_info[i].width_index = *ptr++;
34369491Sbostic unsigned char tem = *ptr++;
34469491Sbostic char_info[i].depth_index = tem & 0xf;
34569491Sbostic char_info[i].height_index = tem >> 4;
34669491Sbostic tem = *ptr++;
34769491Sbostic char_info[i].italic_index = tem >> 2;
34869491Sbostic char_info[i].tag = tem & 3;
34969491Sbostic char_info[i].remainder = *ptr++;
35069491Sbostic }
35169491Sbostic for (i = 0; i < nw; i++)
35269491Sbostic width[i] = read4(ptr);
35369491Sbostic for (i = 0; i < nh; i++)
35469491Sbostic height[i] = read4(ptr);
35569491Sbostic for (i = 0; i < nd; i++)
35669491Sbostic depth[i] = read4(ptr);
35769491Sbostic for (i = 0; i < ni; i++)
35869491Sbostic italic[i] = read4(ptr);
35969491Sbostic for (i = 0; i < nl; i++) {
36069491Sbostic lig_kern[i].skip_byte = *ptr++;
36169491Sbostic lig_kern[i].next_char = *ptr++;
36269491Sbostic lig_kern[i].op_byte = *ptr++;
36369491Sbostic lig_kern[i].remainder = *ptr++;
36469491Sbostic }
36569491Sbostic for (i = 0; i < nk; i++)
36669491Sbostic kern[i] = read4(ptr);
36769491Sbostic ptr += ne*4;
36869491Sbostic for (i = 0; i < np; i++)
36969491Sbostic param[i] = read4(ptr);
37069491Sbostic assert(ptr == buf + lf*4 - 2);
37169491Sbostic a_delete buf;
37269491Sbostic return 1;
37369491Sbostic }
37469491Sbostic
37569491Sbostic class gf {
37669491Sbostic int left[256];
37769491Sbostic int right[256];
37869491Sbostic static int sread4(int *p, FILE *fp);
37969491Sbostic static int uread3(int *p, FILE *fp);
38069491Sbostic static int uread2(int *p, FILE *fp);
38169491Sbostic static int skip(int n, FILE *fp);
38269491Sbostic public:
38369491Sbostic gf();
38469491Sbostic int load(const char *file);
get_left_adjustment(int i)38569491Sbostic int get_left_adjustment(int i) { return left[i]; }
get_right_adjustment(int i)38669491Sbostic int get_right_adjustment(int i) { return right[i]; }
38769491Sbostic };
38869491Sbostic
gf()38969491Sbostic gf::gf()
39069491Sbostic {
39169491Sbostic for (int i = 0; i < 256; i++)
39269491Sbostic left[i] = right[i] = 0;
39369491Sbostic }
39469491Sbostic
load(const char * file)39569491Sbostic int gf::load(const char *file)
39669491Sbostic {
39769491Sbostic enum {
39869491Sbostic paint_0 = 0,
39969491Sbostic paint1 = 64,
40069491Sbostic boc = 67,
40169491Sbostic boc1 = 68,
40269491Sbostic eoc = 69,
40369491Sbostic skip0 = 70,
40469491Sbostic skip1 = 71,
40569491Sbostic new_row_0 = 74,
40669491Sbostic xxx1 = 239,
40769491Sbostic yyy = 243,
40869491Sbostic no_op = 244,
40969491Sbostic pre = 247,
41069491Sbostic post = 248
41169491Sbostic };
41269491Sbostic int got_an_adjustment = 0;
41369491Sbostic int pending_adjustment = 0;
41469491Sbostic int left_adj, right_adj;
41569491Sbostic const int gf_id_byte = 131;
41669491Sbostic errno = 0;
41769491Sbostic FILE *fp = fopen(file, "r");
41869491Sbostic if (!fp) {
41969491Sbostic error("can't open `%1': %2", file, strerror(errno));
42069491Sbostic return 0;
42169491Sbostic }
42269491Sbostic if (getc(fp) != pre || getc(fp) != gf_id_byte) {
42369491Sbostic error("bad gf file");
42469491Sbostic return 0;
42569491Sbostic }
42669491Sbostic int n = getc(fp);
42769491Sbostic if (n == EOF)
42869491Sbostic goto eof;
42969491Sbostic if (!skip(n, fp))
43069491Sbostic goto eof;
43169491Sbostic for (;;) {
43269491Sbostic int op = getc(fp);
43369491Sbostic if (op == EOF)
43469491Sbostic goto eof;
43569491Sbostic if (op == post)
43669491Sbostic break;
43769491Sbostic if ((op >= paint_0 && op <= paint_0 + 63)
43869491Sbostic || (op >= new_row_0 && op <= new_row_0 + 164))
43969491Sbostic continue;
44069491Sbostic switch (op) {
44169491Sbostic case no_op:
44269491Sbostic case eoc:
44369491Sbostic case skip0:
44469491Sbostic break;
44569491Sbostic case paint1:
44669491Sbostic case skip1:
44769491Sbostic if (!skip(1, fp))
44869491Sbostic goto eof;
44969491Sbostic break;
45069491Sbostic case paint1 + 1:
45169491Sbostic case skip1 + 1:
45269491Sbostic if (!skip(2, fp))
45369491Sbostic goto eof;
45469491Sbostic break;
45569491Sbostic case paint1 + 2:
45669491Sbostic case skip1 + 2:
45769491Sbostic if (!skip(3, fp))
45869491Sbostic goto eof;
45969491Sbostic break;
46069491Sbostic case boc:
46169491Sbostic {
46269491Sbostic int code;
46369491Sbostic if (!sread4(&code, fp))
46469491Sbostic goto eof;
46569491Sbostic if (pending_adjustment) {
46669491Sbostic pending_adjustment = 0;
46769491Sbostic left[code & 0377] = left_adj;
46869491Sbostic right[code & 0377] = right_adj;
46969491Sbostic }
47069491Sbostic if (!skip(20, fp))
47169491Sbostic goto eof;
47269491Sbostic break;
47369491Sbostic }
47469491Sbostic case boc1:
47569491Sbostic {
47669491Sbostic int code = getc(fp);
47769491Sbostic if (code == EOF)
47869491Sbostic goto eof;
47969491Sbostic if (pending_adjustment) {
48069491Sbostic pending_adjustment = 0;
48169491Sbostic left[code] = left_adj;
48269491Sbostic right[code] = right_adj;
48369491Sbostic }
48469491Sbostic if (!skip(4, fp))
48569491Sbostic goto eof;
48669491Sbostic break;
48769491Sbostic }
48869491Sbostic case xxx1:
48969491Sbostic {
49069491Sbostic int len = getc(fp);
49169491Sbostic if (len == EOF)
49269491Sbostic goto eof;
49369491Sbostic char buf[256];
49469491Sbostic if (fread(buf, 1, len, fp) != len)
49569491Sbostic goto eof;
49669491Sbostic if (len == 10 /* strlen("adjustment") */
49769491Sbostic && memcmp(buf, "adjustment", len) == 0) {
49869491Sbostic int c = getc(fp);
49969491Sbostic if (c != yyy) {
50069491Sbostic if (c != EOF)
50169491Sbostic ungetc(c, fp);
50269491Sbostic break;
50369491Sbostic }
50469491Sbostic if (!sread4(&left_adj, fp))
50569491Sbostic goto eof;
50669491Sbostic c = getc(fp);
50769491Sbostic if (c != yyy) {
50869491Sbostic if (c != EOF)
50969491Sbostic ungetc(c, fp);
51069491Sbostic break;
51169491Sbostic }
51269491Sbostic if (!sread4(&right_adj, fp))
51369491Sbostic goto eof;
51469491Sbostic got_an_adjustment = 1;
51569491Sbostic pending_adjustment = 1;
51669491Sbostic }
51769491Sbostic break;
51869491Sbostic }
51969491Sbostic case xxx1 + 1:
52069491Sbostic if (!uread2(&n, fp) || !skip(n, fp))
52169491Sbostic goto eof;
52269491Sbostic break;
52369491Sbostic case xxx1 + 2:
52469491Sbostic if (!uread3(&n, fp) || !skip(n, fp))
52569491Sbostic goto eof;
52669491Sbostic break;
52769491Sbostic case xxx1 + 3:
52869491Sbostic if (!sread4(&n, fp) || !skip(n, fp))
52969491Sbostic goto eof;
53069491Sbostic break;
53169491Sbostic case yyy:
53269491Sbostic if (!skip(4, fp))
53369491Sbostic goto eof;
53469491Sbostic break;
53569491Sbostic default:
53669491Sbostic fatal("unrecognized opcode `%1'", op);
53769491Sbostic break;
53869491Sbostic }
53969491Sbostic }
54069491Sbostic if (!got_an_adjustment)
54169491Sbostic warning("no adjustment specials found in gf file");
54269491Sbostic return 1;
54369491Sbostic eof:
54469491Sbostic error("unexpected end of file");
54569491Sbostic return 0;
54669491Sbostic }
54769491Sbostic
sread4(int * p,FILE * fp)54869491Sbostic int gf::sread4(int *p, FILE *fp)
54969491Sbostic {
55069491Sbostic *p = getc(fp);
55169491Sbostic if (*p >= 128)
55269491Sbostic *p -= 256;
55369491Sbostic *p <<= 8;
55469491Sbostic *p |= getc(fp);
55569491Sbostic *p <<= 8;
55669491Sbostic *p |= getc(fp);
55769491Sbostic *p <<= 8;
55869491Sbostic *p |= getc(fp);
55969491Sbostic return !ferror(fp) && !feof(fp);
56069491Sbostic }
56169491Sbostic
uread3(int * p,FILE * fp)56269491Sbostic int gf::uread3(int *p, FILE *fp)
56369491Sbostic {
56469491Sbostic *p = getc(fp);
56569491Sbostic *p <<= 8;
56669491Sbostic *p |= getc(fp);
56769491Sbostic *p <<= 8;
56869491Sbostic *p |= getc(fp);
56969491Sbostic return !ferror(fp) && !feof(fp);
57069491Sbostic }
57169491Sbostic
uread2(int * p,FILE * fp)57269491Sbostic int gf::uread2(int *p, FILE *fp)
57369491Sbostic {
57469491Sbostic *p = getc(fp);
57569491Sbostic *p <<= 8;
57669491Sbostic *p |= getc(fp);
57769491Sbostic return !ferror(fp) && !feof(fp);
57869491Sbostic }
57969491Sbostic
skip(int n,FILE * fp)58069491Sbostic int gf::skip(int n, FILE *fp)
58169491Sbostic {
58269491Sbostic while (--n >= 0)
58369491Sbostic if (getc(fp) == EOF)
58469491Sbostic return 0;
58569491Sbostic return 1;
58669491Sbostic }
58769491Sbostic
58869491Sbostic
58969491Sbostic struct char_list {
59069491Sbostic char *ch;
59169491Sbostic char_list *next;
59269491Sbostic char_list(const char *, char_list * = 0);
59369491Sbostic };
59469491Sbostic
char_list(const char * s,char_list * p)59569491Sbostic char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
59669491Sbostic {
59769491Sbostic }
59869491Sbostic
59969491Sbostic
read_map(const char * file,char_list ** table)60069491Sbostic int read_map(const char *file, char_list **table)
60169491Sbostic {
60269491Sbostic errno = 0;
60369491Sbostic FILE *fp = fopen(file, "r");
60469491Sbostic if (!fp) {
60569491Sbostic error("can't open `%1': %2", file, strerror(errno));
60669491Sbostic return 0;
60769491Sbostic }
60869491Sbostic for (int i = 0; i < 256; i++)
60969491Sbostic table[i] = 0;
61069491Sbostic char buf[512];
61169491Sbostic int lineno = 0;
61269491Sbostic while (fgets(buf, int(sizeof(buf)), fp)) {
61369491Sbostic lineno++;
61469491Sbostic char *ptr = buf;
61569491Sbostic while (csspace(*ptr))
61669491Sbostic ptr++;
61769491Sbostic if (*ptr == '\0' || *ptr == '#')
61869491Sbostic continue;
61969491Sbostic ptr = strtok(ptr, " \n\t");
62069491Sbostic if (!ptr)
62169491Sbostic continue;
62269491Sbostic int n;
62369491Sbostic if (sscanf(ptr, "%d", &n) != 1) {
62469491Sbostic error("%1:%2: bad map file", file, lineno);
62569491Sbostic fclose(fp);
62669491Sbostic return 0;
62769491Sbostic }
62869491Sbostic if (n < 0 || n > 255) {
62969491Sbostic error("%1:%2: code out of range", file, lineno);
63069491Sbostic fclose(fp);
63169491Sbostic return 0;
63269491Sbostic }
63369491Sbostic ptr = strtok(0, " \n\t");
63469491Sbostic if (!ptr) {
63569491Sbostic error("%1:%2: missing names", file, lineno);
63669491Sbostic fclose(fp);
63769491Sbostic return 0;
63869491Sbostic }
63969491Sbostic for (; ptr; ptr = strtok(0, " \n\t"))
64069491Sbostic table[n] = new char_list(ptr, table[n]);
64169491Sbostic }
64269491Sbostic fclose(fp);
64369491Sbostic return 1;
64469491Sbostic }
64569491Sbostic
64669491Sbostic
64769491Sbostic /* Every character that can participate in a ligature appears in the
64869491Sbostic lig_chars table. `ch' gives the full-name of the character, `name'
64969491Sbostic gives the groff name of the character, `i' gives its index in
65069491Sbostic the encoding, which is filled in later (-1 if it does not appear). */
65169491Sbostic
65269491Sbostic struct {
65369491Sbostic const char *ch;
65469491Sbostic int i;
65569491Sbostic } lig_chars[] = {
65669491Sbostic "f", -1,
65769491Sbostic "i", -1,
65869491Sbostic "l", -1,
65969491Sbostic "ff", -1,
66069491Sbostic "fi", -1,
66169491Sbostic "fl", -1,
66269491Sbostic "Fi", -1,
66369491Sbostic "Fl", -1,
66469491Sbostic };
66569491Sbostic
66669491Sbostic // Indices into lig_chars[].
66769491Sbostic
66869491Sbostic enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
66969491Sbostic
67069491Sbostic // Each possible ligature appears in this table.
67169491Sbostic
67269491Sbostic struct {
67369491Sbostic unsigned char c1, c2, res;
67469491Sbostic const char *ch;
67569491Sbostic } lig_table[] = {
67669491Sbostic CH_f, CH_f, CH_ff, "ff",
67769491Sbostic CH_f, CH_i, CH_fi, "fi",
67869491Sbostic CH_f, CH_l, CH_fl, "fl",
67969491Sbostic CH_ff, CH_i, CH_ffi, "ffi",
68069491Sbostic CH_ff, CH_l, CH_ffl, "ffl",
68169491Sbostic };
68269491Sbostic
68369491Sbostic static void usage();
68469491Sbostic
main(int argc,char ** argv)68569491Sbostic int main(int argc, char **argv)
68669491Sbostic {
68769491Sbostic program_name = argv[0];
68869491Sbostic int special_flag = 0;
68969491Sbostic int skewchar = -1;
69069491Sbostic int opt;
69169491Sbostic const char *gf_file = 0;
69269491Sbostic while ((opt = getopt(argc, argv, "svg:k:")) != EOF)
69369491Sbostic switch (opt) {
69469491Sbostic case 'g':
69569491Sbostic gf_file = optarg;
69669491Sbostic break;
69769491Sbostic case 's':
69869491Sbostic special_flag = 1;
69969491Sbostic break;
70069491Sbostic case 'k':
70169491Sbostic {
70269491Sbostic char *ptr;
70369491Sbostic long n = strtol(optarg, &ptr, 0);
70469491Sbostic if ((n == 0 && ptr == optarg)
70569491Sbostic || *ptr != '\0'
70669491Sbostic || n < 0
70769491Sbostic || n > UCHAR_MAX)
70869491Sbostic error("invalid skewchar");
70969491Sbostic else
71069491Sbostic skewchar = (int)n;
71169491Sbostic break;
71269491Sbostic }
71369491Sbostic case 'v':
71469491Sbostic {
71569491Sbostic extern const char *version_string;
71669491Sbostic fprintf(stderr, "tfmtodit version %s\n", version_string);
71769491Sbostic fflush(stderr);
71869491Sbostic break;
71969491Sbostic }
72069491Sbostic case '?':
72169491Sbostic usage();
72269491Sbostic break;
72369491Sbostic case EOF:
72469491Sbostic assert(0);
72569491Sbostic }
72669491Sbostic if (argc - optind != 3)
72769491Sbostic usage();
72869491Sbostic gf g;
72969491Sbostic if (gf_file) {
73069491Sbostic if (!g.load(gf_file))
73169491Sbostic return 1;
73269491Sbostic }
73369491Sbostic const char *tfm_file = argv[optind];
73469491Sbostic const char *map_file = argv[optind + 1];
73569491Sbostic const char *font_file = argv[optind + 2];
73669491Sbostic tfm t;
73769491Sbostic if (!t.load(tfm_file))
73869491Sbostic return 1;
73969491Sbostic char_list *table[256];
74069491Sbostic if (!read_map(map_file, table))
74169491Sbostic return 1;
74269491Sbostic errno = 0;
74369491Sbostic if (!freopen(font_file, "w", stdout)) {
74469491Sbostic error("can't open `%1' for writing: %2", font_file, strerror(errno));
74569491Sbostic return 1;
74669491Sbostic }
74769491Sbostic printf("name %s\n", font_file);
74869491Sbostic if (special_flag)
74969491Sbostic fputs("special\n", stdout);
75069491Sbostic char *internal_name = strsave(argv[optind]);
75169491Sbostic int len = strlen(internal_name);
75269491Sbostic if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
75369491Sbostic internal_name[len - 4] = '\0';
75469491Sbostic char *s = strrchr(internal_name, '/');
75569491Sbostic printf("internalname %s\n", s ? s + 1 : internal_name);
75669491Sbostic int n;
75769491Sbostic if (t.get_param(2, &n)) {
75869491Sbostic if (n > 0)
75969491Sbostic printf("spacewidth %d\n", n*MULTIPLIER);
76069491Sbostic }
76169491Sbostic if (t.get_param(1, &n) && n != 0)
76269491Sbostic printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/M_PI);
76369491Sbostic int xheight;
76469491Sbostic if (!t.get_param(5, &xheight))
76569491Sbostic xheight = 0;
76669491Sbostic int i;
76769491Sbostic // Print the list of ligatures.
76869491Sbostic // First find the indices of each character that can participate in
76969491Sbostic // a ligature.
77069491Sbostic for (i = 0; i < 256; i++)
77169491Sbostic for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
77269491Sbostic for (char_list *p = table[i]; p; p = p->next)
77369491Sbostic if (strcmp(lig_chars[j].ch, p->ch) == 0)
77469491Sbostic lig_chars[j].i = i;
77569491Sbostic // For each possible ligature, if its participants all exist,
77669491Sbostic // and it appears as a ligature in the tfm file, include in
77769491Sbostic // the list of ligatures.
77869491Sbostic int started = 0;
77969491Sbostic for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
78069491Sbostic int i1 = lig_chars[lig_table[i].c1].i;
78169491Sbostic int i2 = lig_chars[lig_table[i].c2].i;
78269491Sbostic int r = lig_chars[lig_table[i].res].i;
78369491Sbostic if (i1 >= 0 && i2 >= 0 && r >= 0) {
78469491Sbostic unsigned char c;
78569491Sbostic if (t.get_lig(i1, i2, &c) && c == r) {
78669491Sbostic if (!started) {
78769491Sbostic started = 1;
78869491Sbostic fputs("ligatures", stdout);
78969491Sbostic }
79069491Sbostic printf(" %s", lig_table[i].ch);
79169491Sbostic }
79269491Sbostic }
79369491Sbostic }
79469491Sbostic if (started)
79569491Sbostic fputs(" 0\n", stdout);
79669491Sbostic printf("checksum %d\n", t.get_checksum());
79769491Sbostic printf("designsize %d\n", t.get_design_size());
79869491Sbostic // Now print out the kerning information.
79969491Sbostic int had_kern = 0;
80069491Sbostic kern_iterator iter(&t);
80169491Sbostic unsigned char c1, c2;
80269491Sbostic int k;
80369491Sbostic while (iter.next(&c1, &c2, &k))
80469491Sbostic if (c2 != skewchar) {
80569491Sbostic k *= MULTIPLIER;
80669491Sbostic char_list *q = table[c2];
80769491Sbostic for (char_list *p1 = table[c1]; p1; p1 = p1->next)
80869491Sbostic for (char_list *p2 = q; p2; p2 = p2->next) {
80969491Sbostic if (!had_kern) {
81069491Sbostic printf("kernpairs\n");
81169491Sbostic had_kern = 1;
81269491Sbostic }
81369491Sbostic printf("%s %s %d\n", p1->ch, p2->ch, k);
81469491Sbostic }
81569491Sbostic }
81669491Sbostic printf("charset\n");
81769491Sbostic char_list unnamed("---");
81869491Sbostic for (i = 0; i < 256; i++)
81969491Sbostic if (t.contains(i)) {
82069491Sbostic char_list *p = table[i] ? table[i] : &unnamed;
82169491Sbostic int m[6];
82269491Sbostic m[0] = t.get_width(i);
82369491Sbostic m[1] = t.get_height(i);
82469491Sbostic m[2] = t.get_depth(i);
82569491Sbostic m[3] = t.get_italic(i);
82669491Sbostic m[4] = g.get_left_adjustment(i);
82769491Sbostic m[5] = g.get_right_adjustment(i);
82869491Sbostic printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
82969491Sbostic for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
83069491Sbostic if (m[j] != 0)
83169491Sbostic break;
83269491Sbostic for (int k = 1; k <= j; k++)
83369491Sbostic printf(",%d", m[k]*MULTIPLIER);
83469491Sbostic int type = 0;
83569491Sbostic if (m[2] > 0)
83669491Sbostic type = 1;
83769491Sbostic if (m[1] > xheight)
83869491Sbostic type += 2;
83969491Sbostic printf("\t%d\t%04o\n", type, i);
84069491Sbostic for (p = p->next; p; p = p->next)
84169491Sbostic printf("%s\t\"\n", p->ch);
84269491Sbostic }
84369491Sbostic return 0;
84469491Sbostic }
84569491Sbostic
usage()84669491Sbostic static void usage()
84769491Sbostic {
84869491Sbostic fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
84969491Sbostic program_name);
85069491Sbostic exit(1);
85169491Sbostic }
852