~ubuntu-branches/ubuntu/dapper/groff/dapper

« back to all changes in this revision

Viewing changes to src/utils/tfmtodit/tfmtodit.cc

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2002-03-17 04:11:50 UTC
  • Revision ID: james.westby@ubuntu.com-20020317041150-wkgfawjc3gxlk0o5
Tags: upstream-1.17.2
ImportĀ upstreamĀ versionĀ 1.17.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- C++ -*-
 
2
/* Copyright (C) 1989-1992, 2000, 2001 Free Software Foundation, Inc.
 
3
     Written by James Clark (jjc@jclark.com)
 
4
 
 
5
This file is part of groff.
 
6
 
 
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
 
10
version.
 
11
 
 
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
 
15
for more details.
 
16
 
 
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. */
 
20
 
 
21
/* I have tried to incorporate the changes needed for TeX 3.0 tfm files,
 
22
but I haven't tested them. */
 
23
 
 
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.
 
32
 
 
33
We do this by loading this definition after cmbase when creating cm.base.
 
34
 
 
35
def ignore_math_fit(expr left_adjustment,right_adjustment) =
 
36
 special "adjustment";
 
37
 numspecial left_adjustment*16/designsize;
 
38
 numspecial right_adjustment*16/designsize;
 
39
 enddef;
 
40
 
 
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.
 
45
 
 
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
 
48
both be zero. */
 
49
 
 
50
#include <stdio.h>
 
51
#include <stdlib.h>
 
52
#include <math.h>
 
53
#include <string.h>
 
54
#include <errno.h>
 
55
#include "lib.h"
 
56
#include "errarg.h"
 
57
#include "error.h"
 
58
#include "assert.h"
 
59
#include "cset.h"
 
60
#include "nonposix.h"
 
61
 
 
62
extern "C" const char *Version_string;
 
63
 
 
64
/* Values in the tfm file should be multiplied by this. */
 
65
 
 
66
#define MULTIPLIER 1
 
67
 
 
68
struct char_info_word {
 
69
  unsigned char width_index;
 
70
  char height_index;
 
71
  char depth_index;
 
72
  char italic_index;
 
73
  char tag;
 
74
  unsigned char remainder;
 
75
};
 
76
 
 
77
struct lig_kern_command {
 
78
  unsigned char skip_byte;
 
79
  unsigned char next_char;
 
80
  unsigned char op_byte;
 
81
  unsigned char remainder;
 
82
};
 
83
 
 
84
class tfm {
 
85
  int bc;
 
86
  int ec;
 
87
  int nw;
 
88
  int nh;
 
89
  int nd;
 
90
  int ni;
 
91
  int nl;
 
92
  int nk;
 
93
  int np;
 
94
  int cs;
 
95
  int ds;
 
96
  char_info_word *char_info;
 
97
  int *width;
 
98
  int *height;
 
99
  int *depth;
 
100
  int *italic;
 
101
  lig_kern_command *lig_kern;
 
102
  int *kern;
 
103
  int *param;
 
104
public:
 
105
  tfm();
 
106
  ~tfm();
 
107
  int load(const char *);
 
108
  int contains(int);
 
109
  int get_width(int);
 
110
  int get_height(int);
 
111
  int get_depth(int);
 
112
  int get_italic(int);
 
113
  int get_param(int, int *);
 
114
  int get_checksum();
 
115
  int get_design_size();
 
116
  int get_lig(unsigned char, unsigned char, unsigned char *);
 
117
  friend class kern_iterator;
 
118
};
 
119
 
 
120
class kern_iterator {
 
121
  tfm *t;
 
122
  int c;
 
123
  int i;
 
124
public:
 
125
  kern_iterator(tfm *);
 
126
  int next(unsigned char *c1, unsigned char *c2, int *k);
 
127
};
 
128
 
 
129
 
 
130
kern_iterator::kern_iterator(tfm *p)
 
131
: t(p), c(t->bc), i(-1)
 
132
{
 
133
}
 
134
 
 
135
int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k)
 
136
{
 
137
  for (; c <= t->ec; c++)
 
138
    if (t->char_info[c - t->bc].tag == 1) {
 
139
      if (i < 0) {
 
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);
 
144
      }
 
145
      for (;;) {
 
146
        int skip = t->lig_kern[i].skip_byte;
 
147
        if (skip <= 128 && t->lig_kern[i].op_byte >= 128) {
 
148
          *c1 = c;
 
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];
 
152
          if (skip == 128) {
 
153
            c++;
 
154
            i = -1;
 
155
          }
 
156
          else
 
157
            i += skip + 1;
 
158
          return 1;
 
159
        }
 
160
        if (skip >= 128)
 
161
          break;
 
162
        i += skip + 1;
 
163
      }
 
164
      i = -1;
 
165
    }
 
166
  return 0;
 
167
}
 
168
          
 
169
tfm::tfm()
 
170
: char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0),
 
171
  kern(0), param(0)
 
172
{
 
173
}
 
174
 
 
175
int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp)
 
176
{
 
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;
 
181
    for (;;) {
 
182
      int skip = lig_kern[i].skip_byte;
 
183
      if (skip > 128)
 
184
        break;
 
185
      // We are only interested in normal ligatures, for which
 
186
      // op_byte == 0.
 
187
      if (lig_kern[i].op_byte == 0
 
188
          && lig_kern[i].next_char == c2) {
 
189
        *cp = lig_kern[i].remainder;
 
190
        return 1;
 
191
      }
 
192
      if (skip == 128)
 
193
        break;
 
194
      i += skip + 1;
 
195
    }
 
196
  }
 
197
  return 0;
 
198
}
 
199
 
 
200
int tfm::contains(int i)
 
201
{
 
202
  return i >= bc && i <= ec && char_info[i - bc].width_index != 0;
 
203
}
 
204
 
 
205
int tfm::get_width(int i)
 
206
{
 
207
  return width[char_info[i - bc].width_index];
 
208
}
 
209
 
 
210
int tfm::get_height(int i)
 
211
{
 
212
  return height[char_info[i - bc].height_index];
 
213
}
 
214
 
 
215
int tfm::get_depth(int i)
 
216
{
 
217
  return depth[char_info[i - bc].depth_index];
 
218
}
 
219
 
 
220
int tfm::get_italic(int i)
 
221
{
 
222
  return italic[char_info[i - bc].italic_index];
 
223
}
 
224
 
 
225
int tfm::get_param(int i, int *p)
 
226
{
 
227
  if (i <= 0 || i > np)
 
228
    return 0;
 
229
  else {
 
230
    *p = param[i - 1];
 
231
    return 1;
 
232
  }
 
233
}
 
234
 
 
235
int tfm::get_checksum()
 
236
{
 
237
  return cs;
 
238
}
 
239
 
 
240
int tfm::get_design_size()
 
241
{
 
242
  return ds;
 
243
}
 
244
 
 
245
tfm::~tfm()
 
246
{
 
247
  a_delete char_info;
 
248
  a_delete width;
 
249
  a_delete height;
 
250
  a_delete depth;
 
251
  a_delete italic;
 
252
  a_delete lig_kern;
 
253
  a_delete kern;
 
254
  a_delete param;
 
255
}
 
256
  
 
257
int read2(unsigned char *&s)
 
258
{
 
259
  int n;
 
260
  n = *s++ << 8;
 
261
  n |= *s++;
 
262
  return n;
 
263
}
 
264
 
 
265
int read4(unsigned char *&s)
 
266
{
 
267
  int n;
 
268
  n = *s++ << 24;
 
269
  n |= *s++ << 16;
 
270
  n |= *s++ << 8;
 
271
  n |= *s++;
 
272
  return n;
 
273
}
 
274
 
 
275
 
 
276
int tfm::load(const char *file)
 
277
{
 
278
  errno = 0;
 
279
  FILE *fp = fopen(file, FOPEN_RB);
 
280
  if (!fp) {
 
281
    error("can't open `%1': %2", file, strerror(errno));
 
282
    return 0;
 
283
  }
 
284
  int c1 = getc(fp);
 
285
  int c2 = getc(fp);
 
286
  if (c1 == EOF || c2 == EOF) {
 
287
    fclose(fp);
 
288
    error("unexpected end of file on `%1'", file);
 
289
    return 0;
 
290
  }
 
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) {
 
295
    if (feof(fp))
 
296
      error("unexpected end of file on `%1'", file);
 
297
    else
 
298
      error("error on file `%1'", file);
 
299
    a_delete buf;
 
300
    fclose(fp);
 
301
    return 0;
 
302
  }
 
303
  fclose(fp);
 
304
  if (lf < 6) {
 
305
    error("bad tfm file `%1': impossibly short", file);
 
306
    a_delete buf;
 
307
    return 0;
 
308
  }
 
309
  unsigned char *ptr = buf;
 
310
  int lh = read2(ptr);
 
311
  bc = read2(ptr);
 
312
  ec = read2(ptr);
 
313
  nw = read2(ptr);
 
314
  nh = read2(ptr);
 
315
  nd = read2(ptr);
 
316
  ni = read2(ptr);
 
317
  nl = read2(ptr);
 
318
  nk = read2(ptr);
 
319
  int ne = read2(ptr);
 
320
  np = read2(ptr);
 
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);
 
323
    a_delete buf;
 
324
    return 0;
 
325
  }
 
326
  if (lh < 2) {
 
327
    error("bad tfm file `%1': header too short", file);
 
328
    a_delete buf;
 
329
    return 0;
 
330
  }
 
331
  char_info = new char_info_word[ec - bc + 1];
 
332
  width = new int[nw];
 
333
  height = new int[nh];
 
334
  depth = new int[nd];
 
335
  italic = new int[ni];
 
336
  lig_kern = new lig_kern_command[nl];
 
337
  kern = new int[nk];
 
338
  param = new int[np];
 
339
  int i;
 
340
  cs = read4(ptr);
 
341
  ds = read4(ptr);
 
342
  ptr += (lh-2)*4;
 
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;
 
348
    tem = *ptr++;
 
349
    char_info[i].italic_index = tem >> 2;
 
350
    char_info[i].tag = tem & 3;
 
351
    char_info[i].remainder = *ptr++;
 
352
  }
 
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++;
 
366
  }
 
367
  for (i = 0; i < nk; i++)
 
368
    kern[i] = read4(ptr);
 
369
  ptr += ne*4;
 
370
  for (i = 0; i < np; i++)
 
371
    param[i] = read4(ptr);
 
372
  assert(ptr == buf + lf*4 - 2);
 
373
  a_delete buf;
 
374
  return 1;
 
375
}
 
376
 
 
377
class gf {
 
378
  int left[256];
 
379
  int right[256];
 
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);
 
384
public:
 
385
  gf();
 
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]; }
 
389
};
 
390
 
 
391
gf::gf()
 
392
{
 
393
  for (int i = 0; i < 256; i++)
 
394
    left[i] = right[i] = 0;
 
395
}
 
396
 
 
397
int gf::load(const char *file)
 
398
{
 
399
  enum {
 
400
    paint_0 = 0,
 
401
    paint1 = 64,
 
402
    boc = 67,
 
403
    boc1 = 68,
 
404
    eoc = 69,
 
405
    skip0 = 70,
 
406
    skip1 = 71,
 
407
    new_row_0 = 74,
 
408
    xxx1 = 239,
 
409
    yyy = 243,
 
410
    no_op = 244,
 
411
    pre = 247,
 
412
    post = 248
 
413
  };
 
414
  int got_an_adjustment = 0;
 
415
  int pending_adjustment = 0;
 
416
  int left_adj, right_adj;
 
417
  const int gf_id_byte = 131;
 
418
  errno = 0;
 
419
  FILE *fp = fopen(file, FOPEN_RB);
 
420
  if (!fp) {
 
421
    error("can't open `%1': %2", file, strerror(errno));
 
422
    return 0;
 
423
  }
 
424
  if (getc(fp) != pre || getc(fp) != gf_id_byte) {
 
425
    error("bad gf file");
 
426
    return 0;
 
427
  }
 
428
  int n = getc(fp);
 
429
  if (n == EOF)
 
430
    goto eof;
 
431
  if (!skip(n, fp))
 
432
    goto eof;
 
433
  for (;;) {
 
434
    int op = getc(fp);
 
435
    if (op == EOF)
 
436
      goto eof;
 
437
    if (op == post)
 
438
      break;
 
439
    if ((op >= paint_0 && op <= paint_0 + 63)
 
440
        || (op >= new_row_0 && op <= new_row_0 + 164))
 
441
      continue;
 
442
    switch (op) {
 
443
    case no_op:
 
444
    case eoc:
 
445
    case skip0:
 
446
      break;
 
447
    case paint1:
 
448
    case skip1:
 
449
      if (!skip(1, fp))
 
450
        goto eof;
 
451
      break;
 
452
    case paint1 + 1:
 
453
    case skip1 + 1:
 
454
      if (!skip(2, fp))
 
455
        goto eof;
 
456
      break;
 
457
    case paint1 + 2:
 
458
    case skip1 + 2:
 
459
      if (!skip(3, fp))
 
460
        goto eof;
 
461
      break;
 
462
    case boc:
 
463
      {
 
464
        int code;
 
465
        if (!sread4(&code, fp))
 
466
          goto eof;
 
467
        if (pending_adjustment) {
 
468
          pending_adjustment = 0;
 
469
          left[code & 0377] = left_adj;
 
470
          right[code & 0377] = right_adj;
 
471
        }
 
472
        if (!skip(20, fp))
 
473
          goto eof;
 
474
        break;
 
475
      }
 
476
    case boc1:
 
477
      {
 
478
        int code = getc(fp);
 
479
        if (code == EOF)
 
480
          goto eof;
 
481
        if (pending_adjustment) {
 
482
          pending_adjustment = 0;
 
483
          left[code] = left_adj;
 
484
          right[code] = right_adj;
 
485
        }
 
486
        if (!skip(4, fp))
 
487
          goto eof;
 
488
        break;
 
489
      }
 
490
    case xxx1:
 
491
      {
 
492
        int len = getc(fp);
 
493
        if (len == EOF)
 
494
          goto eof;
 
495
        char buf[256];
 
496
        if (fread(buf, 1, len, fp) != (size_t)len)
 
497
          goto eof;
 
498
        if (len == 10 /* strlen("adjustment") */
 
499
            && memcmp(buf, "adjustment", len) == 0) {
 
500
          int c = getc(fp);
 
501
          if (c != yyy) {
 
502
            if (c != EOF)
 
503
              ungetc(c, fp);
 
504
            break;
 
505
          }
 
506
          if (!sread4(&left_adj, fp))
 
507
            goto eof;
 
508
          c = getc(fp);
 
509
          if (c != yyy) {
 
510
            if (c != EOF)
 
511
              ungetc(c, fp);
 
512
            break;
 
513
          }
 
514
          if (!sread4(&right_adj, fp))
 
515
            goto eof;
 
516
          got_an_adjustment = 1;
 
517
          pending_adjustment = 1;
 
518
        }
 
519
        break;
 
520
      }
 
521
    case xxx1 + 1:
 
522
      if (!uread2(&n, fp) || !skip(n, fp))
 
523
        goto eof;
 
524
      break;
 
525
    case xxx1 + 2:
 
526
      if (!uread3(&n, fp) || !skip(n, fp))
 
527
        goto eof;
 
528
      break;
 
529
    case xxx1 + 3:
 
530
      if (!sread4(&n, fp) || !skip(n, fp))
 
531
        goto eof;
 
532
      break;
 
533
    case yyy:
 
534
      if (!skip(4, fp))
 
535
        goto eof;
 
536
      break;
 
537
    default:
 
538
      fatal("unrecognized opcode `%1'", op);
 
539
      break;
 
540
    }
 
541
  }
 
542
  if (!got_an_adjustment)
 
543
    warning("no adjustment specials found in gf file");
 
544
  return 1;
 
545
 eof:
 
546
  error("unexpected end of file");
 
547
  return 0;
 
548
}
 
549
 
 
550
int gf::sread4(int *p, FILE *fp)
 
551
{
 
552
  *p = getc(fp);
 
553
  if (*p >= 128)
 
554
    *p -= 256;
 
555
  *p <<= 8;
 
556
  *p |= getc(fp);
 
557
  *p <<= 8;
 
558
  *p |= getc(fp);
 
559
  *p <<= 8;
 
560
  *p |= getc(fp);
 
561
  return !ferror(fp) && !feof(fp);
 
562
}
 
563
 
 
564
int gf::uread3(int *p, FILE *fp)
 
565
{
 
566
  *p = getc(fp);
 
567
  *p <<= 8;
 
568
  *p |= getc(fp);
 
569
  *p <<= 8;
 
570
  *p |= getc(fp);
 
571
  return !ferror(fp) && !feof(fp);
 
572
}
 
573
 
 
574
int gf::uread2(int *p, FILE *fp)
 
575
{
 
576
  *p = getc(fp);
 
577
  *p <<= 8;
 
578
  *p |= getc(fp);
 
579
  return !ferror(fp) && !feof(fp);
 
580
}
 
581
 
 
582
int gf::skip(int n, FILE *fp)
 
583
{
 
584
  while (--n >= 0)
 
585
    if (getc(fp) == EOF)
 
586
      return 0;
 
587
  return 1;
 
588
}
 
589
 
 
590
 
 
591
struct char_list {
 
592
  char *ch;
 
593
  char_list *next;
 
594
  char_list(const char *, char_list * = 0);
 
595
};
 
596
 
 
597
char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p)
 
598
{
 
599
}
 
600
 
 
601
 
 
602
int read_map(const char *file, char_list **table)
 
603
{
 
604
  errno = 0;
 
605
  FILE *fp = fopen(file, "r");
 
606
  if (!fp) {
 
607
    error("can't open `%1': %2", file, strerror(errno));
 
608
    return 0;
 
609
  }
 
610
  for (int i = 0; i < 256; i++)
 
611
    table[i] = 0;
 
612
  char buf[512];
 
613
  int lineno = 0;
 
614
  while (fgets(buf, int(sizeof(buf)), fp)) {
 
615
    lineno++;
 
616
    char *ptr = buf;
 
617
    while (csspace(*ptr))
 
618
      ptr++;
 
619
    if (*ptr == '\0' || *ptr == '#')
 
620
      continue;
 
621
    ptr = strtok(ptr, " \n\t");
 
622
    if (!ptr)
 
623
      continue;
 
624
    int n;
 
625
    if (sscanf(ptr, "%d", &n) != 1) {
 
626
      error("%1:%2: bad map file", file, lineno);
 
627
      fclose(fp);
 
628
      return 0;
 
629
    }
 
630
    if (n < 0 || n > 255) {
 
631
      error("%1:%2: code out of range", file, lineno);
 
632
      fclose(fp);
 
633
      return 0;
 
634
    }
 
635
    ptr = strtok(0, " \n\t");
 
636
    if (!ptr) {
 
637
      error("%1:%2: missing names", file, lineno);
 
638
      fclose(fp);
 
639
      return 0;
 
640
    }
 
641
    for (; ptr; ptr = strtok(0, " \n\t"))
 
642
      table[n] = new char_list(ptr, table[n]);
 
643
  }
 
644
  fclose(fp);
 
645
  return 1;
 
646
}
 
647
 
 
648
 
 
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). */
 
653
 
 
654
struct {
 
655
  const char *ch;
 
656
  int i;
 
657
} lig_chars[] = {
 
658
  { "f", -1 },
 
659
  { "i", -1 },
 
660
  { "l", -1 },
 
661
  { "ff", -1 },
 
662
  { "fi", -1 },
 
663
  { "fl", -1 },
 
664
  { "Fi", -1 },
 
665
  { "Fl", -1 },
 
666
};
 
667
 
 
668
// Indices into lig_chars[].
 
669
 
 
670
enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl };
 
671
 
 
672
// Each possible ligature appears in this table.
 
673
 
 
674
struct {
 
675
  unsigned char c1, c2, res;
 
676
  const char *ch;
 
677
} lig_table[] = {
 
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" },
 
683
  };
 
684
 
 
685
static void usage(FILE *stream);
 
686
  
 
687
int main(int argc, char **argv)
 
688
{
 
689
  program_name = argv[0];
 
690
  int special_flag = 0;
 
691
  int skewchar = -1;
 
692
  int opt;
 
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' },
 
697
    { NULL, 0, 0, 0 }
 
698
  };
 
699
  while ((opt = getopt_long(argc, argv, "svg:k:", long_options, NULL)) != EOF)
 
700
    switch (opt) {
 
701
    case 'g':
 
702
      gf_file = optarg;
 
703
      break;
 
704
    case 's':
 
705
      special_flag = 1;
 
706
      break;
 
707
    case 'k':
 
708
      {
 
709
        char *ptr;
 
710
        long n = strtol(optarg, &ptr, 0);
 
711
        if ((n == 0 && ptr == optarg)
 
712
            || *ptr != '\0'
 
713
            || n < 0
 
714
            || n > UCHAR_MAX)
 
715
          error("invalid skewchar");
 
716
        else
 
717
          skewchar = (int)n;
 
718
        break;
 
719
      }
 
720
    case 'v':
 
721
      {
 
722
        printf("GNU tfmtodit (groff) version %s\n", Version_string);
 
723
        exit(0);
 
724
        break;
 
725
      }
 
726
    case CHAR_MAX + 1: // --help
 
727
      usage(stdout);
 
728
      exit(0);
 
729
      break;
 
730
    case '?':
 
731
      usage(stderr);
 
732
      exit(1);
 
733
      break;
 
734
    case EOF:
 
735
      assert(0);
 
736
    }
 
737
  if (argc - optind != 3) {
 
738
    usage(stderr);
 
739
    exit(1);
 
740
  }
 
741
  gf g;
 
742
  if (gf_file) {
 
743
    if (!g.load(gf_file))
 
744
      return 1;
 
745
  }
 
746
  const char *tfm_file = argv[optind];
 
747
  const char *map_file = argv[optind + 1];
 
748
  const char *font_file = argv[optind + 2];
 
749
  tfm t;
 
750
  if (!t.load(tfm_file))
 
751
    return 1;
 
752
  char_list *table[256];
 
753
  if (!read_map(map_file, table))
 
754
    return 1;
 
755
  errno = 0;
 
756
  if (!freopen(font_file, "w", stdout)) {
 
757
    error("can't open `%1' for writing: %2", font_file, strerror(errno));
 
758
    return 1;
 
759
  }
 
760
  printf("name %s\n", font_file);
 
761
  if (special_flag)
 
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];
 
772
  while (*sep)
 
773
    {
 
774
      s1 = strrchr(internal_name, *sep);
 
775
      if (s1 && (!s || s1 > s))
 
776
        s = s1;
 
777
      sep++;
 
778
    }
 
779
  printf("internalname %s\n", s ? s + 1 : internal_name);
 
780
  int n;
 
781
  if (t.get_param(2, &n)) {
 
782
    if (n > 0)
 
783
      printf("spacewidth %d\n", n*MULTIPLIER);
 
784
  }
 
785
  if (t.get_param(1, &n) && n != 0)
 
786
    printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/PI);
 
787
  int xheight;
 
788
  if (!t.get_param(5, &xheight))
 
789
    xheight = 0;
 
790
  unsigned int i;
 
791
  // Print the list of ligatures.
 
792
  // First find the indices of each character that can participate in
 
793
  // a ligature.
 
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)
 
798
          lig_chars[j].i = i;
 
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.
 
802
  int started = 0;
 
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) {
 
808
      unsigned char c;
 
809
      if (t.get_lig(i1, i2, &c) && c == r) {
 
810
        if (!started) {
 
811
          started = 1;
 
812
          fputs("ligatures", stdout);
 
813
        }
 
814
        printf(" %s", lig_table[i].ch);
 
815
      }
 
816
    }
 
817
  }
 
818
  if (started)
 
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.
 
823
  int had_kern = 0;
 
824
  kern_iterator iter(&t);
 
825
  unsigned char c1, c2;
 
826
  int k;
 
827
  while (iter.next(&c1, &c2, &k))
 
828
    if (c2 != skewchar) {
 
829
      k *= MULTIPLIER;
 
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) {
 
833
          if (!had_kern) {
 
834
            printf("kernpairs\n");
 
835
            had_kern = 1;
 
836
          }
 
837
          printf("%s %s %d\n", p1->ch, p2->ch, k);
 
838
        }
 
839
    }
 
840
  printf("charset\n");
 
841
  char_list unnamed("---");
 
842
  for (i = 0; i < 256; i++) 
 
843
    if (t.contains(i)) {
 
844
      char_list *p = table[i] ? table[i] : &unnamed;
 
845
      int m[6];
 
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);
 
853
      int j;
 
854
      for (j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--)
 
855
        if (m[j] != 0)
 
856
          break;
 
857
      for (k = 1; k <= j; k++)
 
858
        printf(",%d", m[k]*MULTIPLIER);
 
859
      int type = 0;
 
860
      if (m[2] > 0)
 
861
        type = 1;
 
862
      if (m[1] > xheight)
 
863
        type += 2;
 
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);
 
867
    }
 
868
  return 0;
 
869
}
 
870
 
 
871
static void usage(FILE *stream)
 
872
{
 
873
  fprintf(stream, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n",
 
874
          program_name);
 
875
}