1a34904b5Sbostic // -*- C++ -*-
2a34904b5Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3a34904b5Sbostic Written by James Clark (jjc@jclark.com)
4a34904b5Sbostic
5a34904b5Sbostic This file is part of groff.
6a34904b5Sbostic
7a34904b5Sbostic groff is free software; you can redistribute it and/or modify it under
8a34904b5Sbostic the terms of the GNU General Public License as published by the Free
9a34904b5Sbostic Software Foundation; either version 2, or (at your option) any later
10a34904b5Sbostic version.
11a34904b5Sbostic
12a34904b5Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
13a34904b5Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
14a34904b5Sbostic FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15a34904b5Sbostic for more details.
16a34904b5Sbostic
17a34904b5Sbostic You should have received a copy of the GNU General Public License along
18a34904b5Sbostic with groff; see the file COPYING. If not, write to the Free Software
19a34904b5Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20a34904b5Sbostic
21a34904b5Sbostic /* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
22a34904b5Sbostic but I haven't tested them. */
23a34904b5Sbostic
24a34904b5Sbostic /* Groff requires more font metric information than TeX. The reason
25a34904b5Sbostic for this is that TeX has separate Math Italic fonts, whereas groff
26a34904b5Sbostic uses normal italic fonts for math. The two additional pieces of
27a34904b5Sbostic information required by groff correspond to the two arguments to the
28a34904b5Sbostic math_fit() macro in the Metafont programs for the CM fonts. In the
29a34904b5Sbostic case of a font for which math_fitting is false, these two arguments
30a34904b5Sbostic are normally ignored by Metafont. We need to get hold of these two
31a34904b5Sbostic parameters and put them in the groff font file.
32a34904b5Sbostic
33a34904b5Sbostic We do this by loading this definition after cmbase when creating cm.base.
34a34904b5Sbostic
35a34904b5Sbostic def ignore_math_fit(expr left_adjustment,right_adjustment) =
36a34904b5Sbostic special "adjustment";
37a34904b5Sbostic numspecial left_adjustment*16/designsize;
38a34904b5Sbostic numspecial right_adjustment*16/designsize;
39a34904b5Sbostic enddef;
40a34904b5Sbostic
41a34904b5Sbostic This puts the two arguments to the math_fit macro into the gf file.
42a34904b5Sbostic (They will appear in the gf file immediately before the character to
43a34904b5Sbostic which they apply.) We then create a gf file using this cm.base. Then
44a34904b5Sbostic we run tfmtodit and specify this gf file with the -g option.
45a34904b5Sbostic
46a34904b5Sbostic This need only be done for a font for which math_fitting is false;
47a34904b5Sbostic When it's true, the left_correction and subscript_correction should
48a34904b5Sbostic both be zero. */
49a34904b5Sbostic
50a34904b5Sbostic #include <stdio.h>
51*4fb4e6f3Sbostic #include <unistd.h>
52a34904b5Sbostic #include <stdlib.h>
53a34904b5Sbostic #include <math.h>
54a34904b5Sbostic #include <string.h>
55a34904b5Sbostic #include <errno.h>
56a34904b5Sbostic #include "lib.h"
57a34904b5Sbostic #include "errarg.h"
58a34904b5Sbostic #include "error.h"
59a34904b5Sbostic #include "assert.h"
60a34904b5Sbostic #include "cset.h"
61a34904b5Sbostic
62a34904b5Sbostic /* Values in the tfm file should be multiplied by this. */
63a34904b5Sbostic
64a34904b5Sbostic #define MULTIPLIER 1
65a34904b5Sbostic
66a34904b5Sbostic struct char_info_word {
67a34904b5Sbostic unsigned char width_index;
68a34904b5Sbostic char height_index;
69a34904b5Sbostic char depth_index;
70a34904b5Sbostic char italic_index;
71a34904b5Sbostic char tag;
72a34904b5Sbostic unsigned char remainder;
73a34904b5Sbostic };
74a34904b5Sbostic
75a34904b5Sbostic struct lig_kern_command {
76a34904b5Sbostic unsigned char skip_byte;
77a34904b5Sbostic unsigned char next_char;
78a34904b5Sbostic unsigned char op_byte;
79a34904b5Sbostic unsigned char remainder;
80a34904b5Sbostic };
81a34904b5Sbostic
82a34904b5Sbostic class tfm {
83a34904b5Sbostic int bc;
84a34904b5Sbostic int ec;
85a34904b5Sbostic int nw;
86a34904b5Sbostic int nh;
87a34904b5Sbostic int nd;
88a34904b5Sbostic int ni;
89a34904b5Sbostic int nl;
90a34904b5Sbostic int nk;
91a34904b5Sbostic int np;
92a34904b5Sbostic int cs;
93a34904b5Sbostic int ds;
94a34904b5Sbostic char_info_word *char_info;
95a34904b5Sbostic int *width;
96a34904b5Sbostic int *height;
97a34904b5Sbostic int *depth;
98a34904b5Sbostic int *italic;
99a34904b5Sbostic lig_kern_command *lig_kern;
100a34904b5Sbostic int *kern;
101a34904b5Sbostic int *param;
102a34904b5Sbostic public:
103a34904b5Sbostic tfm();
104a34904b5Sbostic ~tfm();
105a34904b5Sbostic int load(const char *);
106a34904b5Sbostic int contains(int);
107a34904b5Sbostic int get_width(int);
108a34904b5Sbostic int get_height(int);
109a34904b5Sbostic int get_depth(int);
110a34904b5Sbostic int get_italic(int);
111a34904b5Sbostic int get_param(int, int *);
112a34904b5Sbostic int get_checksum();
113a34904b5Sbostic int get_design_size();
114a34904b5Sbostic int get_lig(unsigned char, unsigned char, unsigned char *);
115a34904b5Sbostic friend class kern_iterator;
116a34904b5Sbostic };
117a34904b5Sbostic
118a34904b5Sbostic class kern_iterator {
119a34904b5Sbostic tfm *t;
120a34904b5Sbostic int c;
121a34904b5Sbostic int i;
122a34904b5Sbostic public:
123a34904b5Sbostic kern_iterator(tfm *);
124a34904b5Sbostic int next(unsigned char *c1, unsigned char *c2, int *k);
125a34904b5Sbostic };
126a34904b5Sbostic
127a34904b5Sbostic
kern_iterator(tfm * p)128a34904b5Sbostic kern_iterator::kern_iterator(tfm *p)
129a34904b5Sbostic : t(p), i(-1), c(t->bc)
130a34904b5Sbostic {
131a34904b5Sbostic }
132a34904b5Sbostic
next(unsigned char * c1,unsigned char * c2,int * k)133a34904b5Sbostic int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
134a34904b5Sbostic {
135a34904b5Sbostic for (; c <= t->ec; c++)
136a34904b5Sbostic if (t->char_info[c - t->bc].tag == 1) {
137a34904b5Sbostic if (i < 0) {
138a34904b5Sbostic i = t->char_info[c - t->bc].remainder;
139a34904b5Sbostic if (t->lig_kern[i].skip_byte > 128)
140a34904b5Sbostic i = (256*t->lig_kern[i].op_byte
141a34904b5Sbostic + t->lig_kern[i].remainder);
142a34904b5Sbostic }
143a34904b5Sbostic for (;;) {
144a34904b5Sbostic int skip = t->lig_kern[i].skip_byte;
145a34904b5Sbostic if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
146a34904b5Sbostic *c1 = c;
147a34904b5Sbostic *c2 = t->lig_kern[i].next_char;
148a34904b5Sbostic *k = t->kern[256*(t->lig_kern[i].op_byte - 128)
149a34904b5Sbostic + t->lig_kern[i].remainder];
150a34904b5Sbostic if (skip == 128) {
151a34904b5Sbostic c++;
152a34904b5Sbostic i = -1;
153a34904b5Sbostic }
154a34904b5Sbostic else
155a34904b5Sbostic i += skip + 1;
156a34904b5Sbostic return 1;
157a34904b5Sbostic }
158a34904b5Sbostic if (skip >= 128)
159a34904b5Sbostic break;
160a34904b5Sbostic i += skip + 1;
161a34904b5Sbostic }
162a34904b5Sbostic i = -1;
163a34904b5Sbostic }
164a34904b5Sbostic return 0;
165a34904b5Sbostic }
166a34904b5Sbostic
tfm()167a34904b5Sbostic tfm::tfm()
168a34904b5Sbostic : char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
169a34904b5Sbostic kern(0), param(0)
170a34904b5Sbostic {
171a34904b5Sbostic }
172a34904b5Sbostic
get_lig(unsigned char c1,unsigned char c2,unsigned char * cp)173a34904b5Sbostic int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
174a34904b5Sbostic {
175a34904b5Sbostic if (contains(c1) && char_info[c1 - bc].tag == 1) {
176a34904b5Sbostic int i = char_info[c1 - bc].remainder;
177a34904b5Sbostic if (lig_kern[i].skip_byte > 128)
178a34904b5Sbostic i = 256*lig_kern[i].op_byte + lig_kern[i].remainder;
179a34904b5Sbostic for (;;) {
180a34904b5Sbostic int skip = lig_kern[i].skip_byte;
181a34904b5Sbostic if (skip > 128)
182a34904b5Sbostic break;
183a34904b5Sbostic // We are only interested in normal ligatures, for which
184a34904b5Sbostic // op_byte == 0.
185a34904b5Sbostic if (lig_kern[i].op_byte == 0
186a34904b5Sbostic && lig_kern[i].next_char == c2) {
187a34904b5Sbostic *cp = lig_kern[i].remainder;
188a34904b5Sbostic return 1;
189a34904b5Sbostic }
190a34904b5Sbostic if (skip == 128)
191a34904b5Sbostic break;
192a34904b5Sbostic i += skip + 1;
193a34904b5Sbostic }
194a34904b5Sbostic }
195a34904b5Sbostic return 0;
196a34904b5Sbostic }
197a34904b5Sbostic
contains(int i)198a34904b5Sbostic int tfm::contains(int i)
199a34904b5Sbostic {
200a34904b5Sbostic return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
201a34904b5Sbostic }
202a34904b5Sbostic
get_width(int i)203a34904b5Sbostic int tfm::get_width(int i)
204a34904b5Sbostic {
205a34904b5Sbostic return width[char_info[i - bc].width_index];
206a34904b5Sbostic }
207a34904b5Sbostic
get_height(int i)208a34904b5Sbostic int tfm::get_height(int i)
209a34904b5Sbostic {
210a34904b5Sbostic return height[char_info[i - bc].height_index];
211a34904b5Sbostic }
212a34904b5Sbostic
get_depth(int i)213a34904b5Sbostic int tfm::get_depth(int i)
214a34904b5Sbostic {
215a34904b5Sbostic return depth[char_info[i - bc].depth_index];
216a34904b5Sbostic }
217a34904b5Sbostic
get_italic(int i)218a34904b5Sbostic int tfm::get_italic(int i)
219a34904b5Sbostic {
220a34904b5Sbostic return italic[char_info[i - bc].italic_index];
221a34904b5Sbostic }
222a34904b5Sbostic
get_param(int i,int * p)223a34904b5Sbostic int tfm::get_param(int i, int *p)
224a34904b5Sbostic {
225a34904b5Sbostic if (i <= 0 || i > np)
226a34904b5Sbostic return 0;
227a34904b5Sbostic else {
228a34904b5Sbostic *p = param[i - 1];
229a34904b5Sbostic return 1;
230a34904b5Sbostic }
231a34904b5Sbostic }
232a34904b5Sbostic
get_checksum()233a34904b5Sbostic int tfm::get_checksum()
234a34904b5Sbostic {
235a34904b5Sbostic return cs;
236a34904b5Sbostic }
237a34904b5Sbostic
get_design_size()238a34904b5Sbostic int tfm::get_design_size()
239a34904b5Sbostic {
240a34904b5Sbostic return ds;
241a34904b5Sbostic }
242a34904b5Sbostic
~tfm()243a34904b5Sbostic tfm::~tfm()
244a34904b5Sbostic {
245a34904b5Sbostic a_delete char_info;
246a34904b5Sbostic a_delete width;
247a34904b5Sbostic a_delete height;
248a34904b5Sbostic a_delete depth;
249a34904b5Sbostic a_delete italic;
250a34904b5Sbostic a_delete lig_kern;
251a34904b5Sbostic a_delete kern;
252a34904b5Sbostic a_delete param;
253a34904b5Sbostic }
254a34904b5Sbostic
read2(unsigned char * & s)255a34904b5Sbostic int read2(unsigned char *&s)
256a34904b5Sbostic {
257a34904b5Sbostic int n;
258a34904b5Sbostic n = *s++ << 8;
259a34904b5Sbostic n |= *s++;
260a34904b5Sbostic return n;
261a34904b5Sbostic }
262a34904b5Sbostic
read4(unsigned char * & s)263a34904b5Sbostic int read4(unsigned char *&s)
264a34904b5Sbostic {
265a34904b5Sbostic int n;
266a34904b5Sbostic n = *s++ << 24;
267a34904b5Sbostic n |= *s++ << 16;
268a34904b5Sbostic n |= *s++ << 8;
269a34904b5Sbostic n |= *s++;
270a34904b5Sbostic return n;
271a34904b5Sbostic }
272a34904b5Sbostic
273a34904b5Sbostic
load(const char * file)274a34904b5Sbostic int tfm::load(const char *file)
275a34904b5Sbostic {
276a34904b5Sbostic errno = 0;
277a34904b5Sbostic FILE *fp = fopen(file, "r");
278a34904b5Sbostic if (!fp) {
279a34904b5Sbostic error("can't open `%1': %2", file, strerror(errno));
280a34904b5Sbostic return 0;
281a34904b5Sbostic }
282a34904b5Sbostic int c1 = getc(fp);
283a34904b5Sbostic int c2 = getc(fp);
284a34904b5Sbostic if (c1 == EOF || c2 == EOF) {
285a34904b5Sbostic fclose(fp);
286a34904b5Sbostic error("unexpected end of file on `%1'", file);
287a34904b5Sbostic return 0;
288a34904b5Sbostic }
289a34904b5Sbostic int lf = (c1 << 8) + c2;
290a34904b5Sbostic int toread = lf*4 - 2;
291a34904b5Sbostic unsigned char *buf = new unsigned char[toread];
292a34904b5Sbostic if (fread(buf, 1, toread, fp) != toread) {
293a34904b5Sbostic if (feof(fp))
294a34904b5Sbostic error("unexpected end of file on `%1'", file);
295a34904b5Sbostic else
296a34904b5Sbostic error("error on file `%1'", file);
297a34904b5Sbostic a_delete buf;
298a34904b5Sbostic fclose(fp);
299a34904b5Sbostic return 0;
300a34904b5Sbostic }
301a34904b5Sbostic fclose(fp);
302a34904b5Sbostic if (lf < 6) {
303a34904b5Sbostic error("bad tfm file `%1': impossibly short", file);
304a34904b5Sbostic a_delete buf;
305a34904b5Sbostic return 0;
306a34904b5Sbostic }
307a34904b5Sbostic unsigned char *ptr = buf;
308a34904b5Sbostic int lh = read2(ptr);
309a34904b5Sbostic bc = read2(ptr);
310a34904b5Sbostic ec = read2(ptr);
311a34904b5Sbostic nw = read2(ptr);
312a34904b5Sbostic nh = read2(ptr);
313a34904b5Sbostic nd = read2(ptr);
314a34904b5Sbostic ni = read2(ptr);
315a34904b5Sbostic nl = read2(ptr);
316a34904b5Sbostic nk = read2(ptr);
317a34904b5Sbostic int ne = read2(ptr);
318a34904b5Sbostic np = read2(ptr);
319a34904b5Sbostic if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) {
320a34904b5Sbostic error("bad tfm file `%1': lengths do not sum", file);
321a34904b5Sbostic a_delete buf;
322a34904b5Sbostic return 0;
323a34904b5Sbostic }
324a34904b5Sbostic if (lh < 2) {
325a34904b5Sbostic error("bad tfm file `%1': header too short", file);
326a34904b5Sbostic a_delete buf;
327a34904b5Sbostic return 0;
328a34904b5Sbostic }
329a34904b5Sbostic char_info = new char_info_word[ec - bc + 1];
330a34904b5Sbostic width = new int[nw];
331a34904b5Sbostic height = new int[nh];
332a34904b5Sbostic depth = new int[nd];
333a34904b5Sbostic italic = new int[ni];
334a34904b5Sbostic lig_kern = new lig_kern_command[nl];
335a34904b5Sbostic kern = new int[nk];
336a34904b5Sbostic param = new int[np];
337a34904b5Sbostic int i;
338a34904b5Sbostic cs = read4(ptr);
339a34904b5Sbostic ds = read4(ptr);
340a34904b5Sbostic ptr += (lh-2)*4;
341a34904b5Sbostic for (i = 0; i < ec - bc + 1; i++) {
342a34904b5Sbostic char_info[i].width_index = *ptr++;
343a34904b5Sbostic unsigned char tem = *ptr++;
344a34904b5Sbostic char_info[i].depth_index = tem & 0xf;
345a34904b5Sbostic char_info[i].height_index = tem >> 4;
346a34904b5Sbostic tem = *ptr++;
347a34904b5Sbostic char_info[i].italic_index = tem >> 2;
348a34904b5Sbostic char_info[i].tag = tem & 3;
349a34904b5Sbostic char_info[i].remainder = *ptr++;
350a34904b5Sbostic }
351a34904b5Sbostic for (i = 0; i < nw; i++)
352a34904b5Sbostic width[i] = read4(ptr);
353a34904b5Sbostic for (i = 0; i < nh; i++)
354a34904b5Sbostic height[i] = read4(ptr);
355a34904b5Sbostic for (i = 0; i < nd; i++)
356a34904b5Sbostic depth[i] = read4(ptr);
357a34904b5Sbostic for (i = 0; i < ni; i++)
358a34904b5Sbostic italic[i] = read4(ptr);
359a34904b5Sbostic for (i = 0; i < nl; i++) {
360a34904b5Sbostic lig_kern[i].skip_byte = *ptr++;
361a34904b5Sbostic lig_kern[i].next_char = *ptr++;
362a34904b5Sbostic lig_kern[i].op_byte = *ptr++;
363a34904b5Sbostic lig_kern[i].remainder = *ptr++;
364a34904b5Sbostic }
365a34904b5Sbostic for (i = 0; i < nk; i++)
366a34904b5Sbostic kern[i] = read4(ptr);
367a34904b5Sbostic ptr += ne*4;
368a34904b5Sbostic for (i = 0; i < np; i++)
369a34904b5Sbostic param[i] = read4(ptr);
370a34904b5Sbostic assert(ptr == buf + lf*4 - 2);
371a34904b5Sbostic a_delete buf;
372a34904b5Sbostic return 1;
373a34904b5Sbostic }
374a34904b5Sbostic
375a34904b5Sbostic class gf {
376a34904b5Sbostic int left[256];
377a34904b5Sbostic int right[256];
378a34904b5Sbostic static int sread4(int *p, FILE *fp);
379a34904b5Sbostic static int uread3(int *p, FILE *fp);
380a34904b5Sbostic static int uread2(int *p, FILE *fp);
381a34904b5Sbostic static int skip(int n, FILE *fp);
382a34904b5Sbostic public:
383a34904b5Sbostic gf();
384a34904b5Sbostic int load(const char *file);
get_left_adjustment(int i)385a34904b5Sbostic int get_left_adjustment(int i) { return left[i]; }
get_right_adjustment(int i)386a34904b5Sbostic int get_right_adjustment(int i) { return right[i]; }
387a34904b5Sbostic };
388a34904b5Sbostic
gf()389a34904b5Sbostic gf::gf()
390a34904b5Sbostic {
391a34904b5Sbostic for (int i = 0; i < 256; i++)
392a34904b5Sbostic left[i] = right[i] = 0;
393a34904b5Sbostic }
394a34904b5Sbostic
load(const char * file)395a34904b5Sbostic int gf::load(const char *file)
396a34904b5Sbostic {
397a34904b5Sbostic enum {
398a34904b5Sbostic paint_0 = 0,
399a34904b5Sbostic paint1 = 64,
400a34904b5Sbostic boc = 67,
401a34904b5Sbostic boc1 = 68,
402a34904b5Sbostic eoc = 69,
403a34904b5Sbostic skip0 = 70,
404a34904b5Sbostic skip1 = 71,
405a34904b5Sbostic new_row_0 = 74,
406a34904b5Sbostic xxx1 = 239,
407a34904b5Sbostic yyy = 243,
408a34904b5Sbostic no_op = 244,
409a34904b5Sbostic pre = 247,
410a34904b5Sbostic post = 248
411a34904b5Sbostic };
412a34904b5Sbostic int got_an_adjustment = 0;
413a34904b5Sbostic int pending_adjustment = 0;
414a34904b5Sbostic int left_adj, right_adj;
415a34904b5Sbostic const int gf_id_byte = 131;
416a34904b5Sbostic errno = 0;
417a34904b5Sbostic FILE *fp = fopen(file, "r");
418a34904b5Sbostic if (!fp) {
419a34904b5Sbostic error("can't open `%1': %2", file, strerror(errno));
420a34904b5Sbostic return 0;
421a34904b5Sbostic }
422a34904b5Sbostic if (getc(fp) != pre || getc(fp) != gf_id_byte) {
423a34904b5Sbostic error("bad gf file");
424a34904b5Sbostic return 0;
425a34904b5Sbostic }
426a34904b5Sbostic int n = getc(fp);
427a34904b5Sbostic if (n == EOF)
428a34904b5Sbostic goto eof;
429a34904b5Sbostic if (!skip(n, fp))
430a34904b5Sbostic goto eof;
431a34904b5Sbostic for (;;) {
432a34904b5Sbostic int op = getc(fp);
433a34904b5Sbostic if (op == EOF)
434a34904b5Sbostic goto eof;
435a34904b5Sbostic if (op == post)
436a34904b5Sbostic break;
437a34904b5Sbostic if ((op >= paint_0 && op <= paint_0 + 63)
438a34904b5Sbostic || (op >= new_row_0 && op <= new_row_0 + 164))
439a34904b5Sbostic continue;
440a34904b5Sbostic switch (op) {
441a34904b5Sbostic case no_op:
442a34904b5Sbostic case eoc:
443a34904b5Sbostic case skip0:
444a34904b5Sbostic break;
445a34904b5Sbostic case paint1:
446a34904b5Sbostic case skip1:
447a34904b5Sbostic if (!skip(1, fp))
448a34904b5Sbostic goto eof;
449a34904b5Sbostic break;
450a34904b5Sbostic case paint1 + 1:
451a34904b5Sbostic case skip1 + 1:
452a34904b5Sbostic if (!skip(2, fp))
453a34904b5Sbostic goto eof;
454a34904b5Sbostic break;
455a34904b5Sbostic case paint1 + 2:
456a34904b5Sbostic case skip1 + 2:
457a34904b5Sbostic if (!skip(3, fp))
458a34904b5Sbostic goto eof;
459a34904b5Sbostic break;
460a34904b5Sbostic case boc:
461a34904b5Sbostic {
462a34904b5Sbostic int code;
463a34904b5Sbostic if (!sread4(&code, fp))
464a34904b5Sbostic goto eof;
465a34904b5Sbostic if (pending_adjustment) {
466a34904b5Sbostic pending_adjustment = 0;
467a34904b5Sbostic left[code & 0377] = left_adj;
468a34904b5Sbostic right[code & 0377] = right_adj;
469a34904b5Sbostic }
470a34904b5Sbostic if (!skip(20, fp))
471a34904b5Sbostic goto eof;
472a34904b5Sbostic break;
473a34904b5Sbostic }
474a34904b5Sbostic case boc1:
475a34904b5Sbostic {
476a34904b5Sbostic int code = getc(fp);
477a34904b5Sbostic if (code == EOF)
478a34904b5Sbostic goto eof;
479a34904b5Sbostic if (pending_adjustment) {
480a34904b5Sbostic pending_adjustment = 0;
481a34904b5Sbostic left[code] = left_adj;
482a34904b5Sbostic right[code] = right_adj;
483a34904b5Sbostic }
484a34904b5Sbostic if (!skip(4, fp))
485a34904b5Sbostic goto eof;
486a34904b5Sbostic break;
487a34904b5Sbostic }
488a34904b5Sbostic case xxx1:
489a34904b5Sbostic {
490a34904b5Sbostic int len = getc(fp);
491a34904b5Sbostic if (len == EOF)
492a34904b5Sbostic goto eof;
493a34904b5Sbostic char buf[256];
494a34904b5Sbostic if (fread(buf, 1, len, fp) != len)
495a34904b5Sbostic goto eof;
496a34904b5Sbostic if (len == 10 /* strlen("adjustment") */
497a34904b5Sbostic && memcmp(buf, "adjustment", len) == 0) {
498a34904b5Sbostic int c = getc(fp);
499a34904b5Sbostic if (c != yyy) {
500a34904b5Sbostic if (c != EOF)
501a34904b5Sbostic ungetc(c, fp);
502a34904b5Sbostic break;
503a34904b5Sbostic }
504a34904b5Sbostic if (!sread4(&left_adj, fp))
505a34904b5Sbostic goto eof;
506a34904b5Sbostic c = getc(fp);
507a34904b5Sbostic if (c != yyy) {
508a34904b5Sbostic if (c != EOF)
509a34904b5Sbostic ungetc(c, fp);
510a34904b5Sbostic break;
511a34904b5Sbostic }
512a34904b5Sbostic if (!sread4(&right_adj, fp))
513a34904b5Sbostic goto eof;
514a34904b5Sbostic got_an_adjustment = 1;
515a34904b5Sbostic pending_adjustment = 1;
516a34904b5Sbostic }
517a34904b5Sbostic break;
518a34904b5Sbostic }
519a34904b5Sbostic case xxx1 + 1:
520a34904b5Sbostic if (!uread2(&n, fp) || !skip(n, fp))
521a34904b5Sbostic goto eof;
522a34904b5Sbostic break;
523a34904b5Sbostic case xxx1 + 2:
524a34904b5Sbostic if (!uread3(&n, fp) || !skip(n, fp))
525a34904b5Sbostic goto eof;
526a34904b5Sbostic break;
527a34904b5Sbostic case xxx1 + 3:
528a34904b5Sbostic if (!sread4(&n, fp) || !skip(n, fp))
529a34904b5Sbostic goto eof;
530a34904b5Sbostic break;
531a34904b5Sbostic case yyy:
532a34904b5Sbostic if (!skip(4, fp))
533a34904b5Sbostic goto eof;
534a34904b5Sbostic break;
535a34904b5Sbostic default:
536a34904b5Sbostic fatal("unrecognized opcode `%1'", op);
537a34904b5Sbostic break;
538a34904b5Sbostic }
539a34904b5Sbostic }
540a34904b5Sbostic if (!got_an_adjustment)
541a34904b5Sbostic warning("no adjustment specials found in gf file");
542a34904b5Sbostic return 1;
543a34904b5Sbostic eof:
544a34904b5Sbostic error("unexpected end of file");
545a34904b5Sbostic return 0;
546a34904b5Sbostic }
547a34904b5Sbostic
sread4(int * p,FILE * fp)548a34904b5Sbostic int gf::sread4(int *p, FILE *fp)
549a34904b5Sbostic {
550a34904b5Sbostic *p = getc(fp);
551a34904b5Sbostic if (*p >= 128)
552a34904b5Sbostic *p -= 256;
553a34904b5Sbostic *p <<= 8;
554a34904b5Sbostic *p |= getc(fp);
555a34904b5Sbostic *p <<= 8;
556a34904b5Sbostic *p |= getc(fp);
557a34904b5Sbostic *p <<= 8;
558a34904b5Sbostic *p |= getc(fp);
559a34904b5Sbostic return !ferror(fp) && !feof(fp);
560a34904b5Sbostic }
561a34904b5Sbostic
uread3(int * p,FILE * fp)562a34904b5Sbostic int gf::uread3(int *p, FILE *fp)
563a34904b5Sbostic {
564a34904b5Sbostic *p = getc(fp);
565a34904b5Sbostic *p <<= 8;
566a34904b5Sbostic *p |= getc(fp);
567a34904b5Sbostic *p <<= 8;
568a34904b5Sbostic *p |= getc(fp);
569a34904b5Sbostic return !ferror(fp) && !feof(fp);
570a34904b5Sbostic }
571a34904b5Sbostic
uread2(int * p,FILE * fp)572a34904b5Sbostic int gf::uread2(int *p, FILE *fp)
573a34904b5Sbostic {
574a34904b5Sbostic *p = getc(fp);
575a34904b5Sbostic *p <<= 8;
576a34904b5Sbostic *p |= getc(fp);
577a34904b5Sbostic return !ferror(fp) && !feof(fp);
578a34904b5Sbostic }
579a34904b5Sbostic
skip(int n,FILE * fp)580a34904b5Sbostic int gf::skip(int n, FILE *fp)
581a34904b5Sbostic {
582a34904b5Sbostic while (--n >= 0)
583a34904b5Sbostic if (getc(fp) == EOF)
584a34904b5Sbostic return 0;
585a34904b5Sbostic return 1;
586a34904b5Sbostic }
587a34904b5Sbostic
588a34904b5Sbostic
589a34904b5Sbostic struct char_list {
590a34904b5Sbostic char *ch;
591a34904b5Sbostic char_list *next;
592a34904b5Sbostic char_list(const char *, char_list * = 0);
593a34904b5Sbostic };
594a34904b5Sbostic
char_list(const char * s,char_list * p)595a34904b5Sbostic char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
596a34904b5Sbostic {
597a34904b5Sbostic }
598a34904b5Sbostic
599a34904b5Sbostic
read_map(const char * file,char_list ** table)600a34904b5Sbostic int read_map(const char *file, char_list **table)
601a34904b5Sbostic {
602a34904b5Sbostic errno = 0;
603a34904b5Sbostic FILE *fp = fopen(file, "r");
604a34904b5Sbostic if (!fp) {
605a34904b5Sbostic error("can't open `%1': %2", file, strerror(errno));
606a34904b5Sbostic return 0;
607a34904b5Sbostic }
608a34904b5Sbostic for (int i = 0; i < 256; i++)
609a34904b5Sbostic table[i] = 0;
610a34904b5Sbostic char buf[512];
611a34904b5Sbostic int lineno = 0;
612a34904b5Sbostic while (fgets(buf, int(sizeof(buf)), fp)) {
613a34904b5Sbostic lineno++;
614a34904b5Sbostic char *ptr = buf;
615a34904b5Sbostic while (csspace(*ptr))
616a34904b5Sbostic ptr++;
617a34904b5Sbostic if (*ptr == '\0' || *ptr == '#')
618a34904b5Sbostic continue;
619a34904b5Sbostic ptr = strtok(ptr, " \n\t");
620a34904b5Sbostic if (!ptr)
621a34904b5Sbostic continue;
622a34904b5Sbostic int n;
623a34904b5Sbostic if (sscanf(ptr, "%d", &n) != 1) {
624a34904b5Sbostic error("%1:%2: bad map file", file, lineno);
625a34904b5Sbostic fclose(fp);
626a34904b5Sbostic return 0;
627a34904b5Sbostic }
628a34904b5Sbostic if (n < 0 || n > 255) {
629a34904b5Sbostic error("%1:%2: code out of range", file, lineno);
630a34904b5Sbostic fclose(fp);
631a34904b5Sbostic return 0;
632a34904b5Sbostic }
633a34904b5Sbostic ptr = strtok(0, " \n\t");
634a34904b5Sbostic if (!ptr) {
635a34904b5Sbostic error("%1:%2: missing names", file, lineno);
636a34904b5Sbostic fclose(fp);
637a34904b5Sbostic return 0;
638a34904b5Sbostic }
639a34904b5Sbostic for (; ptr; ptr = strtok(0, " \n\t"))
640a34904b5Sbostic table[n] = new char_list(ptr, table[n]);
641a34904b5Sbostic }
642a34904b5Sbostic fclose(fp);
643a34904b5Sbostic return 1;
644a34904b5Sbostic }
645a34904b5Sbostic
646a34904b5Sbostic
647a34904b5Sbostic /* Every character that can participate in a ligature appears in the
648a34904b5Sbostic lig_chars table. `ch' gives the full-name of the character, `name'
649a34904b5Sbostic gives the groff name of the character, `i' gives its index in
650a34904b5Sbostic the encoding, which is filled in later (-1 if it does not appear). */
651a34904b5Sbostic
652a34904b5Sbostic struct {
653a34904b5Sbostic const char *ch;
654a34904b5Sbostic int i;
655a34904b5Sbostic } lig_chars[] = {
656a34904b5Sbostic "f", -1,
657a34904b5Sbostic "i", -1,
658a34904b5Sbostic "l", -1,
659a34904b5Sbostic "ff", -1,
660a34904b5Sbostic "fi", -1,
661a34904b5Sbostic "fl", -1,
662a34904b5Sbostic "Fi", -1,
663a34904b5Sbostic "Fl", -1,
664a34904b5Sbostic };
665a34904b5Sbostic
666a34904b5Sbostic // Indices into lig_chars[].
667a34904b5Sbostic
668a34904b5Sbostic enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
669a34904b5Sbostic
670a34904b5Sbostic // Each possible ligature appears in this table.
671a34904b5Sbostic
672a34904b5Sbostic struct {
673a34904b5Sbostic unsigned char c1, c2, res;
674a34904b5Sbostic const char *ch;
675a34904b5Sbostic } lig_table[] = {
676a34904b5Sbostic CH_f, CH_f, CH_ff, "ff",
677a34904b5Sbostic CH_f, CH_i, CH_fi, "fi",
678a34904b5Sbostic CH_f, CH_l, CH_fl, "fl",
679a34904b5Sbostic CH_ff, CH_i, CH_ffi, "ffi",
680a34904b5Sbostic CH_ff, CH_l, CH_ffl, "ffl",
681a34904b5Sbostic };
682a34904b5Sbostic
683a34904b5Sbostic static void usage();
684a34904b5Sbostic
main(int argc,char ** argv)685a34904b5Sbostic int main(int argc, char **argv)
686a34904b5Sbostic {
687a34904b5Sbostic program_name = argv[0];
688a34904b5Sbostic int special_flag = 0;
689a34904b5Sbostic int skewchar = -1;
690a34904b5Sbostic int opt;
691a34904b5Sbostic const char *gf_file = 0;
692a34904b5Sbostic while ((opt = getopt(argc, argv, "svg:k:")) != EOF)
693a34904b5Sbostic switch (opt) {
694a34904b5Sbostic case 'g':
695a34904b5Sbostic gf_file = optarg;
696a34904b5Sbostic break;
697a34904b5Sbostic case 's':
698a34904b5Sbostic special_flag = 1;
699a34904b5Sbostic break;
700a34904b5Sbostic case 'k':
701a34904b5Sbostic {
702a34904b5Sbostic char *ptr;
703a34904b5Sbostic long n = strtol(optarg, &ptr, 0);
704a34904b5Sbostic if ((n == 0 && ptr == optarg)
705a34904b5Sbostic || *ptr != '\0'
706a34904b5Sbostic || n < 0
707a34904b5Sbostic || n > UCHAR_MAX)
708a34904b5Sbostic error("invalid skewchar");
709a34904b5Sbostic else
710a34904b5Sbostic skewchar = (int)n;
711a34904b5Sbostic break;
712a34904b5Sbostic }
713a34904b5Sbostic case 'v':
714a34904b5Sbostic {
715a34904b5Sbostic extern const char *version_string;
716a34904b5Sbostic fprintf(stderr, "tfmtodit version %s\n", version_string);
717a34904b5Sbostic fflush(stderr);
718a34904b5Sbostic break;
719a34904b5Sbostic }
720a34904b5Sbostic case '?':
721a34904b5Sbostic usage();
722a34904b5Sbostic break;
723a34904b5Sbostic case EOF:
724a34904b5Sbostic assert(0);
725a34904b5Sbostic }
726a34904b5Sbostic if (argc - optind != 3)
727a34904b5Sbostic usage();
728a34904b5Sbostic gf g;
729a34904b5Sbostic if (gf_file) {
730a34904b5Sbostic if (!g.load(gf_file))
731a34904b5Sbostic return 1;
732a34904b5Sbostic }
733a34904b5Sbostic const char *tfm_file = argv[optind];
734a34904b5Sbostic const char *map_file = argv[optind + 1];
735a34904b5Sbostic const char *font_file = argv[optind + 2];
736a34904b5Sbostic tfm t;
737a34904b5Sbostic if (!t.load(tfm_file))
738a34904b5Sbostic return 1;
739a34904b5Sbostic char_list *table[256];
740a34904b5Sbostic if (!read_map(map_file, table))
741a34904b5Sbostic return 1;
742a34904b5Sbostic errno = 0;
743a34904b5Sbostic if (!freopen(font_file, "w", stdout)) {
744a34904b5Sbostic error("can't open `%1' for writing: %2", font_file, strerror(errno));
745a34904b5Sbostic return 1;
746a34904b5Sbostic }
747a34904b5Sbostic printf("name %s\n", font_file);
748a34904b5Sbostic if (special_flag)
749a34904b5Sbostic fputs("special\n", stdout);
750a34904b5Sbostic char *internal_name = strsave(argv[optind]);
751a34904b5Sbostic int len = strlen(internal_name);
752a34904b5Sbostic if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0)
753a34904b5Sbostic internal_name[len - 4] = '\0';
754a34904b5Sbostic char *s = strrchr(internal_name, '/');
755a34904b5Sbostic printf("internalname %s\n", s ? s + 1 : internal_name);
756a34904b5Sbostic int n;
757a34904b5Sbostic if (t.get_param(2, &n)) {
758a34904b5Sbostic if (n > 0)
759a34904b5Sbostic printf("spacewidth %d\n", n*MULTIPLIER);
760a34904b5Sbostic }
761a34904b5Sbostic if (t.get_param(1, &n) && n != 0)
762a34904b5Sbostic printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/M_PI);
763a34904b5Sbostic int xheight;
764a34904b5Sbostic if (!t.get_param(5, &xheight))
765a34904b5Sbostic xheight = 0;
766a34904b5Sbostic int i;
767a34904b5Sbostic // Print the list of ligatures.
768a34904b5Sbostic // First find the indices of each character that can participate in
769a34904b5Sbostic // a ligature.
770a34904b5Sbostic for (i = 0; i < 256; i++)
771a34904b5Sbostic for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++)
772a34904b5Sbostic for (char_list *p = table[i]; p; p = p->next)
773a34904b5Sbostic if (strcmp(lig_chars[j].ch, p->ch) == 0)
774a34904b5Sbostic lig_chars[j].i = i;
775a34904b5Sbostic // For each possible ligature, if its participants all exist,
776a34904b5Sbostic // and it appears as a ligature in the tfm file, include in
777a34904b5Sbostic // the list of ligatures.
778a34904b5Sbostic int started = 0;
779a34904b5Sbostic for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) {
780a34904b5Sbostic int i1 = lig_chars[lig_table[i].c1].i;
781a34904b5Sbostic int i2 = lig_chars[lig_table[i].c2].i;
782a34904b5Sbostic int r = lig_chars[lig_table[i].res].i;
783a34904b5Sbostic if (i1 >= 0 && i2 >= 0 && r >= 0) {
784a34904b5Sbostic unsigned char c;
785a34904b5Sbostic if (t.get_lig(i1, i2, &c) && c == r) {
786a34904b5Sbostic if (!started) {
787a34904b5Sbostic started = 1;
788a34904b5Sbostic fputs("ligatures", stdout);
789a34904b5Sbostic }
790a34904b5Sbostic printf(" %s", lig_table[i].ch);
791a34904b5Sbostic }
792a34904b5Sbostic }
793a34904b5Sbostic }
794a34904b5Sbostic if (started)
795a34904b5Sbostic fputs(" 0\n", stdout);
796a34904b5Sbostic printf("checksum %d\n", t.get_checksum());
797a34904b5Sbostic printf("designsize %d\n", t.get_design_size());
798a34904b5Sbostic // Now print out the kerning information.
799a34904b5Sbostic int had_kern = 0;
800a34904b5Sbostic kern_iterator iter(&t);
801a34904b5Sbostic unsigned char c1, c2;
802a34904b5Sbostic int k;
803a34904b5Sbostic while (iter.next(&c1, &c2, &k))
804a34904b5Sbostic if (c2 != skewchar) {
805a34904b5Sbostic k *= MULTIPLIER;
806a34904b5Sbostic char_list *q = table[c2];
807a34904b5Sbostic for (char_list *p1 = table[c1]; p1; p1 = p1->next)
808a34904b5Sbostic for (char_list *p2 = q; p2; p2 = p2->next) {
809a34904b5Sbostic if (!had_kern) {
810a34904b5Sbostic printf("kernpairs\n");
811a34904b5Sbostic had_kern = 1;
812a34904b5Sbostic }
813a34904b5Sbostic printf("%s %s %d\n", p1->ch, p2->ch, k);
814a34904b5Sbostic }
815a34904b5Sbostic }
816a34904b5Sbostic printf("charset\n");
817a34904b5Sbostic char_list unnamed("---");
818a34904b5Sbostic for (i = 0; i < 256; i++)
819a34904b5Sbostic if (t.contains(i)) {
820a34904b5Sbostic char_list *p = table[i] ? table[i] : &unnamed;
821a34904b5Sbostic int m[6];
822a34904b5Sbostic m[0] = t.get_width(i);
823a34904b5Sbostic m[1] = t.get_height(i);
824a34904b5Sbostic m[2] = t.get_depth(i);
825a34904b5Sbostic m[3] = t.get_italic(i);
826a34904b5Sbostic m[4] = g.get_left_adjustment(i);
827a34904b5Sbostic m[5] = g.get_right_adjustment(i);
828a34904b5Sbostic printf("%s\t%d", p->ch, m[0]*MULTIPLIER);
829a34904b5Sbostic for (int j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
830a34904b5Sbostic if (m[j] != 0)
831a34904b5Sbostic break;
832a34904b5Sbostic for (int k = 1; k <= j; k++)
833a34904b5Sbostic printf(",%d", m[k]*MULTIPLIER);
834a34904b5Sbostic int type = 0;
835a34904b5Sbostic if (m[2] > 0)
836a34904b5Sbostic type = 1;
837a34904b5Sbostic if (m[1] > xheight)
838a34904b5Sbostic type += 2;
839a34904b5Sbostic printf("\t%d\t%04o\n", type, i);
840a34904b5Sbostic for (p = p->next; p; p = p->next)
841a34904b5Sbostic printf("%s\t\"\n", p->ch);
842a34904b5Sbostic }
843a34904b5Sbostic return 0;
844a34904b5Sbostic }
845a34904b5Sbostic
usage()846a34904b5Sbostic static void usage()
847a34904b5Sbostic {
848a34904b5Sbostic fprintf(stderr, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
849a34904b5Sbostic program_name);
850a34904b5Sbostic exit(1);
851a34904b5Sbostic }
852