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

« back to all changes in this revision

Viewing changes to src/libs/libgroff/font.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, 1990, 1991, 1992, 2000, 2001
 
3
   Free Software Foundation, Inc.
 
4
     Written by James Clark (jjc@jclark.com)
 
5
 
 
6
This file is part of groff.
 
7
 
 
8
groff is free software; you can redistribute it and/or modify it under
 
9
the terms of the GNU General Public License as published by the Free
 
10
Software Foundation; either version 2, or (at your option) any later
 
11
version.
 
12
 
 
13
groff is distributed in the hope that it will be useful, but WITHOUT ANY
 
14
WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License along
 
19
with groff; see the file COPYING.  If not, write to the Free Software
 
20
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
21
 
 
22
#include <stdio.h>
 
23
#include <string.h>
 
24
#include <ctype.h>
 
25
#include <assert.h>
 
26
#include <math.h>
 
27
#include <stdlib.h>
 
28
#include "errarg.h"
 
29
#include "error.h"
 
30
#include "cset.h"
 
31
#include "font.h"
 
32
#include "lib.h"
 
33
 
 
34
const char *const WS = " \t\n\r";
 
35
 
 
36
struct font_char_metric {
 
37
  char type;
 
38
  int code;
 
39
  int width;
 
40
  int height;
 
41
  int depth;
 
42
  int pre_math_space;
 
43
  int italic_correction;
 
44
  int subscript_correction;
 
45
  char *special_device_coding;
 
46
};
 
47
 
 
48
struct font_kern_list {
 
49
  int i1;
 
50
  int i2;
 
51
  int amount;
 
52
  font_kern_list *next;
 
53
 
 
54
  font_kern_list(int, int, int, font_kern_list * = 0);
 
55
};
 
56
 
 
57
struct font_widths_cache {
 
58
  font_widths_cache *next;
 
59
  int point_size;
 
60
  int *width;
 
61
 
 
62
  font_widths_cache(int, int, font_widths_cache * = 0);
 
63
  ~font_widths_cache();
 
64
};
 
65
 
 
66
/* text_file */
 
67
 
 
68
struct text_file {
 
69
  FILE *fp;
 
70
  char *path;
 
71
  int lineno;
 
72
  int size;
 
73
  int skip_comments;
 
74
  char *buf;
 
75
  text_file(FILE *fp, char *p);
 
76
  ~text_file();
 
77
  int next();
 
78
  void error(const char *format, 
 
79
             const errarg &arg1 = empty_errarg,
 
80
             const errarg &arg2 = empty_errarg,
 
81
             const errarg &arg3 = empty_errarg);
 
82
};
 
83
 
 
84
text_file::text_file(FILE *p, char *s) 
 
85
: fp(p), path(s), lineno(0), size(0), skip_comments(1), buf(0)
 
86
{
 
87
}
 
88
 
 
89
text_file::~text_file()
 
90
{
 
91
  a_delete buf;
 
92
  a_delete path;
 
93
  if (fp)
 
94
    fclose(fp);
 
95
}
 
96
 
 
97
 
 
98
int text_file::next()
 
99
{
 
100
  if (fp == 0)
 
101
    return 0;
 
102
  if (buf == 0) {
 
103
    buf = new char [128];
 
104
    size = 128;
 
105
  }
 
106
  for (;;) {
 
107
    int i = 0;
 
108
    for (;;) {
 
109
      int c = getc(fp);
 
110
      if (c == EOF)
 
111
        break;
 
112
      if (illegal_input_char(c))
 
113
        error("illegal input character code `%1'", int(c));
 
114
      else {
 
115
        if (i + 1 >= size) {
 
116
          char *old_buf = buf;
 
117
          buf = new char[size*2];
 
118
          memcpy(buf, old_buf, size);
 
119
          a_delete old_buf;
 
120
          size *= 2;
 
121
        }
 
122
        buf[i++] = c;
 
123
        if (c == '\n')
 
124
          break;
 
125
      }
 
126
    }
 
127
    if (i == 0)
 
128
      break;
 
129
    buf[i] = '\0';
 
130
    lineno++;
 
131
    char *ptr = buf;
 
132
    while (csspace(*ptr))
 
133
      ptr++;
 
134
    if (*ptr != 0 && (!skip_comments || *ptr != '#'))
 
135
      return 1;
 
136
  }
 
137
  return 0;
 
138
}
 
139
 
 
140
void text_file::error(const char *format, 
 
141
                      const errarg &arg1,
 
142
                      const errarg &arg2,
 
143
                      const errarg &arg3)
 
144
{
 
145
  error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);
 
146
}
 
147
 
 
148
 
 
149
/* font functions */
 
150
 
 
151
font::font(const char *s)
 
152
: ligatures(0), kern_hash_table(0), space_width(0), ch_index(0), nindices(0),
 
153
  ch(0), ch_used(0), ch_size(0), special(0), widths_cache(0)
 
154
{
 
155
  name = new char[strlen(s) + 1];
 
156
  strcpy(name, s);
 
157
  internalname = 0;
 
158
  slant = 0.0;
 
159
  // load();                    // for testing
 
160
}
 
161
 
 
162
font::~font()
 
163
{
 
164
  a_delete ch;
 
165
  a_delete ch_index;
 
166
  if (kern_hash_table) {
 
167
    for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) {
 
168
      font_kern_list *kerns = kern_hash_table[i];
 
169
      while (kerns) {
 
170
        font_kern_list *tem = kerns;
 
171
        kerns = kerns->next;
 
172
        delete tem;
 
173
      }
 
174
    }
 
175
    a_delete kern_hash_table;
 
176
  }
 
177
  a_delete name;
 
178
  a_delete internalname;
 
179
  while (widths_cache) {
 
180
    font_widths_cache *tem = widths_cache;
 
181
    widths_cache = widths_cache->next;
 
182
    delete tem;
 
183
  }
 
184
}
 
185
 
 
186
static int scale_round(int n, int x, int y)
 
187
{
 
188
  assert(x >= 0 && y > 0);
 
189
  int y2 = y/2;
 
190
  if (x == 0)
 
191
    return 0;
 
192
  if (n >= 0) {
 
193
    if (n <= (INT_MAX - y2)/x)
 
194
      return (n*x + y2)/y;
 
195
    return int(n*double(x)/double(y) + .5);
 
196
  }
 
197
  else {
 
198
    if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
 
199
      return (n*x - y2)/y;
 
200
    return int(n*double(x)/double(y) - .5);
 
201
  }
 
202
}
 
203
 
 
204
inline int font::scale(int w, int sz)
 
205
{
 
206
  return sz == unitwidth ? w : scale_round(w, sz, unitwidth);
 
207
}
 
208
 
 
209
int font::get_skew(int c, int point_size, int sl)
 
210
{
 
211
  int h = get_height(c, point_size);
 
212
  return int(h*tan((slant+sl)*PI/180.0) + .5);
 
213
}
 
214
 
 
215
int font::contains(int c)
 
216
{
 
217
  return c >= 0 && c < nindices && ch_index[c] >= 0;
 
218
}
 
219
 
 
220
int font::is_special()
 
221
{
 
222
  return special;
 
223
}
 
224
 
 
225
font_widths_cache::font_widths_cache(int ps, int ch_size,
 
226
                                     font_widths_cache *p)
 
227
: next(p), point_size(ps)
 
228
{
 
229
  width = new int[ch_size];
 
230
  for (int i = 0; i < ch_size; i++)
 
231
    width[i] = -1;
 
232
}
 
233
 
 
234
font_widths_cache::~font_widths_cache()
 
235
{
 
236
  a_delete width;
 
237
}
 
238
 
 
239
int font::get_width(int c, int point_size)
 
240
{
 
241
  assert(c >= 0 && c < nindices);
 
242
  int i = ch_index[c];
 
243
  assert(i >= 0);
 
244
 
 
245
  if (point_size == unitwidth)
 
246
    return ch[i].width;
 
247
 
 
248
  if (!widths_cache)
 
249
    widths_cache = new font_widths_cache(point_size, ch_size);
 
250
  else if (widths_cache->point_size != point_size) {
 
251
    font_widths_cache **p;
 
252
    for (p = &widths_cache; *p; p = &(*p)->next)
 
253
      if ((*p)->point_size == point_size)
 
254
        break;
 
255
    if (*p) {
 
256
      font_widths_cache *tem = *p;
 
257
      *p = (*p)->next;
 
258
      tem->next = widths_cache;
 
259
      widths_cache = tem;
 
260
    }
 
261
    else
 
262
      widths_cache = new font_widths_cache(point_size, ch_size, widths_cache);
 
263
  }
 
264
  int &w = widths_cache->width[i];
 
265
  if (w < 0)
 
266
    w = scale(ch[i].width, point_size);
 
267
  return w;
 
268
}
 
269
 
 
270
int font::get_height(int c, int point_size)
 
271
{
 
272
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
273
  return scale(ch[ch_index[c]].height, point_size);
 
274
}
 
275
 
 
276
int font::get_depth(int c, int point_size)
 
277
{
 
278
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
279
  return scale(ch[ch_index[c]].depth, point_size);
 
280
}
 
281
 
 
282
int font::get_italic_correction(int c, int point_size)
 
283
{
 
284
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
285
  return scale(ch[ch_index[c]].italic_correction, point_size);
 
286
}
 
287
 
 
288
int font::get_left_italic_correction(int c, int point_size)
 
289
{
 
290
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
291
  return scale(ch[ch_index[c]].pre_math_space, point_size);
 
292
}
 
293
 
 
294
int font::get_subscript_correction(int c, int point_size)
 
295
{
 
296
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
297
  return scale(ch[ch_index[c]].subscript_correction, point_size);
 
298
}
 
299
 
 
300
int font::get_space_width(int point_size)
 
301
{
 
302
  return scale(space_width, point_size);
 
303
}
 
304
 
 
305
font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p)
 
306
     : i1(c1), i2(c2), amount(n), next(p)
 
307
{
 
308
}
 
309
 
 
310
inline int font::hash_kern(int i1, int i2)
 
311
{
 
312
  int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE;
 
313
  return n < 0 ? -n : n;
 
314
}
 
315
 
 
316
void font::add_kern(int i1, int i2, int amount)
 
317
{
 
318
  if (!kern_hash_table) {
 
319
    kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE];
 
320
    for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++)
 
321
      kern_hash_table[i] = 0;
 
322
  }
 
323
  font_kern_list **p = kern_hash_table + hash_kern(i1, i2);
 
324
  *p = new font_kern_list(i1, i2, amount, *p);
 
325
}
 
326
 
 
327
int font::get_kern(int i1, int i2, int point_size)
 
328
{
 
329
  if (kern_hash_table) {
 
330
    for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next)
 
331
      if (i1 == p->i1 && i2 == p->i2)
 
332
        return scale(p->amount, point_size);
 
333
  }
 
334
  return 0;
 
335
}
 
336
 
 
337
int font::has_ligature(int mask)
 
338
{
 
339
  return mask & ligatures;
 
340
}
 
341
 
 
342
int font::get_character_type(int c)
 
343
{
 
344
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
345
  return ch[ch_index[c]].type;
 
346
}
 
347
 
 
348
int font::get_code(int c)
 
349
{
 
350
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
351
  return ch[ch_index[c]].code;
 
352
}
 
353
 
 
354
const char *font::get_name()
 
355
{
 
356
  return name;
 
357
}
 
358
 
 
359
const char *font::get_internal_name()
 
360
{
 
361
  return internalname;
 
362
}
 
363
 
 
364
const char *font::get_special_device_encoding(int c)
 
365
{
 
366
  assert(c >= 0 && c < nindices && ch_index[c] >= 0);
 
367
  return( ch[ch_index[c]].special_device_coding );
 
368
}
 
369
 
 
370
void font::alloc_ch_index(int index)
 
371
{
 
372
  if (nindices == 0) {
 
373
    nindices = 128;
 
374
    if (index >= nindices)
 
375
      nindices = index + 10;
 
376
    ch_index = new short[nindices];
 
377
    for (int i = 0; i < nindices; i++)
 
378
      ch_index[i] = -1;
 
379
  }
 
380
  else {
 
381
    int old_nindices = nindices;
 
382
    nindices *= 2;
 
383
    if (index >= nindices)
 
384
      nindices = index + 10;
 
385
    short *old_ch_index = ch_index;
 
386
    ch_index = new short[nindices];
 
387
    memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices);
 
388
    for (int i = old_nindices; i < nindices; i++)
 
389
      ch_index[i] = -1;
 
390
    a_delete old_ch_index;
 
391
  }
 
392
}
 
393
 
 
394
void font::extend_ch()
 
395
{
 
396
  if (ch == 0)
 
397
    ch = new font_char_metric[ch_size = 16];
 
398
  else {
 
399
    int old_ch_size = ch_size;
 
400
    ch_size *= 2;
 
401
    font_char_metric *old_ch = ch;
 
402
    ch = new font_char_metric[ch_size];
 
403
    memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric));
 
404
    a_delete old_ch;
 
405
  }
 
406
}
 
407
 
 
408
void font::compact()
 
409
{
 
410
  int i;
 
411
  for (i = nindices - 1; i >= 0; i--)
 
412
    if (ch_index[i] >= 0)
 
413
      break;
 
414
  i++;
 
415
  if (i < nindices) {
 
416
    short *old_ch_index = ch_index;
 
417
    ch_index = new short[i];
 
418
    memcpy(ch_index, old_ch_index, i*sizeof(short));
 
419
    a_delete old_ch_index;
 
420
    nindices = i;
 
421
  }
 
422
  if (ch_used < ch_size) {
 
423
    font_char_metric *old_ch = ch;
 
424
    ch = new font_char_metric[ch_used];
 
425
    memcpy(ch, old_ch, ch_used*sizeof(font_char_metric));
 
426
    a_delete old_ch;
 
427
    ch_size = ch_used;
 
428
  }
 
429
}
 
430
 
 
431
void font::add_entry(int index, const font_char_metric &metric)
 
432
{
 
433
  assert(index >= 0);
 
434
  if (index >= nindices)
 
435
    alloc_ch_index(index);
 
436
  assert(index < nindices);
 
437
  if (ch_used + 1 >= ch_size)
 
438
    extend_ch();
 
439
  assert(ch_used + 1 < ch_size);
 
440
  ch_index[index] = ch_used;
 
441
  ch[ch_used++] = metric;
 
442
}
 
443
 
 
444
void font::copy_entry(int new_index, int old_index)
 
445
{
 
446
  assert(new_index >= 0 && old_index >= 0 && old_index < nindices);
 
447
  if (new_index >= nindices)
 
448
    alloc_ch_index(new_index);
 
449
  ch_index[new_index] = ch_index[old_index];
 
450
}
 
451
 
 
452
font *font::load_font(const char *s, int *not_found)
 
453
{
 
454
  font *f = new font(s);
 
455
  if (!f->load(not_found)) {
 
456
    delete f;
 
457
    return 0;
 
458
  }
 
459
  return f;
 
460
}
 
461
 
 
462
static char *trim_arg(char *p)
 
463
{
 
464
  if (!p)
 
465
    return 0;
 
466
  while (csspace(*p))
 
467
    p++;
 
468
  char *q = strchr(p, '\0');
 
469
  while (q > p && csspace(q[-1]))
 
470
    q--;
 
471
  *q = '\0';
 
472
  return p;
 
473
}
 
474
 
 
475
// If the font can't be found, then if not_found is non-NULL, it will be set
 
476
// to 1 otherwise a message will be printed.
 
477
 
 
478
int font::load(int *not_found)
 
479
{
 
480
  char *path;
 
481
  FILE *fp;
 
482
  if ((fp = open_file(name, &path)) == NULL) {
 
483
    if (not_found)
 
484
      *not_found = 1;
 
485
    else
 
486
      error("can't find font file `%1'", name);
 
487
    return 0;
 
488
  }
 
489
  text_file t(fp, path);
 
490
  t.skip_comments = 1;
 
491
  char *p;
 
492
  for (;;) {
 
493
    if (!t.next()) {
 
494
      t.error("missing charset command");
 
495
      return 0;
 
496
    }
 
497
    p = strtok(t.buf, WS);
 
498
    if (strcmp(p, "name") == 0) {
 
499
    }
 
500
    else if (strcmp(p, "spacewidth") == 0) {
 
501
      p = strtok(0, WS);
 
502
      int n;
 
503
      if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) {
 
504
        t.error("bad argument for spacewidth command");
 
505
        return 0;
 
506
      }
 
507
      space_width = n;
 
508
    }
 
509
    else if (strcmp(p, "slant") == 0) {
 
510
      p = strtok(0, WS);
 
511
      double n;
 
512
      if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) {
 
513
        t.error("bad argument for slant command", p);
 
514
        return 0;
 
515
      }
 
516
      slant = n;
 
517
    }
 
518
    else if (strcmp(p, "ligatures") == 0) {
 
519
      for (;;) {
 
520
        p = strtok(0, WS);
 
521
        if (p == 0 || strcmp(p, "0") == 0)
 
522
          break;
 
523
        if (strcmp(p, "ff") == 0)
 
524
          ligatures |= LIG_ff;
 
525
        else if (strcmp(p, "fi") == 0)
 
526
          ligatures |= LIG_fi;
 
527
        else if (strcmp(p, "fl") == 0)
 
528
          ligatures |= LIG_fl;
 
529
        else if (strcmp(p, "ffi") == 0)
 
530
          ligatures |= LIG_ffi;
 
531
        else if (strcmp(p, "ffl") == 0)
 
532
          ligatures |= LIG_ffl;
 
533
        else {
 
534
          t.error("unrecognised ligature `%1'", p);
 
535
          return 0;
 
536
        }
 
537
      }
 
538
    }
 
539
    else if (strcmp(p, "internalname") == 0) {
 
540
      p = strtok(0, WS);
 
541
      if (!p) {
 
542
        t.error("`internalname command requires argument");
 
543
        return 0;
 
544
      }
 
545
      internalname = new char[strlen(p) + 1];
 
546
      strcpy(internalname, p);
 
547
    }
 
548
    else if (strcmp(p, "special") == 0) {
 
549
      special = 1;
 
550
    }
 
551
    else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) {
 
552
      char *command = p;
 
553
      p = strtok(0, "\n");
 
554
      handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno);
 
555
    }
 
556
    else
 
557
      break;
 
558
  }
 
559
  char *command = p;
 
560
  int had_charset = 0;
 
561
  t.skip_comments = 0;
 
562
  while (command) {
 
563
    if (strcmp(command, "kernpairs") == 0) {
 
564
      for (;;) {
 
565
        if (!t.next()) {
 
566
          command = 0;
 
567
          break;
 
568
        }
 
569
        char *c1 = strtok(t.buf, WS);
 
570
        if (c1 == 0)
 
571
          continue;
 
572
        char *c2 = strtok(0, WS);
 
573
        if (c2 == 0) {
 
574
          command = c1;
 
575
          break;
 
576
        }
 
577
        p = strtok(0, WS);
 
578
        if (p == 0) {
 
579
          t.error("missing kern amount");
 
580
          return 0;
 
581
        }
 
582
        int n;
 
583
        if (sscanf(p, "%d", &n) != 1) {
 
584
          t.error("bad kern amount `%1'", p);
 
585
          return 0;
 
586
        }
 
587
        int i1 = name_to_index(c1);
 
588
        if (i1 < 0) {
 
589
          t.error("illegal character `%1'", c1);
 
590
          return 0;
 
591
        }
 
592
        int i2 = name_to_index(c2);
 
593
        if (i2 < 0) {
 
594
          t.error("illegal character `%1'", c2);
 
595
          return 0;
 
596
        }
 
597
        add_kern(i1, i2, n);
 
598
      }
 
599
    }
 
600
    else if (strcmp(command, "charset") == 0) {
 
601
      had_charset = 1;
 
602
      int last_index = -1;
 
603
      for (;;) {
 
604
        if (!t.next()) {
 
605
          command = 0;
 
606
          break;
 
607
        }
 
608
        char *nm = strtok(t.buf, WS);
 
609
        if (nm == 0)
 
610
          continue;                     // I dont think this should happen
 
611
        p = strtok(0, WS);
 
612
        if (p == 0) {
 
613
          command = nm;
 
614
          break;
 
615
        }
 
616
        if (p[0] == '"') {
 
617
          if (last_index == -1) {
 
618
            t.error("first charset entry is duplicate");
 
619
            return 0;
 
620
          }
 
621
          if (strcmp(nm, "---") == 0) {
 
622
            t.error("unnamed character cannot be duplicate");
 
623
            return 0;
 
624
          }
 
625
          int index = name_to_index(nm);
 
626
          if (index < 0) {
 
627
            t.error("illegal character `%1'", nm);
 
628
            return 0;
 
629
          }
 
630
          copy_entry(index, last_index);
 
631
        }
 
632
        else {
 
633
          font_char_metric metric;
 
634
          metric.height = 0;
 
635
          metric.depth = 0;
 
636
          metric.pre_math_space = 0;
 
637
          metric.italic_correction = 0;
 
638
          metric.subscript_correction = 0;
 
639
          int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d",
 
640
                              &metric.width, &metric.height, &metric.depth,
 
641
                              &metric.italic_correction,
 
642
                              &metric.pre_math_space,
 
643
                              &metric.subscript_correction);
 
644
          if (nparms < 1) {
 
645
            t.error("bad width for `%1'", nm);
 
646
            return 0;
 
647
          }
 
648
          p = strtok(0, WS);
 
649
          if (p == 0) {
 
650
            t.error("missing character type for `%1'", nm);
 
651
            return 0;
 
652
          }
 
653
          int type;
 
654
          if (sscanf(p, "%d", &type) != 1) {
 
655
            t.error("bad character type for `%1'", nm);
 
656
            return 0;
 
657
          }
 
658
          if (type < 0 || type > 255) {
 
659
            t.error("character code `%1' out of range", type);
 
660
            return 0;
 
661
          }
 
662
          metric.type = type;
 
663
          p = strtok(0, WS);
 
664
          if (p == 0) {
 
665
            t.error("missing code for `%1'", nm);
 
666
            return 0;
 
667
          }
 
668
          char *ptr;
 
669
          metric.code = (int)strtol(p, &ptr, 0);
 
670
          if (metric.code == 0 && ptr == p) {
 
671
            t.error("bad code `%1' for character `%2'", p, nm);
 
672
            return 0;
 
673
          }
 
674
 
 
675
          p = strtok(0, WS);
 
676
          if ((p == NULL) || (strcmp(p, "--") == 0)) {
 
677
            metric.special_device_coding = NULL;
 
678
          } else {
 
679
            char *name=(char *)malloc(strlen(p)+1);
 
680
 
 
681
            if (name == NULL) {
 
682
              fatal("malloc failed while reading character encoding");
 
683
            }
 
684
            strcpy(name, p);
 
685
            metric.special_device_coding = name;
 
686
          }
 
687
 
 
688
          if (strcmp(nm, "---") == 0) {
 
689
            last_index = number_to_index(metric.code);
 
690
            add_entry(last_index, metric);
 
691
          }
 
692
          else {
 
693
            last_index = name_to_index(nm);
 
694
            if (last_index < 0) {
 
695
              t.error("illegal character `%1'", nm);
 
696
              return 0;
 
697
            }
 
698
            add_entry(last_index, metric);
 
699
            copy_entry(number_to_index(metric.code), last_index);
 
700
          }
 
701
        }
 
702
      }
 
703
      if (last_index == -1) {
 
704
        t.error("I didn't seem to find any characters");
 
705
        return 0;
 
706
      }
 
707
    }
 
708
    else {
 
709
      t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command);
 
710
      return 0;
 
711
    }
 
712
  }
 
713
  if (!had_charset) {
 
714
    t.error("missing charset command");
 
715
    return 0;
 
716
  }
 
717
  if (space_width == 0)
 
718
    space_width = scale_round(unitwidth, res, 72*3*sizescale);
 
719
  compact();
 
720
  return 1;
 
721
}
 
722
 
 
723
static struct {
 
724
  const char *command;
 
725
  int *ptr;
 
726
} table[] = {
 
727
  { "res", &font::res },
 
728
  { "hor", &font::hor },
 
729
  { "vert", &font::vert },
 
730
  { "unitwidth", &font::unitwidth },
 
731
  { "paperwidth", &font::paperwidth },
 
732
  { "paperlength", &font::paperlength },
 
733
  { "spare1", &font::biggestfont },
 
734
  { "biggestfont", &font::biggestfont },
 
735
  { "spare2", &font::spare2 },
 
736
  { "sizescale", &font::sizescale }
 
737
  };
 
738
 
 
739
 
 
740
int font::load_desc()
 
741
{
 
742
  int nfonts = 0;
 
743
  FILE *fp;
 
744
  char *path;
 
745
  if ((fp = open_file("DESC", &path)) == 0) {
 
746
    error("can't find `DESC' file");
 
747
    return 0;
 
748
  }
 
749
  text_file t(fp, path);
 
750
  t.skip_comments = 1;
 
751
  res = 0;
 
752
  while (t.next()) {
 
753
    char *p = strtok(t.buf, WS);
 
754
    int found = 0;
 
755
    unsigned int idx;
 
756
    for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++)
 
757
      if (strcmp(table[idx].command, p) == 0)
 
758
        found = 1;
 
759
    if (found) {
 
760
      char *q = strtok(0, WS);
 
761
      if (!q) {
 
762
        t.error("missing value for command `%1'", p);
 
763
        return 0;
 
764
      }
 
765
      //int *ptr = &(this->*(table[idx-1].ptr));
 
766
      int *ptr = table[idx-1].ptr;
 
767
      if (sscanf(q, "%d", ptr) != 1) {
 
768
        t.error("bad number `%1'", q);
 
769
        return 0;
 
770
      }
 
771
    }
 
772
    else if (strcmp("tcommand", p) == 0) {
 
773
      tcommand = 1;
 
774
    }
 
775
    else if (strcmp("pass_filenames", p) == 0) {
 
776
      pass_filenames = 1;
 
777
    }
 
778
    else if (strcmp("use_charnames_in_special", p) == 0) {
 
779
      use_charnames_in_special = 1;
 
780
    }
 
781
    else if (strcmp("family", p) == 0) {
 
782
      p = strtok(0, WS);
 
783
      if (!p) {
 
784
        t.error("family command requires an argument");
 
785
        return 0;
 
786
      }
 
787
      char *tem = new char[strlen(p)+1];
 
788
      strcpy(tem, p);
 
789
      family = tem;
 
790
    }
 
791
    else if (strcmp("fonts", p) == 0) {
 
792
      p = strtok(0, WS);
 
793
      if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) {
 
794
        t.error("bad number of fonts `%1'", p);
 
795
        return 0;
 
796
      }
 
797
      font_name_table = (const char **)new char *[nfonts+1]; 
 
798
      for (int i = 0; i < nfonts; i++) {
 
799
        p = strtok(0, WS);
 
800
        while (p == 0) {
 
801
          if (!t.next()) {
 
802
            t.error("end of file while reading list of fonts");
 
803
            return 0;
 
804
          }
 
805
          p = strtok(t.buf, WS);
 
806
        }
 
807
        char *temp = new char[strlen(p)+1];
 
808
        strcpy(temp, p);
 
809
        font_name_table[i] = temp;
 
810
      }
 
811
      p = strtok(0, WS);
 
812
      if (p != 0) {
 
813
        t.error("font count does not match number of fonts");
 
814
        return 0;
 
815
      }
 
816
      font_name_table[nfonts] = 0;
 
817
    }
 
818
    else if (strcmp("sizes", p) == 0) {
 
819
      int n = 16;
 
820
      sizes = new int[n];
 
821
      int i = 0;
 
822
      for (;;) {
 
823
        p = strtok(0, WS);
 
824
        while (p == 0) {
 
825
          if (!t.next()) {
 
826
            t.error("list of sizes must be terminated by `0'");
 
827
            return 0;
 
828
          }
 
829
          p = strtok(t.buf, WS);
 
830
        }
 
831
        int lower, upper;
 
832
        switch (sscanf(p, "%d-%d", &lower, &upper)) {
 
833
        case 1:
 
834
          upper = lower;
 
835
          // fall through
 
836
        case 2:
 
837
          if (lower <= upper && lower >= 0)
 
838
            break;
 
839
          // fall through
 
840
        default:
 
841
          t.error("bad size range `%1'", p);
 
842
          return 0;
 
843
        }
 
844
        if (i + 2 > n) {
 
845
          int *old_sizes = sizes;
 
846
          sizes = new int[n*2];
 
847
          memcpy(sizes, old_sizes, n*sizeof(int));
 
848
          n *= 2;
 
849
          a_delete old_sizes;
 
850
        }
 
851
        sizes[i++] = lower;
 
852
        if (lower == 0)
 
853
          break;
 
854
        sizes[i++] = upper;
 
855
      }
 
856
      if (i == 1) {
 
857
        t.error("must have some sizes");
 
858
        return 0;
 
859
      }
 
860
    }
 
861
    else if (strcmp("styles", p) == 0) {
 
862
      int style_table_size = 5;
 
863
      style_table = (const char **)new char *[style_table_size];
 
864
      int j;
 
865
      for (j = 0; j < style_table_size; j++)
 
866
        style_table[j] = 0;
 
867
      int i = 0;
 
868
      for (;;) {
 
869
        p = strtok(0, WS);
 
870
        if (p == 0)
 
871
          break;
 
872
        // leave room for terminating 0
 
873
        if (i + 1 >= style_table_size) {
 
874
          const char **old_style_table = style_table;
 
875
          style_table_size *= 2;
 
876
          style_table = (const char **)new char*[style_table_size];
 
877
          for (j = 0; j < i; j++)
 
878
            style_table[j] = old_style_table[j];
 
879
          for (; j < style_table_size; j++)
 
880
            style_table[j] = 0;
 
881
          a_delete old_style_table;
 
882
        }
 
883
        char *tem = new char[strlen(p) + 1];
 
884
        strcpy(tem, p);
 
885
        style_table[i++] = tem;
 
886
      }
 
887
    }
 
888
    else if (strcmp("charset", p) == 0)
 
889
      break;
 
890
    else if (unknown_desc_command_handler) {
 
891
      char *command = p;
 
892
      p = strtok(0, "\n");
 
893
      (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno);
 
894
    }
 
895
  }
 
896
  if (res == 0) {
 
897
    t.error("missing `res' command");
 
898
    return 0;
 
899
  }
 
900
  if (unitwidth == 0) {
 
901
    t.error("missing `unitwidth' command");
 
902
    return 0;
 
903
  }
 
904
  if (font_name_table == 0) {
 
905
    t.error("missing `fonts' command");
 
906
    return 0;
 
907
  }
 
908
  if (sizes == 0) {
 
909
    t.error("missing `sizes' command");
 
910
    return 0;
 
911
  }
 
912
  if (sizescale < 1) {
 
913
    t.error("bad `sizescale' value");
 
914
    return 0;
 
915
  }
 
916
  if (hor < 1) {
 
917
    t.error("bad `hor' value");
 
918
    return 0;
 
919
  }
 
920
  if (vert < 1) {
 
921
    t.error("bad `vert' value");
 
922
    return 0;
 
923
  }
 
924
  return 1;
 
925
}      
 
926
 
 
927
void font::handle_unknown_font_command(const char *, const char *,
 
928
                                       const char *, int)
 
929
{
 
930
}
 
931
 
 
932
FONT_COMMAND_HANDLER
 
933
font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func)
 
934
{
 
935
  FONT_COMMAND_HANDLER prev = unknown_desc_command_handler;
 
936
  unknown_desc_command_handler = func;
 
937
  return prev;
 
938
}
 
939