~ubuntu-branches/ubuntu/oneiric/evince/oneiric-updates

« back to all changes in this revision

Viewing changes to dvi/mdvi-lib/fontmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-01-10 19:35:11 UTC
  • mto: (1.3.1 experimental) (52.1.1 hardy-proposed)
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: james.westby@ubuntu.com-20070110193511-yjrnndv8e8wv03yy
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* encoding.c - functions to manipulate encodings and fontmaps */
2
 
/*
3
 
 * Copyright (C) 2000, Matias Atria
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 */
19
 
 
20
 
#include <string.h>
21
 
#include <stdlib.h>
22
 
#include <stdio.h>
23
 
#include <errno.h>
24
 
#include <sys/stat.h>
25
 
 
26
 
#include "mdvi.h"
27
 
#include "private.h"
28
 
 
29
 
#include <kpathsea/expand.h>
30
 
#include <kpathsea/pathsearch.h>
31
 
 
32
 
typedef struct _DviFontMap DviFontMap;
33
 
 
34
 
struct _DviFontMap {
35
 
        ListHead entries;
36
 
        DviHashTable fonts;
37
 
};
38
 
 
39
 
typedef struct _PSFontMap {
40
 
        struct _PSFontMap *next;
41
 
        struct _PSFontMap *prev;
42
 
        char    *psname;
43
 
        char    *mapname;
44
 
        char    *fullname;
45
 
} PSFontMap;
46
 
 
47
 
/* these variables control PS font maps */
48
 
static char *pslibdir = NULL;   /* path where we look for PS font maps */
49
 
static char *psfontdir = NULL;  /* PS font search path */
50
 
static int psinitialized = 0;   /* did we expand the path already? */
51
 
 
52
 
static ListHead psfonts = MDVI_EMPTY_LIST_HEAD;
53
 
static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE;
54
 
 
55
 
static ListHead fontmaps;
56
 
static DviHashTable maptable;
57
 
static int fontmaps_loaded = 0;
58
 
 
59
 
#define MAP_HASH_SIZE   57
60
 
#define ENC_HASH_SIZE   31
61
 
#define PSMAP_HASH_SIZE 57
62
 
 
63
 
/* this hash table should be big enough to 
64
 
 * hold (ideally) one glyph name per bucket */
65
 
#define ENCNAME_HASH_SIZE       131 /* most TeX fonts have 128 glyphs */
66
 
 
67
 
static ListHead encodings = MDVI_EMPTY_LIST_HEAD;
68
 
static DviEncoding *tex_text_encoding = NULL;
69
 
static DviEncoding *default_encoding = NULL;
70
 
 
71
 
/* we keep two hash tables for encodings: one for their base files (e.g.
72
 
 * "8r.enc"), and another one for their names (e.g. "TeXBase1Encoding") */ 
73
 
static DviHashTable enctable = MDVI_EMPTY_HASH_TABLE;
74
 
static DviHashTable enctable_file = MDVI_EMPTY_HASH_TABLE;
75
 
 
76
 
/* the TeX text encoding, from dvips */
77
 
static char *tex_text_vector[256] = {
78
 
        "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon",
79
 
        "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
80
 
        "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave",
81
 
        "acute", "caron", "breve", "macron", "ring", "cedilla",
82
 
        "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash", "space",
83
 
        "exclam", "quotedbl", "numbersign", "dollar", "percent",
84
 
        "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
85
 
        "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two",
86
 
        "three", "four", "five", "six", "seven", "eight", "nine", "colon",
87
 
        "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
88
 
        "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
89
 
        "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
90
 
        "bracketleft", "backslash", "bracketright", "circumflex",
91
 
        "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h",
92
 
        "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
93
 
        "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "tilde",
94
 
        "dieresis", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95
 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96
 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97
 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98
 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99
 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
100
 
};
101
 
 
102
 
static void ps_init_default_paths __PROTO((void));
103
 
static int      mdvi_set_default_encoding __PROTO((const char *name));
104
 
static int      mdvi_init_fontmaps __PROTO((void));
105
 
 
106
 
/* 
107
 
 * What we do here is allocate one block large enough to hold the entire
108
 
 * file (these files are small) minus the leading comments. This is much
109
 
 * better than allocating up to 256 tiny strings per encoding vector. */
110
 
static int read_encoding(DviEncoding *enc)
111
 
{
112
 
        FILE    *in;
113
 
        int     curr;
114
 
        char    *line;
115
 
        char    *name;
116
 
        char    *next;
117
 
        struct stat st;
118
 
        
119
 
        ASSERT(enc->private == NULL);
120
 
 
121
 
        in = fopen(enc->filename, "r");
122
 
        if(in == NULL) {
123
 
                DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n",
124
 
                        enc->name, enc->filename, strerror(errno)));
125
 
                return -1;
126
 
        }
127
 
        if(fstat(fileno(in), &st) < 0) {
128
 
                /* should not happen */
129
 
                fclose(in);
130
 
                return -1;
131
 
        }
132
 
        st.st_size -= enc->offset;
133
 
 
134
 
        /* this will be one big string */
135
 
        enc->private = (char *)malloc(st.st_size + 1);
136
 
        /* setup the hash table */
137
 
        mdvi_hash_create(&enc->nametab, ENCNAME_HASH_SIZE);
138
 
        /* setup the encoding vector */
139
 
        enc->vector = (char **)mdvi_malloc(256 * sizeof(char *));
140
 
 
141
 
        /* jump to the beginning of the interesting part */
142
 
        fseek(in, enc->offset, SEEK_SET);
143
 
        /* and read everything */
144
 
        if(fread(enc->private, st.st_size, 1, in) != 1) {
145
 
                fclose(in);
146
 
                mdvi_free(enc->private);
147
 
                enc->private = NULL;
148
 
                return -1;
149
 
        }
150
 
        /* we don't need this anymore */
151
 
        fclose(in);
152
 
        curr = 0;
153
 
 
154
 
        next = name = NULL;
155
 
        DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name));  
156
 
        for(line = enc->private; *line && curr < 256; line = next) {
157
 
                SKIPSP(line);
158
 
                if(*line == ']') {
159
 
                        line++; SKIPSP(line);
160
 
                        if(STRNEQ(line, "def", 3))
161
 
                                break;
162
 
                }
163
 
                name = getword(line, " \t\n", &next);
164
 
                if(name == NULL)
165
 
                        break;
166
 
                /* next > line */
167
 
                if(*name < ' ')
168
 
                        continue;
169
 
                if(*name == '%') {
170
 
                        while(*next && *next != '\n')
171
 
                                next++;
172
 
                        if(*next) next++; /* skip \n */
173
 
                        continue;
174
 
                }
175
 
 
176
 
                /* got a name */
177
 
                if(*next) *next++ = 0;
178
 
                
179
 
                if(*name == '/')
180
 
                        name++;
181
 
                enc->vector[curr] = name;
182
 
                /* add it to the hash table */
183
 
                if(!STREQ(name, ".notdef")) {
184
 
                        mdvi_hash_add(&enc->nametab, MDVI_KEY(name), 
185
 
                                Int2Ptr(curr + 1), MDVI_HASH_REPLACE);
186
 
                }
187
 
                curr++;
188
 
        }
189
 
        if(curr == 0) {
190
 
                mdvi_hash_reset(&enc->nametab, 0);
191
 
                mdvi_free(enc->private);
192
 
                mdvi_free(enc);
193
 
                return -1;
194
 
        }
195
 
        while(curr < 256)
196
 
                enc->vector[curr++] = NULL;
197
 
        return 0;
198
 
}
199
 
 
200
 
static DviEncoding *find_encoding(const char *name)
201
 
{
202
 
        return (DviEncoding *)(encodings.count ? 
203
 
                mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL);
204
 
}
205
 
 
206
 
static void destroy_encoding(DviEncoding *enc)
207
 
{
208
 
        if(enc == default_encoding) {
209
 
                default_encoding = tex_text_encoding;
210
 
                /* now we use reference counts again */
211
 
                mdvi_release_encoding(enc, 1);
212
 
        }
213
 
        if(enc != tex_text_encoding) {
214
 
                mdvi_hash_reset(&enc->nametab, 0);
215
 
                if(enc->private) {
216
 
                        mdvi_free(enc->private);
217
 
                        mdvi_free(enc->vector);
218
 
                }
219
 
                if(enc->name)
220
 
                        mdvi_free(enc->name);
221
 
                if(enc->filename)
222
 
                        mdvi_free(enc->filename);
223
 
                mdvi_free(enc);
224
 
        }
225
 
}
226
 
 
227
 
/* this is used for the `enctable_file' hash table */
228
 
static void file_hash_free(DviHashKey key, void *data)
229
 
{
230
 
        mdvi_free(key);
231
 
}
232
 
 
233
 
static DviEncoding *register_encoding(const char *basefile, int replace)
234
 
{
235
 
        DviEncoding *enc;
236
 
        FILE    *in;
237
 
        char    *filename;
238
 
        char    *name;
239
 
        Dstring input;
240
 
        char    *line;
241
 
        long    offset;
242
 
 
243
 
        DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile));
244
 
 
245
 
        if(encodings.count) {
246
 
                enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile));
247
 
                if(enc != NULL) {
248
 
                        DEBUG((DBG_FMAP, "%s: already there\n", basefile));
249
 
                        return enc; /* no error */
250
 
                }
251
 
        } 
252
 
 
253
 
        /* try our own files first */
254
 
        filename = kpse_find_file(basefile, 
255
 
                kpse_program_text_format, 0);
256
 
 
257
 
        /* then try the system-wide ones */
258
 
        if(filename == NULL)
259
 
                filename = kpse_find_file(basefile, 
260
 
                        kpse_tex_ps_header_format, 0);
261
 
        if(filename == NULL)
262
 
                filename = kpse_find_file(basefile,
263
 
                        kpse_dvips_config_format, 0);
264
 
 
265
 
        /* finally try the given name */
266
 
        if(filename == NULL)
267
 
                filename = mdvi_strdup(basefile);
268
 
 
269
 
        in = fopen(filename, "r");
270
 
        if(in == NULL) {
271
 
                mdvi_free(filename);
272
 
                return NULL;
273
 
        }
274
 
        
275
 
        /* just lookup the name of the encoding */
276
 
        name = NULL;
277
 
        dstring_init(&input);
278
 
        while((line = dgets(&input, in)) != NULL) {
279
 
                if(STRNEQ(line, "Encoding=", 9)) {
280
 
                        name = getword(line + 9, " \t", &line);
281
 
                        if(*line) *line++ = 0;
282
 
                        break;
283
 
                } else if(*line == '/') {
284
 
                        char    *label = getword(line + 1, " \t", &line);
285
 
                        if(*line) {
286
 
                                *line++ = 0;
287
 
                                SKIPSP(line);
288
 
                                if(*line == '[') {
289
 
                                        *line = 0;
290
 
                                        name = label;
291
 
                                        break;
292
 
                                }
293
 
                        }
294
 
                }
295
 
        }
296
 
        offset = ftell(in);
297
 
        fclose(in);
298
 
        if(name == NULL || *name == 0) {
299
 
                DEBUG((DBG_FMAP, 
300
 
                        "%s: could not determine name of encoding\n",
301
 
                        basefile));
302
 
                mdvi_free(filename);
303
 
                return NULL;
304
 
        }
305
 
        
306
 
        /* check if the encoding is already there */
307
 
        enc = find_encoding(name);
308
 
        if(enc == tex_text_encoding) {
309
 
                /* A special case: if the vector we found is the static one,
310
 
                 * allow the user to override it with an external file */
311
 
                listh_remove(&encodings, LIST(enc));
312
 
                mdvi_hash_remove(&enctable, MDVI_KEY(enc->name));
313
 
                if(enc == default_encoding)
314
 
                        default_encoding = NULL;
315
 
        } else if(enc) {
316
 
                /* if the encoding is being used, refuse to remove it */
317
 
                if(enc->links) {
318
 
                        mdvi_free(filename);
319
 
                        dstring_reset(&input);
320
 
                        return NULL;
321
 
                }
322
 
                if(replace) {
323
 
                        mdvi_hash_remove(&enctable, MDVI_KEY(name));
324
 
                        mdvi_hash_remove(&enctable_file, MDVI_KEY(basefile));
325
 
                        listh_remove(&encodings, LIST(enc));
326
 
                        if(enc == default_encoding) {
327
 
                                default_encoding = NULL;
328
 
                                mdvi_release_encoding(enc, 1);
329
 
                        }
330
 
                        DEBUG((DBG_FMAP, "%s: overriding encoding\n", name));
331
 
                        destroy_encoding(enc);
332
 
                } else {
333
 
                        mdvi_free(filename);
334
 
                        dstring_reset(&input);
335
 
                        return enc; /* no error */
336
 
                }
337
 
        }
338
 
        enc = xalloc(DviEncoding);
339
 
        enc->name = mdvi_strdup(name);
340
 
        enc->filename = filename;
341
 
        enc->links = 0;
342
 
        enc->offset = offset;
343
 
        enc->private = NULL;
344
 
        enc->vector = NULL;
345
 
        mdvi_hash_init(&enc->nametab);
346
 
        dstring_reset(&input);
347
 
        if(default_encoding == NULL)
348
 
                default_encoding = enc;
349
 
        mdvi_hash_add(&enctable, MDVI_KEY(enc->name), 
350
 
                enc, MDVI_HASH_UNCHECKED);
351
 
        mdvi_hash_add(&enctable_file, MDVI_KEY(mdvi_strdup(basefile)), 
352
 
                enc, MDVI_HASH_REPLACE);
353
 
        listh_prepend(&encodings, LIST(enc));
354
 
        DEBUG((DBG_FMAP, "%s: encoding `%s' registered\n",
355
 
                basefile, enc->name));
356
 
        return enc;
357
 
}
358
 
 
359
 
DviEncoding *mdvi_request_encoding(const char *name)
360
 
{
361
 
        DviEncoding *enc = find_encoding(name);
362
 
 
363
 
        if(enc == NULL) {
364
 
                DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n",
365
 
                        name, default_encoding->name));
366
 
                return default_encoding;
367
 
        }
368
 
        /* we don't keep reference counts for this */
369
 
        if(enc == tex_text_encoding)
370
 
                return enc;
371
 
        if(!enc->private && read_encoding(enc) < 0)
372
 
                return NULL;
373
 
        enc->links++;
374
 
 
375
 
        /* if the hash table is empty, rebuild it */
376
 
        if(enc->nametab.nkeys == 0) {
377
 
                int     i;
378
 
 
379
 
                DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name));                
380
 
                for(i = 0; i < 256; i++) {
381
 
                        if(enc->vector[i] == NULL)
382
 
                                continue;
383
 
                        mdvi_hash_add(&enc->nametab,
384
 
                                MDVI_KEY(enc->vector[i]),
385
 
                                (DviHashKey)Int2Ptr(i),
386
 
                                MDVI_HASH_REPLACE);
387
 
                }
388
 
        }
389
 
        return enc;
390
 
}
391
 
 
392
 
void    mdvi_release_encoding(DviEncoding *enc, int should_free)
393
 
{
394
 
        /* ignore our static encoding */
395
 
        if(enc == tex_text_encoding)
396
 
                return;
397
 
        if(!enc->links || --enc->links > 0 || !should_free)
398
 
                return;
399
 
        DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name));
400
 
        mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */
401
 
}
402
 
 
403
 
int     mdvi_encode_glyph(DviEncoding *enc, const char *name)
404
 
{
405
 
        void    *data;
406
 
        
407
 
        data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name));
408
 
        if(data == NULL)
409
 
                return -1;
410
 
        /* we added +1 to the hashed index just to distinguish
411
 
         * a failed lookup from a zero index. Adjust it now. */
412
 
        return (Ptr2Int(data) - 1);
413
 
}
414
 
 
415
 
/****************
416
 
 * Fontmaps     *
417
 
 ****************/
418
 
 
419
 
static void parse_spec(DviFontMapEnt *ent, char *spec)
420
 
{
421
 
        char    *arg, *command;
422
 
        
423
 
        /* this is a ridiculously simple parser, and recognizes only
424
 
         * things of the form <argument> <command>. Of these, only
425
 
         * command=SlantFont, ExtendFont and ReEncodeFont are handled */
426
 
        while(*spec) {
427
 
                arg = getword(spec, " \t", &spec);
428
 
                if(*spec) *spec++ = 0;
429
 
                command = getword(spec, " \t", &spec);
430
 
                if(*spec) *spec++ = 0;
431
 
                if(!arg || !command)    
432
 
                        continue;
433
 
                if(STREQ(command, "SlantFont")) {
434
 
                        double  x = 10000 * strtod(arg, 0);
435
 
                
436
 
                        /* SFROUND evaluates arguments twice */ 
437
 
                        ent->slant = SFROUND(x);
438
 
                } else if(STREQ(command, "ExtendFont")) {
439
 
                        double  x = 10000 * strtod(arg, 0);
440
 
                        
441
 
                        ent->extend = SFROUND(x);
442
 
                } else if(STREQ(command, "ReEncodeFont")) {
443
 
                        if(ent->encoding)
444
 
                                mdvi_free(ent->encoding);
445
 
                        ent->encoding = mdvi_strdup(arg);
446
 
                }
447
 
        }
448
 
}
449
 
 
450
 
#if 0
451
 
static void print_ent(DviFontMapEnt *ent)
452
 
{
453
 
        printf("Entry for `%s':\n", ent->fontname);
454
 
        printf("  PS name: %s\n", ent->psname ? ent->psname : "(none)");
455
 
        printf("  Encoding: %s\n", ent->encoding ? ent->encoding : "(default)");
456
 
        printf("  EncFile: %s\n", ent->encfile ? ent->encfile : "(none)");
457
 
        printf("  FontFile: %s\n", ent->fontfile ? ent->fontfile : "(same)");
458
 
        printf("  Extend: %ld\n", ent->extend);
459
 
        printf("  Slant: %ld\n", ent->slant);
460
 
}
461
 
#endif
462
 
 
463
 
DviFontMapEnt   *mdvi_load_fontmap(const char *file)
464
 
{
465
 
        char    *ptr;
466
 
        FILE    *in;
467
 
        int     lineno = 1;
468
 
        Dstring input;
469
 
        ListHead list;
470
 
        DviFontMapEnt *ent;
471
 
        DviEncoding     *last_encoding;
472
 
        char    *last_encfile;
473
 
 
474
 
        ptr = kpse_find_file(file, kpse_program_text_format, 0);
475
 
        if(ptr == NULL)
476
 
                ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0);
477
 
        if(ptr == NULL)
478
 
                ptr = kpse_find_file(file, kpse_dvips_config_format, 0);
479
 
        if(ptr == NULL)
480
 
                in = fopen(file, "r");                  
481
 
        else {
482
 
                in = fopen(ptr, "r");
483
 
                mdvi_free(ptr);
484
 
        }
485
 
        if(in == NULL)
486
 
                return NULL;
487
 
                
488
 
        ent = NULL;
489
 
        listh_init(&list);
490
 
        dstring_init(&input);
491
 
        last_encoding = NULL;
492
 
        last_encfile  = NULL;
493
 
                
494
 
        while((ptr = dgets(&input, in)) != NULL) {
495
 
                char    *font_file;
496
 
                char    *tex_name;
497
 
                char    *ps_name;
498
 
                char    *vec_name;
499
 
                int     is_encoding;
500
 
                DviEncoding *enc;
501
 
 
502
 
                lineno++;
503
 
                SKIPSP(ptr);
504
 
                
505
 
                /* we skip what dvips does */
506
 
                if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' || 
507
 
                   *ptr == ';' || *ptr == '%')
508
 
                        continue;
509
 
                        
510
 
                font_file   = NULL;
511
 
                tex_name    = NULL;
512
 
                ps_name     = NULL;
513
 
                vec_name    = NULL;
514
 
                is_encoding = 0;
515
 
 
516
 
                if(ent == NULL) {
517
 
                        ent = xalloc(DviFontMapEnt);
518
 
                        ent->encoding = NULL;
519
 
                        ent->slant = 0;
520
 
                        ent->extend = 0;
521
 
                }
522
 
                while(*ptr) {
523
 
                        char    *hdr_name = NULL;
524
 
                        
525
 
                        while(*ptr && *ptr <= ' ')
526
 
                                ptr++;
527
 
                        if(*ptr == 0)
528
 
                                break;
529
 
                        if(*ptr == '"') {
530
 
                                char    *str;
531
 
                                
532
 
                                str = getstring(ptr, " \t", &ptr);
533
 
                                if(*ptr) *ptr++ = 0;
534
 
                                parse_spec(ent, str);
535
 
                                continue;
536
 
                        } else if(*ptr == '<') {
537
 
                                ptr++;
538
 
                                if(*ptr == '<')
539
 
                                        ptr++;
540
 
                                else if(*ptr == '[') {
541
 
                                        is_encoding = 1;
542
 
                                        ptr++;
543
 
                                }
544
 
                                SKIPSP(ptr);
545
 
                                hdr_name = ptr;
546
 
                        } else if(!tex_name)
547
 
                                tex_name = ptr;
548
 
                        else if(!ps_name)
549
 
                                ps_name = ptr;
550
 
                        else
551
 
                                hdr_name = ptr;
552
 
 
553
 
                        /* get next word */
554
 
                        getword(ptr, " \t", &ptr);
555
 
                        if(*ptr) *ptr++ = 0;
556
 
 
557
 
                        if(hdr_name) {
558
 
                                const char *ext = file_extension(hdr_name);
559
 
                                
560
 
                                if(is_encoding || (ext && STRCEQ(ext, "enc")))
561
 
                                        vec_name = hdr_name;
562
 
                                else
563
 
                                        font_file = hdr_name;
564
 
                        }
565
 
                }
566
 
 
567
 
                if(tex_name == NULL)
568
 
                        continue;
569
 
                ent->fontname = mdvi_strdup(tex_name);
570
 
                ent->psname   = ps_name   ? mdvi_strdup(ps_name)   : NULL;
571
 
                ent->fontfile = font_file ? mdvi_strdup(font_file) : NULL;
572
 
                ent->encfile  = vec_name  ? mdvi_strdup(vec_name)  : NULL;
573
 
                ent->fullfile = NULL;
574
 
                enc = NULL; /* we don't have this yet */
575
 
 
576
 
                /* if we have an encoding file, register it */
577
 
                if(ent->encfile) {
578
 
                        /* register_encoding is smart enough not to load the 
579
 
                         * same file twice */
580
 
                        if(!last_encfile || !STREQ(last_encfile, ent->encfile)) {
581
 
                                last_encfile  = ent->encfile;
582
 
                                last_encoding = register_encoding(ent->encfile, 1);
583
 
                        }
584
 
                        enc = last_encoding;
585
 
                }
586
 
                if(ent->encfile && enc){                
587
 
                        if(ent->encoding && !STREQ(ent->encoding, enc->name)) {
588
 
                                warning(
589
 
        _("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"),
590
 
                                        file, lineno);
591
 
                        } else if(!ent->encoding)
592
 
                                ent->encoding = mdvi_strdup(enc->name);
593
 
                }
594
 
                
595
 
                /* add it to the list */
596
 
                /*print_ent(ent);*/
597
 
                listh_append(&list, LIST(ent));
598
 
                ent = NULL;
599
 
        }
600
 
        dstring_reset(&input);  
601
 
        fclose(in);
602
 
        
603
 
        return (DviFontMapEnt *)list.head;
604
 
}
605
 
 
606
 
static void free_ent(DviFontMapEnt *ent)
607
 
{
608
 
        ASSERT(ent->fontname != NULL);
609
 
        mdvi_free(ent->fontname);
610
 
        if(ent->psname)
611
 
                mdvi_free(ent->psname);
612
 
        if(ent->fontfile)
613
 
                mdvi_free(ent->fontfile);
614
 
        if(ent->encoding)
615
 
                mdvi_free(ent->encoding);
616
 
        if(ent->encfile)
617
 
                mdvi_free(ent->encfile);
618
 
        if(ent->fullfile)
619
 
                mdvi_free(ent->fullfile);
620
 
        mdvi_free(ent);
621
 
}
622
 
 
623
 
void    mdvi_install_fontmap(DviFontMapEnt *head)
624
 
{
625
 
        DviFontMapEnt *ent, *next;
626
 
 
627
 
        for(ent = head; ent; ent = next) {
628
 
                /* add all the entries, overriding old ones */
629
 
                DviFontMapEnt *old;
630
 
                
631
 
                old = (DviFontMapEnt *)
632
 
                        mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname));
633
 
                if(old != NULL) {
634
 
                        DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n",
635
 
                                old->fontname));
636
 
                        listh_remove(&fontmaps, LIST(old));
637
 
                        free_ent(old);
638
 
                }
639
 
                next = ent->next;
640
 
                mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname), 
641
 
                        ent, MDVI_HASH_UNCHECKED);
642
 
                listh_append(&fontmaps, LIST(ent));
643
 
        }
644
 
}
645
 
 
646
 
static void init_static_encoding()
647
 
{
648
 
        DviEncoding     *encoding;
649
 
        int     i;
650
 
 
651
 
        DEBUG((DBG_FMAP, "installing static TeX text encoding\n"));     
652
 
        encoding = xalloc(DviEncoding);
653
 
        encoding->private  = "";
654
 
        encoding->filename = "";
655
 
        encoding->name     = "TeXTextEncoding";
656
 
        encoding->vector   = tex_text_vector;
657
 
        encoding->links    = 1;
658
 
        encoding->offset   = 0;
659
 
        mdvi_hash_create(&encoding->nametab, ENCNAME_HASH_SIZE);
660
 
        for(i = 0; i < 256; i++) {
661
 
                if(encoding->vector[i]) {
662
 
                        mdvi_hash_add(&encoding->nametab,
663
 
                                MDVI_KEY(encoding->vector[i]),
664
 
                                (DviHashKey)Int2Ptr(i),
665
 
                                MDVI_HASH_UNCHECKED);
666
 
                }
667
 
        }
668
 
        ASSERT_VALUE(encodings.count, 0);
669
 
        mdvi_hash_create(&enctable, ENC_HASH_SIZE);
670
 
        mdvi_hash_create(&enctable_file, ENC_HASH_SIZE);
671
 
        enctable_file.hash_free = file_hash_free;
672
 
        mdvi_hash_add(&enctable, MDVI_KEY(encoding->name), 
673
 
                encoding, MDVI_HASH_UNCHECKED);
674
 
        listh_prepend(&encodings, LIST(encoding));
675
 
        tex_text_encoding = encoding;
676
 
        default_encoding = tex_text_encoding;
677
 
}
678
 
 
679
 
static int      mdvi_set_default_encoding(const char *name)
680
 
{
681
 
        DviEncoding *enc, *old;
682
 
 
683
 
        enc = find_encoding(name);
684
 
        if(enc == NULL)
685
 
                return -1;
686
 
        if(enc == default_encoding)
687
 
                return 0;
688
 
        /* this will read it from file if necessary,
689
 
         * but it can fail if the file is corrupted */
690
 
        enc = mdvi_request_encoding(name);
691
 
        if(enc == NULL)
692
 
                return -1;
693
 
        old = default_encoding;
694
 
        default_encoding = enc;
695
 
        if(old != tex_text_encoding)
696
 
                mdvi_release_encoding(old, 1);
697
 
        return 0;
698
 
}
699
 
 
700
 
static int      mdvi_init_fontmaps(void)
701
 
{
702
 
        char    *file;
703
 
        char    *line;
704
 
        FILE    *in;
705
 
        Dstring input;
706
 
        int     count = 0;
707
 
        char    *config;
708
 
 
709
 
        if(fontmaps_loaded)
710
 
                return 0;
711
 
        /* we will only try this once */
712
 
        fontmaps_loaded = 1;
713
 
 
714
 
        DEBUG((DBG_FMAP, "reading fontmaps\n"));
715
 
 
716
 
        /* make sure the static encoding is there */
717
 
        init_static_encoding();
718
 
 
719
 
        /* create the fontmap hash table */
720
 
        mdvi_hash_create(&maptable, MAP_HASH_SIZE);
721
 
                        
722
 
        /* get the name of our configuration file */
723
 
        config = kpse_cnf_get("mdvi-config");
724
 
        if(config == NULL)
725
 
                config = MDVI_DEFAULT_CONFIG;
726
 
        /* let's ask kpathsea for the file first */
727
 
        file = kpse_find_file(config, kpse_program_text_format, 0);
728
 
        if(file == NULL)
729
 
                in = fopen(config, "r");
730
 
        else {
731
 
                in = fopen(file, "r");
732
 
                mdvi_free(file);
733
 
        }
734
 
        if(in == NULL)
735
 
                return -1;
736
 
        dstring_init(&input);
737
 
        while((line = dgets(&input, in)) != NULL) {
738
 
                char    *arg;
739
 
                
740
 
                SKIPSP(line);
741
 
                if(*line < ' ' || *line == '#' || *line == '%')
742
 
                        continue;
743
 
                if(STRNEQ(line, "fontmap", 7)) {
744
 
                        DviFontMapEnt *ent;
745
 
                        
746
 
                        arg = getstring(line + 7, " \t", &line); *line = 0;
747
 
                        DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg));
748
 
                        ent = mdvi_load_fontmap(arg);
749
 
                        if(ent == NULL)
750
 
                                warning(_("%s: could not load fontmap\n"), arg);
751
 
                        else {
752
 
                                DEBUG((DBG_FMAP, 
753
 
                                        "%s: installing fontmap\n", arg));
754
 
                                mdvi_install_fontmap(ent);
755
 
                                count++;
756
 
                        }
757
 
                } else if(STRNEQ(line, "encoding", 8)) {
758
 
                        arg = getstring(line + 8, " \t", &line); *line = 0;
759
 
                        if(arg && *arg)
760
 
                                register_encoding(arg, 1);
761
 
                } else if(STRNEQ(line, "default-encoding", 16)) {
762
 
                        arg = getstring(line + 16, " \t", &line); *line = 0;
763
 
                        if(mdvi_set_default_encoding(arg) < 0)
764
 
                                warning(_("%s: could not set as default encoding\n"),
765
 
                                        arg);
766
 
                } else if(STRNEQ(line, "psfontpath", 10)) {
767
 
                        arg = getstring(line + 11, " \t", &line); *line = 0;
768
 
                        if(!psinitialized)
769
 
                                ps_init_default_paths();
770
 
                        if(psfontdir)
771
 
                                mdvi_free(psfontdir);
772
 
                        psfontdir = kpse_path_expand(arg);
773
 
                } else if(STRNEQ(line, "pslibpath", 9)) {
774
 
                        arg = getstring(line + 10, " \t", &line); *line = 0;
775
 
                        if(!psinitialized)
776
 
                                ps_init_default_paths();
777
 
                        if(pslibdir)
778
 
                                mdvi_free(pslibdir);
779
 
                        pslibdir = kpse_path_expand(arg);
780
 
                } else if(STRNEQ(line, "psfontmap", 9)) {
781
 
                        arg = getstring(line + 9, " \t", &line); *line = 0;
782
 
                        if(mdvi_ps_read_fontmap(arg) < 0)
783
 
                                warning("%s: %s: could not read PS fontmap\n",
784
 
                                        config, arg);
785
 
                }
786
 
        }
787
 
        fclose(in);
788
 
        dstring_reset(&input);
789
 
        fontmaps_loaded = 1;
790
 
        DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n",
791
 
                count, fontmaps.count));
792
 
        return count;
793
 
}
794
 
 
795
 
int     mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname)
796
 
{
797
 
        DviFontMapEnt *ent;
798
 
 
799
 
        if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
800
 
                return -1;              
801
 
        ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname));
802
 
 
803
 
        if(ent == NULL)
804
 
                return -1;
805
 
        info->psname   = ent->psname;
806
 
        info->encoding = ent->encoding;
807
 
        info->fontfile = ent->fontfile;
808
 
        info->extend   = ent->extend;
809
 
        info->slant    = ent->slant;
810
 
        info->fullfile = ent->fullfile;
811
 
        
812
 
        return 0;       
813
 
}
814
 
 
815
 
int     mdvi_add_fontmap_file(const char *name, const char *fullpath)
816
 
{
817
 
        DviFontMapEnt *ent;
818
 
        
819
 
        if(!fontmaps_loaded && mdvi_init_fontmaps() < 0)
820
 
                return -1;
821
 
        ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name));
822
 
        if(ent == NULL)
823
 
                return -1;
824
 
        if(ent->fullfile)
825
 
                mdvi_free(ent->fullfile);
826
 
        ent->fullfile = mdvi_strdup(fullpath);
827
 
        return 0;
828
 
}
829
 
 
830
 
 
831
 
void    mdvi_flush_encodings(void)
832
 
{
833
 
        DviEncoding *enc;
834
 
 
835
 
        if(enctable.nbucks == 0)
836
 
                return;
837
 
 
838
 
        DEBUG((DBG_FMAP, "flushing %d encodings\n", encodings.count));
839
 
        /* asked to remove all encodings */
840
 
        for(; (enc = (DviEncoding *)encodings.head); ) {
841
 
                encodings.head = LIST(enc->next);
842
 
                if((enc != tex_text_encoding && enc->links) || enc->links > 1) {
843
 
                        warning(_("encoding vector `%s' is in use\n"),
844
 
                                enc->name);
845
 
                }
846
 
                destroy_encoding(enc);
847
 
        }
848
 
        /* destroy the static encoding */
849
 
        if(tex_text_encoding->nametab.buckets)
850
 
                mdvi_hash_reset(&tex_text_encoding->nametab, 0);
851
 
        mdvi_hash_reset(&enctable, 0);
852
 
        mdvi_hash_reset(&enctable_file, 0);     
853
 
}
854
 
 
855
 
void    mdvi_flush_fontmaps(void)
856
 
{
857
 
        DviFontMapEnt *ent;
858
 
        
859
 
        if(!fontmaps_loaded)
860
 
                return;
861
 
 
862
 
        DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count));
863
 
        for(; (ent = (DviFontMapEnt *)fontmaps.head); ) {
864
 
                fontmaps.head = LIST(ent->next);
865
 
                free_ent(ent);
866
 
        }
867
 
        mdvi_hash_reset(&maptable, 0);
868
 
        fontmaps_loaded = 0;
869
 
}
870
 
 
871
 
/* reading of PS fontmaps */
872
 
 
873
 
void    ps_init_default_paths(void)
874
 
{
875
 
        char    *kppath;
876
 
        char    *kfpath;
877
 
 
878
 
        ASSERT(psinitialized == 0);
879
 
 
880
 
        kppath = getenv("GS_LIB");
881
 
        kfpath = getenv("GS_FONTPATH"); 
882
 
 
883
 
        if(kppath != NULL)
884
 
                pslibdir = kpse_path_expand(kppath);
885
 
        if(kfpath != NULL)
886
 
                psfontdir = kpse_path_expand(kfpath);
887
 
 
888
 
        listh_init(&psfonts);
889
 
        mdvi_hash_create(&pstable, PSMAP_HASH_SIZE);
890
 
        psinitialized = 1;
891
 
}
892
 
 
893
 
int     mdvi_ps_read_fontmap(const char *name)
894
 
{
895
 
        char    *fullname;
896
 
        FILE    *in;
897
 
        Dstring dstr;
898
 
        char    *line;
899
 
        int     count = 0;
900
 
        
901
 
        if(!psinitialized)
902
 
                ps_init_default_paths();
903
 
        if(pslibdir)
904
 
                fullname = kpse_path_search(pslibdir, name, 1);
905
 
        else
906
 
                fullname = (char *)name;
907
 
        in = fopen(fullname, "r");
908
 
        if(in == NULL) {
909
 
                if(fullname != name)
910
 
                        mdvi_free(fullname);
911
 
                return -1;
912
 
        }
913
 
        dstring_init(&dstr);
914
 
        
915
 
        while((line = dgets(&dstr, in)) != NULL) {
916
 
                char    *name;
917
 
                char    *mapname;
918
 
                const char *ext;
919
 
                PSFontMap *ps;
920
 
                
921
 
                SKIPSP(line);
922
 
                /* we're looking for lines of the form
923
 
                 *  /FONT-NAME    (fontfile)
924
 
                 *  /FONT-NAME    /FONT-ALIAS 
925
 
                 */
926
 
                if(*line != '/')
927
 
                        continue;
928
 
                name = getword(line + 1, " \t", &line);
929
 
                if(*line) *line++ = 0;
930
 
                mapname = getword(line, " \t", &line);
931
 
                if(*line) *line++ = 0;
932
 
                
933
 
                if(!name || !mapname || !*name)
934
 
                        continue;
935
 
                if(*mapname == '(') {
936
 
                        char    *end;
937
 
                        
938
 
                        mapname++;
939
 
                        for(end = mapname; *end && *end != ')'; end++);
940
 
                        *end = 0;
941
 
                }
942
 
                if(!*mapname)
943
 
                        continue;
944
 
                /* dont add `.gsf' fonts, which require a full blown
945
 
                 * PostScript interpreter */
946
 
                ext = file_extension(mapname);
947
 
                if(ext && STREQ(ext, "gsf")) {
948
 
                        DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n",
949
 
                                name, mapname));
950
 
                        continue;
951
 
                }
952
 
                ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name));
953
 
                if(ps != NULL) {
954
 
                        if(STREQ(ps->mapname, mapname))
955
 
                                continue;
956
 
                        DEBUG((DBG_FMAP, 
957
 
                                "(ps) replacing font `%s' (%s) by `%s'\n",
958
 
                                name, ps->mapname, mapname));
959
 
                        mdvi_free(ps->mapname);
960
 
                        ps->mapname = mdvi_strdup(mapname);
961
 
                        if(ps->fullname) {
962
 
                                mdvi_free(ps->fullname);
963
 
                                ps->fullname = NULL;
964
 
                        }
965
 
                } else {
966
 
                        DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n",
967
 
                                name, mapname));
968
 
                        ps = xalloc(PSFontMap);
969
 
                        ps->psname   = mdvi_strdup(name);
970
 
                        ps->mapname  = mdvi_strdup(mapname);
971
 
                        ps->fullname = NULL;
972
 
                        listh_append(&psfonts, LIST(ps));
973
 
                        mdvi_hash_add(&pstable, MDVI_KEY(ps->psname),
974
 
                                ps, MDVI_HASH_UNCHECKED);
975
 
                        count++;
976
 
                }
977
 
        }
978
 
        fclose(in);
979
 
        dstring_reset(&dstr);
980
 
        
981
 
        DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n",
982
 
                fullname, count));
983
 
        return 0;
984
 
}
985
 
 
986
 
void    mdvi_ps_flush_fonts(void)
987
 
{
988
 
        PSFontMap *map;
989
 
        
990
 
        if(!psinitialized)
991
 
                return;
992
 
        DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n",
993
 
                psfonts.count));
994
 
        mdvi_hash_reset(&pstable, 0);
995
 
        for(; (map = (PSFontMap *)psfonts.head); ) {
996
 
                psfonts.head = LIST(map->next);
997
 
                mdvi_free(map->psname);
998
 
                mdvi_free(map->mapname);
999
 
                if(map->fullname)
1000
 
                        mdvi_free(map->fullname);
1001
 
                mdvi_free(map);
1002
 
        }
1003
 
        listh_init(&psfonts);
1004
 
        if(pslibdir) {
1005
 
                mdvi_free(pslibdir);
1006
 
                pslibdir = NULL;
1007
 
        }
1008
 
        if(psfontdir) {
1009
 
                mdvi_free(psfontdir);
1010
 
                psfontdir = NULL;
1011
 
        }
1012
 
        psinitialized = 0;
1013
 
}
1014
 
 
1015
 
char    *mdvi_ps_find_font(const char *psname)
1016
 
{
1017
 
        PSFontMap *map, *smap;
1018
 
        char    *filename;
1019
 
        int     recursion_limit = 32;
1020
 
 
1021
 
        DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname));
1022
 
        if(!psinitialized)
1023
 
                return NULL;
1024
 
        map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname));
1025
 
        if(map == NULL)
1026
 
                return NULL;
1027
 
        if(map->fullname)
1028
 
                return mdvi_strdup(map->fullname);
1029
 
 
1030
 
        /* is it an alias? */
1031
 
        smap = map;
1032
 
        while(recursion_limit-- > 0 && smap && *smap->mapname == '/')
1033
 
                smap = (PSFontMap *)mdvi_hash_lookup(&pstable, 
1034
 
                        MDVI_KEY(smap->mapname + 1));
1035
 
        if(smap == NULL) {
1036
 
                if(recursion_limit == 0)
1037
 
                        DEBUG((DBG_FMAP, 
1038
 
                                "(ps) %s: possible loop in PS font map\n",
1039
 
                                psname));
1040
 
                return NULL;
1041
 
        }
1042
 
 
1043
 
        if(psfontdir)
1044
 
                filename = kpse_path_search(psfontdir, smap->mapname, 1);
1045
 
        else if(file_exists(map->mapname))
1046
 
                filename = mdvi_strdup(map->mapname);
1047
 
        else
1048
 
                filename = NULL;
1049
 
        if(filename)
1050
 
                map->fullname = mdvi_strdup(filename);
1051
 
                
1052
 
        return filename;
1053
 
}
1054
 
 
1055
 
/*
1056
 
 * To get metric info for a font, we proceed as follows:
1057
 
 *  - We try to find NAME.<tfm,ofm,afm>.
1058
 
 *  - We query the fontmap for NAME.
1059
 
 *  - We get back a PSNAME, and use to find the file in the PS font map.
1060
 
 *  - We get the PSFONT file name, replace its extension by "afm" and
1061
 
 *  lookup the file in GS's font search path.
1062
 
 *  - We finally read the data, transform it as specified in our font map,
1063
 
 *  and return it to the caller. The new data is left in the font metrics
1064
 
 *  cache, so the next time it will be found at the first step (when we look
1065
 
 *  up NAME.afm).
1066
 
 *
1067
 
 * The name `_ps_' in this function is not meant to imply that it can be 
1068
 
 * used for Type1 fonts only. It should be usable for TrueType fonts as well.
1069
 
 *
1070
 
 * The returned metric info is subjected to the same caching mechanism as
1071
 
 * all the other metric data, as returned by get_font_metrics(). One should
1072
 
 * not modify the returned data at all, and it should be disposed with
1073
 
 * free_font_metrics().
1074
 
 */
1075
 
TFMInfo *mdvi_ps_get_metrics(const char *fontname)
1076
 
{
1077
 
        TFMInfo *info;
1078
 
        DviFontMapInfo map;
1079
 
        char    buffer[64]; /* to avoid mallocs */
1080
 
        char    *psfont;
1081
 
        char    *basefile;
1082
 
        char    *afmfile;
1083
 
        char    *ext;
1084
 
        int     baselen;
1085
 
        int     nc;
1086
 
        TFMChar *ch;
1087
 
        double  efactor;
1088
 
        double  sfactor;
1089
 
 
1090
 
        DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname));      
1091
 
        info = get_font_metrics(fontname, DviFontAny, NULL);
1092
 
        if(info != NULL)
1093
 
                return info;
1094
 
 
1095
 
        /* query the fontmap */
1096
 
        if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname)
1097
 
                return NULL;
1098
 
        
1099
 
        /* get the PS font */
1100
 
        psfont = mdvi_ps_find_font(map.psname);
1101
 
        if(psfont == NULL)
1102
 
                return NULL;
1103
 
        DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n",
1104
 
                fontname, psfont));
1105
 
        /* replace its extension */
1106
 
        basefile = strrchr(psfont, '/');
1107
 
        if(basefile == NULL)
1108
 
                basefile = psfont;
1109
 
        baselen = strlen(basefile);
1110
 
        ext = strrchr(basefile, '.');
1111
 
        if(ext != NULL)
1112
 
                *ext = 0;
1113
 
        if(baselen + 4 < 64)
1114
 
                afmfile = &buffer[0];
1115
 
        else
1116
 
                afmfile = mdvi_malloc(baselen + 5);
1117
 
        strcpy(afmfile, basefile);
1118
 
        strcpy(afmfile + baselen, ".afm");
1119
 
        /* we don't need this anymore */
1120
 
        mdvi_free(psfont);
1121
 
        DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n",
1122
 
                fontname, afmfile));
1123
 
        /* lookup the file */
1124
 
        psfont = kpse_path_search(psfontdir, afmfile, 1);
1125
 
        /* don't need this anymore */
1126
 
        if(afmfile != &buffer[0])
1127
 
                mdvi_free(afmfile);
1128
 
        if(psfont != NULL) {
1129
 
                info = get_font_metrics(fontname, DviFontAFM, psfont);
1130
 
                mdvi_free(psfont);
1131
 
        } else
1132
 
                info = NULL;
1133
 
        if(info == NULL || (!map.extend && !map.slant))
1134
 
                return info;
1135
 
 
1136
 
        /* 
1137
 
         * transform the data as prescribed -- keep in mind that `info' 
1138
 
         * points to CACHED data, so we're modifying the metric cache 
1139
 
         * in place.
1140
 
         */
1141
 
 
1142
 
#define DROUND(x)       ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5))
1143
 
#define TRANSFORM(x,y)  DROUND(efactor * (x) + sfactor * (y))
1144
 
 
1145
 
        efactor = (double)map.extend / 10000.0;
1146
 
        sfactor = (double)map.slant / 10000.0;
1147
 
        DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n",
1148
 
                efactor, sfactor));
1149
 
 
1150
 
        nc = info->hic - info->loc + 1;
1151
 
        for(ch = info->chars; ch < info->chars + nc; ch++) {
1152
 
                /* the AFM bounding box is:
1153
 
                 *    wx = ch->advance
1154
 
                 *   llx = ch->left
1155
 
                 *   lly = -ch->depth
1156
 
                 *   urx = ch->right
1157
 
                 *   ury = ch->height
1158
 
                 * what we do here is transform wx, llx, and urx by
1159
 
                 *         newX = efactor * oldX + sfactor * oldY
1160
 
                 * where for `wx' oldY = 0. Also, these numbers are all in
1161
 
                 * TFM units (i.e. TFM's fix-words, which is just the actual
1162
 
                 * number times 2^20, no need to do anything to it).
1163
 
                 */
1164
 
                if(ch->present) {
1165
 
                        ch->advance = TRANSFORM(ch->advance, 0);
1166
 
                        ch->left    = TRANSFORM(ch->left, -ch->depth);
1167
 
                        ch->right   = TRANSFORM(ch->right, ch->height);
1168
 
                }
1169
 
        }
1170
 
        
1171
 
        return info;
1172
 
}