diff options
Diffstat (limited to 'dvi/mdvi-lib/fontmap.c')
-rw-r--r-- | dvi/mdvi-lib/fontmap.c | 1172 |
1 files changed, 0 insertions, 1172 deletions
diff --git a/dvi/mdvi-lib/fontmap.c b/dvi/mdvi-lib/fontmap.c deleted file mode 100644 index cc61064..0000000 --- a/dvi/mdvi-lib/fontmap.c +++ /dev/null @@ -1,1172 +0,0 @@ -/* encoding.c - functions to manipulate encodings and fontmaps */ -/* - * Copyright (C) 2000, Matias Atria - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <sys/stat.h> - -#include "mdvi.h" -#include "private.h" - -#include <kpathsea/expand.h> -#include <kpathsea/pathsearch.h> - -typedef struct _DviFontMap DviFontMap; - -struct _DviFontMap { - ListHead entries; - DviHashTable fonts; -}; - -typedef struct _PSFontMap { - struct _PSFontMap *next; - struct _PSFontMap *prev; - char *psname; - char *mapname; - char *fullname; -} PSFontMap; - -/* these variables control PS font maps */ -static char *pslibdir = NULL; /* path where we look for PS font maps */ -static char *psfontdir = NULL; /* PS font search path */ -static int psinitialized = 0; /* did we expand the path already? */ - -static ListHead psfonts = MDVI_EMPTY_LIST_HEAD; -static DviHashTable pstable = MDVI_EMPTY_HASH_TABLE; - -static ListHead fontmaps; -static DviHashTable maptable; -static int fontmaps_loaded = 0; - -#define MAP_HASH_SIZE 57 -#define ENC_HASH_SIZE 31 -#define PSMAP_HASH_SIZE 57 - -/* this hash table should be big enough to - * hold (ideally) one glyph name per bucket */ -#define ENCNAME_HASH_SIZE 131 /* most TeX fonts have 128 glyphs */ - -static ListHead encodings = MDVI_EMPTY_LIST_HEAD; -static DviEncoding *tex_text_encoding = NULL; -static DviEncoding *default_encoding = NULL; - -/* we keep two hash tables for encodings: one for their base files (e.g. - * "8r.enc"), and another one for their names (e.g. "TeXBase1Encoding") */ -static DviHashTable enctable = MDVI_EMPTY_HASH_TABLE; -static DviHashTable enctable_file = MDVI_EMPTY_HASH_TABLE; - -/* the TeX text encoding, from dvips */ -static char *tex_text_vector[256] = { - "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon", - "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle", - "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", - "acute", "caron", "breve", "macron", "ring", "cedilla", - "germandbls", "ae", "oe", "oslash", "AE", "OE", "Oslash", "space", - "exclam", "quotedbl", "numbersign", "dollar", "percent", - "ampersand", "quoteright", "parenleft", "parenright", "asterisk", - "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", - "three", "four", "five", "six", "seven", "eight", "nine", "colon", - "semicolon", "less", "equal", "greater", "question", "at", "A", "B", - "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", - "bracketleft", "backslash", "bracketright", "circumflex", - "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", - "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", - "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "tilde", - "dieresis", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static void ps_init_default_paths __PROTO((void)); -static int mdvi_set_default_encoding __PROTO((const char *name)); -static int mdvi_init_fontmaps __PROTO((void)); - -/* - * What we do here is allocate one block large enough to hold the entire - * file (these files are small) minus the leading comments. This is much - * better than allocating up to 256 tiny strings per encoding vector. */ -static int read_encoding(DviEncoding *enc) -{ - FILE *in; - int curr; - char *line; - char *name; - char *next; - struct stat st; - - ASSERT(enc->private == NULL); - - in = fopen(enc->filename, "r"); - if(in == NULL) { - DEBUG((DBG_FMAP, "%s: could not read `%s' (%s)\n", - enc->name, enc->filename, strerror(errno))); - return -1; - } - if(fstat(fileno(in), &st) < 0) { - /* should not happen */ - fclose(in); - return -1; - } - st.st_size -= enc->offset; - - /* this will be one big string */ - enc->private = (char *)malloc(st.st_size + 1); - /* setup the hash table */ - mdvi_hash_create(&enc->nametab, ENCNAME_HASH_SIZE); - /* setup the encoding vector */ - enc->vector = (char **)mdvi_malloc(256 * sizeof(char *)); - - /* jump to the beginning of the interesting part */ - fseek(in, enc->offset, SEEK_SET); - /* and read everything */ - if(fread(enc->private, st.st_size, 1, in) != 1) { - fclose(in); - mdvi_free(enc->private); - enc->private = NULL; - return -1; - } - /* we don't need this anymore */ - fclose(in); - curr = 0; - - next = name = NULL; - DEBUG((DBG_FMAP, "%s: reading encoding vector\n", enc->name)); - for(line = enc->private; *line && curr < 256; line = next) { - SKIPSP(line); - if(*line == ']') { - line++; SKIPSP(line); - if(STRNEQ(line, "def", 3)) - break; - } - name = getword(line, " \t\n", &next); - if(name == NULL) - break; - /* next > line */ - if(*name < ' ') - continue; - if(*name == '%') { - while(*next && *next != '\n') - next++; - if(*next) next++; /* skip \n */ - continue; - } - - /* got a name */ - if(*next) *next++ = 0; - - if(*name == '/') - name++; - enc->vector[curr] = name; - /* add it to the hash table */ - if(!STREQ(name, ".notdef")) { - mdvi_hash_add(&enc->nametab, MDVI_KEY(name), - Int2Ptr(curr + 1), MDVI_HASH_REPLACE); - } - curr++; - } - if(curr == 0) { - mdvi_hash_reset(&enc->nametab, 0); - mdvi_free(enc->private); - mdvi_free(enc); - return -1; - } - while(curr < 256) - enc->vector[curr++] = NULL; - return 0; -} - -static DviEncoding *find_encoding(const char *name) -{ - return (DviEncoding *)(encodings.count ? - mdvi_hash_lookup(&enctable, MDVI_KEY(name)) : NULL); -} - -static void destroy_encoding(DviEncoding *enc) -{ - if(enc == default_encoding) { - default_encoding = tex_text_encoding; - /* now we use reference counts again */ - mdvi_release_encoding(enc, 1); - } - if(enc != tex_text_encoding) { - mdvi_hash_reset(&enc->nametab, 0); - if(enc->private) { - mdvi_free(enc->private); - mdvi_free(enc->vector); - } - if(enc->name) - mdvi_free(enc->name); - if(enc->filename) - mdvi_free(enc->filename); - mdvi_free(enc); - } -} - -/* this is used for the `enctable_file' hash table */ -static void file_hash_free(DviHashKey key, void *data) -{ - mdvi_free(key); -} - -static DviEncoding *register_encoding(const char *basefile, int replace) -{ - DviEncoding *enc; - FILE *in; - char *filename; - char *name; - Dstring input; - char *line; - long offset; - - DEBUG((DBG_FMAP, "register_encoding(%s)\n", basefile)); - - if(encodings.count) { - enc = mdvi_hash_lookup(&enctable_file, MDVI_KEY(basefile)); - if(enc != NULL) { - DEBUG((DBG_FMAP, "%s: already there\n", basefile)); - return enc; /* no error */ - } - } - - /* try our own files first */ - filename = kpse_find_file(basefile, - kpse_program_text_format, 0); - - /* then try the system-wide ones */ - if(filename == NULL) - filename = kpse_find_file(basefile, - kpse_tex_ps_header_format, 0); - if(filename == NULL) - filename = kpse_find_file(basefile, - kpse_dvips_config_format, 0); - - /* finally try the given name */ - if(filename == NULL) - filename = mdvi_strdup(basefile); - - in = fopen(filename, "r"); - if(in == NULL) { - mdvi_free(filename); - return NULL; - } - - /* just lookup the name of the encoding */ - name = NULL; - dstring_init(&input); - while((line = dgets(&input, in)) != NULL) { - if(STRNEQ(line, "Encoding=", 9)) { - name = getword(line + 9, " \t", &line); - if(*line) *line++ = 0; - break; - } else if(*line == '/') { - char *label = getword(line + 1, " \t", &line); - if(*line) { - *line++ = 0; - SKIPSP(line); - if(*line == '[') { - *line = 0; - name = label; - break; - } - } - } - } - offset = ftell(in); - fclose(in); - if(name == NULL || *name == 0) { - DEBUG((DBG_FMAP, - "%s: could not determine name of encoding\n", - basefile)); - mdvi_free(filename); - return NULL; - } - - /* check if the encoding is already there */ - enc = find_encoding(name); - if(enc == tex_text_encoding) { - /* A special case: if the vector we found is the static one, - * allow the user to override it with an external file */ - listh_remove(&encodings, LIST(enc)); - mdvi_hash_remove(&enctable, MDVI_KEY(enc->name)); - if(enc == default_encoding) - default_encoding = NULL; - } else if(enc) { - /* if the encoding is being used, refuse to remove it */ - if(enc->links) { - mdvi_free(filename); - dstring_reset(&input); - return NULL; - } - if(replace) { - mdvi_hash_remove(&enctable, MDVI_KEY(name)); - mdvi_hash_remove(&enctable_file, MDVI_KEY(basefile)); - listh_remove(&encodings, LIST(enc)); - if(enc == default_encoding) { - default_encoding = NULL; - mdvi_release_encoding(enc, 1); - } - DEBUG((DBG_FMAP, "%s: overriding encoding\n", name)); - destroy_encoding(enc); - } else { - mdvi_free(filename); - dstring_reset(&input); - return enc; /* no error */ - } - } - enc = xalloc(DviEncoding); - enc->name = mdvi_strdup(name); - enc->filename = filename; - enc->links = 0; - enc->offset = offset; - enc->private = NULL; - enc->vector = NULL; - mdvi_hash_init(&enc->nametab); - dstring_reset(&input); - if(default_encoding == NULL) - default_encoding = enc; - mdvi_hash_add(&enctable, MDVI_KEY(enc->name), - enc, MDVI_HASH_UNCHECKED); - mdvi_hash_add(&enctable_file, MDVI_KEY(mdvi_strdup(basefile)), - enc, MDVI_HASH_REPLACE); - listh_prepend(&encodings, LIST(enc)); - DEBUG((DBG_FMAP, "%s: encoding `%s' registered\n", - basefile, enc->name)); - return enc; -} - -DviEncoding *mdvi_request_encoding(const char *name) -{ - DviEncoding *enc = find_encoding(name); - - if(enc == NULL) { - DEBUG((DBG_FMAP, "%s: encoding not found, returning default `%s'\n", - name, default_encoding->name)); - return default_encoding; - } - /* we don't keep reference counts for this */ - if(enc == tex_text_encoding) - return enc; - if(!enc->private && read_encoding(enc) < 0) - return NULL; - enc->links++; - - /* if the hash table is empty, rebuild it */ - if(enc->nametab.nkeys == 0) { - int i; - - DEBUG((DBG_FMAP, "%s: rehashing\n", enc->name)); - for(i = 0; i < 256; i++) { - if(enc->vector[i] == NULL) - continue; - mdvi_hash_add(&enc->nametab, - MDVI_KEY(enc->vector[i]), - (DviHashKey)Int2Ptr(i), - MDVI_HASH_REPLACE); - } - } - return enc; -} - -void mdvi_release_encoding(DviEncoding *enc, int should_free) -{ - /* ignore our static encoding */ - if(enc == tex_text_encoding) - return; - if(!enc->links || --enc->links > 0 || !should_free) - return; - DEBUG((DBG_FMAP, "%s: resetting encoding vector\n", enc->name)); - mdvi_hash_reset(&enc->nametab, 1); /* we'll reuse it */ -} - -int mdvi_encode_glyph(DviEncoding *enc, const char *name) -{ - void *data; - - data = mdvi_hash_lookup(&enc->nametab, MDVI_KEY(name)); - if(data == NULL) - return -1; - /* we added +1 to the hashed index just to distinguish - * a failed lookup from a zero index. Adjust it now. */ - return (Ptr2Int(data) - 1); -} - -/**************** - * Fontmaps * - ****************/ - -static void parse_spec(DviFontMapEnt *ent, char *spec) -{ - char *arg, *command; - - /* this is a ridiculously simple parser, and recognizes only - * things of the form <argument> <command>. Of these, only - * command=SlantFont, ExtendFont and ReEncodeFont are handled */ - while(*spec) { - arg = getword(spec, " \t", &spec); - if(*spec) *spec++ = 0; - command = getword(spec, " \t", &spec); - if(*spec) *spec++ = 0; - if(!arg || !command) - continue; - if(STREQ(command, "SlantFont")) { - double x = 10000 * strtod(arg, 0); - - /* SFROUND evaluates arguments twice */ - ent->slant = SFROUND(x); - } else if(STREQ(command, "ExtendFont")) { - double x = 10000 * strtod(arg, 0); - - ent->extend = SFROUND(x); - } else if(STREQ(command, "ReEncodeFont")) { - if(ent->encoding) - mdvi_free(ent->encoding); - ent->encoding = mdvi_strdup(arg); - } - } -} - -#if 0 -static void print_ent(DviFontMapEnt *ent) -{ - printf("Entry for `%s':\n", ent->fontname); - printf(" PS name: %s\n", ent->psname ? ent->psname : "(none)"); - printf(" Encoding: %s\n", ent->encoding ? ent->encoding : "(default)"); - printf(" EncFile: %s\n", ent->encfile ? ent->encfile : "(none)"); - printf(" FontFile: %s\n", ent->fontfile ? ent->fontfile : "(same)"); - printf(" Extend: %ld\n", ent->extend); - printf(" Slant: %ld\n", ent->slant); -} -#endif - -DviFontMapEnt *mdvi_load_fontmap(const char *file) -{ - char *ptr; - FILE *in; - int lineno = 1; - Dstring input; - ListHead list; - DviFontMapEnt *ent; - DviEncoding *last_encoding; - char *last_encfile; - - ptr = kpse_find_file(file, kpse_program_text_format, 0); - if(ptr == NULL) - ptr = kpse_find_file(file, kpse_tex_ps_header_format, 0); - if(ptr == NULL) - ptr = kpse_find_file(file, kpse_dvips_config_format, 0); - if(ptr == NULL) - in = fopen(file, "r"); - else { - in = fopen(ptr, "r"); - mdvi_free(ptr); - } - if(in == NULL) - return NULL; - - ent = NULL; - listh_init(&list); - dstring_init(&input); - last_encoding = NULL; - last_encfile = NULL; - - while((ptr = dgets(&input, in)) != NULL) { - char *font_file; - char *tex_name; - char *ps_name; - char *vec_name; - int is_encoding; - DviEncoding *enc; - - lineno++; - SKIPSP(ptr); - - /* we skip what dvips does */ - if(*ptr <= ' ' || *ptr == '*' || *ptr == '#' || - *ptr == ';' || *ptr == '%') - continue; - - font_file = NULL; - tex_name = NULL; - ps_name = NULL; - vec_name = NULL; - is_encoding = 0; - - if(ent == NULL) { - ent = xalloc(DviFontMapEnt); - ent->encoding = NULL; - ent->slant = 0; - ent->extend = 0; - } - while(*ptr) { - char *hdr_name = NULL; - - while(*ptr && *ptr <= ' ') - ptr++; - if(*ptr == 0) - break; - if(*ptr == '"') { - char *str; - - str = getstring(ptr, " \t", &ptr); - if(*ptr) *ptr++ = 0; - parse_spec(ent, str); - continue; - } else if(*ptr == '<') { - ptr++; - if(*ptr == '<') - ptr++; - else if(*ptr == '[') { - is_encoding = 1; - ptr++; - } - SKIPSP(ptr); - hdr_name = ptr; - } else if(!tex_name) - tex_name = ptr; - else if(!ps_name) - ps_name = ptr; - else - hdr_name = ptr; - - /* get next word */ - getword(ptr, " \t", &ptr); - if(*ptr) *ptr++ = 0; - - if(hdr_name) { - const char *ext = file_extension(hdr_name); - - if(is_encoding || (ext && STRCEQ(ext, "enc"))) - vec_name = hdr_name; - else - font_file = hdr_name; - } - } - - if(tex_name == NULL) - continue; - ent->fontname = mdvi_strdup(tex_name); - ent->psname = ps_name ? mdvi_strdup(ps_name) : NULL; - ent->fontfile = font_file ? mdvi_strdup(font_file) : NULL; - ent->encfile = vec_name ? mdvi_strdup(vec_name) : NULL; - ent->fullfile = NULL; - enc = NULL; /* we don't have this yet */ - - /* if we have an encoding file, register it */ - if(ent->encfile) { - /* register_encoding is smart enough not to load the - * same file twice */ - if(!last_encfile || !STREQ(last_encfile, ent->encfile)) { - last_encfile = ent->encfile; - last_encoding = register_encoding(ent->encfile, 1); - } - enc = last_encoding; - } - if(ent->encfile && enc){ - if(ent->encoding && !STREQ(ent->encoding, enc->name)) { - warning( - _("%s: %d: [%s] requested encoding `%s' does not match vector `%s'\n"), - file, lineno); - } else if(!ent->encoding) - ent->encoding = mdvi_strdup(enc->name); - } - - /* add it to the list */ - /*print_ent(ent);*/ - listh_append(&list, LIST(ent)); - ent = NULL; - } - dstring_reset(&input); - fclose(in); - - return (DviFontMapEnt *)list.head; -} - -static void free_ent(DviFontMapEnt *ent) -{ - ASSERT(ent->fontname != NULL); - mdvi_free(ent->fontname); - if(ent->psname) - mdvi_free(ent->psname); - if(ent->fontfile) - mdvi_free(ent->fontfile); - if(ent->encoding) - mdvi_free(ent->encoding); - if(ent->encfile) - mdvi_free(ent->encfile); - if(ent->fullfile) - mdvi_free(ent->fullfile); - mdvi_free(ent); -} - -void mdvi_install_fontmap(DviFontMapEnt *head) -{ - DviFontMapEnt *ent, *next; - - for(ent = head; ent; ent = next) { - /* add all the entries, overriding old ones */ - DviFontMapEnt *old; - - old = (DviFontMapEnt *) - mdvi_hash_remove(&maptable, MDVI_KEY(ent->fontname)); - if(old != NULL) { - DEBUG((DBG_FMAP, "%s: overriding fontmap entry\n", - old->fontname)); - listh_remove(&fontmaps, LIST(old)); - free_ent(old); - } - next = ent->next; - mdvi_hash_add(&maptable, MDVI_KEY(ent->fontname), - ent, MDVI_HASH_UNCHECKED); - listh_append(&fontmaps, LIST(ent)); - } -} - -static void init_static_encoding() -{ - DviEncoding *encoding; - int i; - - DEBUG((DBG_FMAP, "installing static TeX text encoding\n")); - encoding = xalloc(DviEncoding); - encoding->private = ""; - encoding->filename = ""; - encoding->name = "TeXTextEncoding"; - encoding->vector = tex_text_vector; - encoding->links = 1; - encoding->offset = 0; - mdvi_hash_create(&encoding->nametab, ENCNAME_HASH_SIZE); - for(i = 0; i < 256; i++) { - if(encoding->vector[i]) { - mdvi_hash_add(&encoding->nametab, - MDVI_KEY(encoding->vector[i]), - (DviHashKey)Int2Ptr(i), - MDVI_HASH_UNCHECKED); - } - } - ASSERT_VALUE(encodings.count, 0); - mdvi_hash_create(&enctable, ENC_HASH_SIZE); - mdvi_hash_create(&enctable_file, ENC_HASH_SIZE); - enctable_file.hash_free = file_hash_free; - mdvi_hash_add(&enctable, MDVI_KEY(encoding->name), - encoding, MDVI_HASH_UNCHECKED); - listh_prepend(&encodings, LIST(encoding)); - tex_text_encoding = encoding; - default_encoding = tex_text_encoding; -} - -static int mdvi_set_default_encoding(const char *name) -{ - DviEncoding *enc, *old; - - enc = find_encoding(name); - if(enc == NULL) - return -1; - if(enc == default_encoding) - return 0; - /* this will read it from file if necessary, - * but it can fail if the file is corrupted */ - enc = mdvi_request_encoding(name); - if(enc == NULL) - return -1; - old = default_encoding; - default_encoding = enc; - if(old != tex_text_encoding) - mdvi_release_encoding(old, 1); - return 0; -} - -static int mdvi_init_fontmaps(void) -{ - char *file; - char *line; - FILE *in; - Dstring input; - int count = 0; - char *config; - - if(fontmaps_loaded) - return 0; - /* we will only try this once */ - fontmaps_loaded = 1; - - DEBUG((DBG_FMAP, "reading fontmaps\n")); - - /* make sure the static encoding is there */ - init_static_encoding(); - - /* create the fontmap hash table */ - mdvi_hash_create(&maptable, MAP_HASH_SIZE); - - /* get the name of our configuration file */ - config = kpse_cnf_get("mdvi-config"); - if(config == NULL) - config = MDVI_DEFAULT_CONFIG; - /* let's ask kpathsea for the file first */ - file = kpse_find_file(config, kpse_program_text_format, 0); - if(file == NULL) - in = fopen(config, "r"); - else { - in = fopen(file, "r"); - mdvi_free(file); - } - if(in == NULL) - return -1; - dstring_init(&input); - while((line = dgets(&input, in)) != NULL) { - char *arg; - - SKIPSP(line); - if(*line < ' ' || *line == '#' || *line == '%') - continue; - if(STRNEQ(line, "fontmap", 7)) { - DviFontMapEnt *ent; - - arg = getstring(line + 7, " \t", &line); *line = 0; - DEBUG((DBG_FMAP, "%s: loading fontmap\n", arg)); - ent = mdvi_load_fontmap(arg); - if(ent == NULL) - warning(_("%s: could not load fontmap\n"), arg); - else { - DEBUG((DBG_FMAP, - "%s: installing fontmap\n", arg)); - mdvi_install_fontmap(ent); - count++; - } - } else if(STRNEQ(line, "encoding", 8)) { - arg = getstring(line + 8, " \t", &line); *line = 0; - if(arg && *arg) - register_encoding(arg, 1); - } else if(STRNEQ(line, "default-encoding", 16)) { - arg = getstring(line + 16, " \t", &line); *line = 0; - if(mdvi_set_default_encoding(arg) < 0) - warning(_("%s: could not set as default encoding\n"), - arg); - } else if(STRNEQ(line, "psfontpath", 10)) { - arg = getstring(line + 11, " \t", &line); *line = 0; - if(!psinitialized) - ps_init_default_paths(); - if(psfontdir) - mdvi_free(psfontdir); - psfontdir = kpse_path_expand(arg); - } else if(STRNEQ(line, "pslibpath", 9)) { - arg = getstring(line + 10, " \t", &line); *line = 0; - if(!psinitialized) - ps_init_default_paths(); - if(pslibdir) - mdvi_free(pslibdir); - pslibdir = kpse_path_expand(arg); - } else if(STRNEQ(line, "psfontmap", 9)) { - arg = getstring(line + 9, " \t", &line); *line = 0; - if(mdvi_ps_read_fontmap(arg) < 0) - warning("%s: %s: could not read PS fontmap\n", - config, arg); - } - } - fclose(in); - dstring_reset(&input); - fontmaps_loaded = 1; - DEBUG((DBG_FMAP, "%d files installed, %d fontmaps\n", - count, fontmaps.count)); - return count; -} - -int mdvi_query_fontmap(DviFontMapInfo *info, const char *fontname) -{ - DviFontMapEnt *ent; - - if(!fontmaps_loaded && mdvi_init_fontmaps() < 0) - return -1; - ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(fontname)); - - if(ent == NULL) - return -1; - info->psname = ent->psname; - info->encoding = ent->encoding; - info->fontfile = ent->fontfile; - info->extend = ent->extend; - info->slant = ent->slant; - info->fullfile = ent->fullfile; - - return 0; -} - -int mdvi_add_fontmap_file(const char *name, const char *fullpath) -{ - DviFontMapEnt *ent; - - if(!fontmaps_loaded && mdvi_init_fontmaps() < 0) - return -1; - ent = (DviFontMapEnt *)mdvi_hash_lookup(&maptable, MDVI_KEY(name)); - if(ent == NULL) - return -1; - if(ent->fullfile) - mdvi_free(ent->fullfile); - ent->fullfile = mdvi_strdup(fullpath); - return 0; -} - - -void mdvi_flush_encodings(void) -{ - DviEncoding *enc; - - if(enctable.nbucks == 0) - return; - - DEBUG((DBG_FMAP, "flushing %d encodings\n", encodings.count)); - /* asked to remove all encodings */ - for(; (enc = (DviEncoding *)encodings.head); ) { - encodings.head = LIST(enc->next); - if((enc != tex_text_encoding && enc->links) || enc->links > 1) { - warning(_("encoding vector `%s' is in use\n"), - enc->name); - } - destroy_encoding(enc); - } - /* destroy the static encoding */ - if(tex_text_encoding->nametab.buckets) - mdvi_hash_reset(&tex_text_encoding->nametab, 0); - mdvi_hash_reset(&enctable, 0); - mdvi_hash_reset(&enctable_file, 0); -} - -void mdvi_flush_fontmaps(void) -{ - DviFontMapEnt *ent; - - if(!fontmaps_loaded) - return; - - DEBUG((DBG_FMAP, "flushing %d fontmaps\n", fontmaps.count)); - for(; (ent = (DviFontMapEnt *)fontmaps.head); ) { - fontmaps.head = LIST(ent->next); - free_ent(ent); - } - mdvi_hash_reset(&maptable, 0); - fontmaps_loaded = 0; -} - -/* reading of PS fontmaps */ - -void ps_init_default_paths(void) -{ - char *kppath; - char *kfpath; - - ASSERT(psinitialized == 0); - - kppath = getenv("GS_LIB"); - kfpath = getenv("GS_FONTPATH"); - - if(kppath != NULL) - pslibdir = kpse_path_expand(kppath); - if(kfpath != NULL) - psfontdir = kpse_path_expand(kfpath); - - listh_init(&psfonts); - mdvi_hash_create(&pstable, PSMAP_HASH_SIZE); - psinitialized = 1; -} - -int mdvi_ps_read_fontmap(const char *name) -{ - char *fullname; - FILE *in; - Dstring dstr; - char *line; - int count = 0; - - if(!psinitialized) - ps_init_default_paths(); - if(pslibdir) - fullname = kpse_path_search(pslibdir, name, 1); - else - fullname = (char *)name; - in = fopen(fullname, "r"); - if(in == NULL) { - if(fullname != name) - mdvi_free(fullname); - return -1; - } - dstring_init(&dstr); - - while((line = dgets(&dstr, in)) != NULL) { - char *name; - char *mapname; - const char *ext; - PSFontMap *ps; - - SKIPSP(line); - /* we're looking for lines of the form - * /FONT-NAME (fontfile) - * /FONT-NAME /FONT-ALIAS - */ - if(*line != '/') - continue; - name = getword(line + 1, " \t", &line); - if(*line) *line++ = 0; - mapname = getword(line, " \t", &line); - if(*line) *line++ = 0; - - if(!name || !mapname || !*name) - continue; - if(*mapname == '(') { - char *end; - - mapname++; - for(end = mapname; *end && *end != ')'; end++); - *end = 0; - } - if(!*mapname) - continue; - /* dont add `.gsf' fonts, which require a full blown - * PostScript interpreter */ - ext = file_extension(mapname); - if(ext && STREQ(ext, "gsf")) { - DEBUG((DBG_FMAP, "(ps) %s: font `%s' ignored\n", - name, mapname)); - continue; - } - ps = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(name)); - if(ps != NULL) { - if(STREQ(ps->mapname, mapname)) - continue; - DEBUG((DBG_FMAP, - "(ps) replacing font `%s' (%s) by `%s'\n", - name, ps->mapname, mapname)); - mdvi_free(ps->mapname); - ps->mapname = mdvi_strdup(mapname); - if(ps->fullname) { - mdvi_free(ps->fullname); - ps->fullname = NULL; - } - } else { - DEBUG((DBG_FMAP, "(ps) adding font `%s' as `%s'\n", - name, mapname)); - ps = xalloc(PSFontMap); - ps->psname = mdvi_strdup(name); - ps->mapname = mdvi_strdup(mapname); - ps->fullname = NULL; - listh_append(&psfonts, LIST(ps)); - mdvi_hash_add(&pstable, MDVI_KEY(ps->psname), - ps, MDVI_HASH_UNCHECKED); - count++; - } - } - fclose(in); - dstring_reset(&dstr); - - DEBUG((DBG_FMAP, "(ps) %s: %d PostScript fonts registered\n", - fullname, count)); - return 0; -} - -void mdvi_ps_flush_fonts(void) -{ - PSFontMap *map; - - if(!psinitialized) - return; - DEBUG((DBG_FMAP, "(ps) flushing PS font map (%d) entries\n", - psfonts.count)); - mdvi_hash_reset(&pstable, 0); - for(; (map = (PSFontMap *)psfonts.head); ) { - psfonts.head = LIST(map->next); - mdvi_free(map->psname); - mdvi_free(map->mapname); - if(map->fullname) - mdvi_free(map->fullname); - mdvi_free(map); - } - listh_init(&psfonts); - if(pslibdir) { - mdvi_free(pslibdir); - pslibdir = NULL; - } - if(psfontdir) { - mdvi_free(psfontdir); - psfontdir = NULL; - } - psinitialized = 0; -} - -char *mdvi_ps_find_font(const char *psname) -{ - PSFontMap *map, *smap; - char *filename; - int recursion_limit = 32; - - DEBUG((DBG_FMAP, "(ps) resolving PS font `%s'\n", psname)); - if(!psinitialized) - return NULL; - map = (PSFontMap *)mdvi_hash_lookup(&pstable, MDVI_KEY(psname)); - if(map == NULL) - return NULL; - if(map->fullname) - return mdvi_strdup(map->fullname); - - /* is it an alias? */ - smap = map; - while(recursion_limit-- > 0 && smap && *smap->mapname == '/') - smap = (PSFontMap *)mdvi_hash_lookup(&pstable, - MDVI_KEY(smap->mapname + 1)); - if(smap == NULL) { - if(recursion_limit == 0) - DEBUG((DBG_FMAP, - "(ps) %s: possible loop in PS font map\n", - psname)); - return NULL; - } - - if(psfontdir) - filename = kpse_path_search(psfontdir, smap->mapname, 1); - else if(file_exists(map->mapname)) - filename = mdvi_strdup(map->mapname); - else - filename = NULL; - if(filename) - map->fullname = mdvi_strdup(filename); - - return filename; -} - -/* - * To get metric info for a font, we proceed as follows: - * - We try to find NAME.<tfm,ofm,afm>. - * - We query the fontmap for NAME. - * - We get back a PSNAME, and use to find the file in the PS font map. - * - We get the PSFONT file name, replace its extension by "afm" and - * lookup the file in GS's font search path. - * - We finally read the data, transform it as specified in our font map, - * and return it to the caller. The new data is left in the font metrics - * cache, so the next time it will be found at the first step (when we look - * up NAME.afm). - * - * The name `_ps_' in this function is not meant to imply that it can be - * used for Type1 fonts only. It should be usable for TrueType fonts as well. - * - * The returned metric info is subjected to the same caching mechanism as - * all the other metric data, as returned by get_font_metrics(). One should - * not modify the returned data at all, and it should be disposed with - * free_font_metrics(). - */ -TFMInfo *mdvi_ps_get_metrics(const char *fontname) -{ - TFMInfo *info; - DviFontMapInfo map; - char buffer[64]; /* to avoid mallocs */ - char *psfont; - char *basefile; - char *afmfile; - char *ext; - int baselen; - int nc; - TFMChar *ch; - double efactor; - double sfactor; - - DEBUG((DBG_FMAP, "(ps) %s: looking for metric data\n", fontname)); - info = get_font_metrics(fontname, DviFontAny, NULL); - if(info != NULL) - return info; - - /* query the fontmap */ - if(mdvi_query_fontmap(&map, fontname) < 0 || !map.psname) - return NULL; - - /* get the PS font */ - psfont = mdvi_ps_find_font(map.psname); - if(psfont == NULL) - return NULL; - DEBUG((DBG_FMAP, "(ps) %s: found as PS font `%s'\n", - fontname, psfont)); - /* replace its extension */ - basefile = strrchr(psfont, '/'); - if(basefile == NULL) - basefile = psfont; - baselen = strlen(basefile); - ext = strrchr(basefile, '.'); - if(ext != NULL) - *ext = 0; - if(baselen + 4 < 64) - afmfile = &buffer[0]; - else - afmfile = mdvi_malloc(baselen + 5); - strcpy(afmfile, basefile); - strcpy(afmfile + baselen, ".afm"); - /* we don't need this anymore */ - mdvi_free(psfont); - DEBUG((DBG_FMAP, "(ps) %s: looking for `%s'\n", - fontname, afmfile)); - /* lookup the file */ - psfont = kpse_path_search(psfontdir, afmfile, 1); - /* don't need this anymore */ - if(afmfile != &buffer[0]) - mdvi_free(afmfile); - if(psfont != NULL) { - info = get_font_metrics(fontname, DviFontAFM, psfont); - mdvi_free(psfont); - } else - info = NULL; - if(info == NULL || (!map.extend && !map.slant)) - return info; - - /* - * transform the data as prescribed -- keep in mind that `info' - * points to CACHED data, so we're modifying the metric cache - * in place. - */ - -#define DROUND(x) ((x) >= 0 ? floor((x) + 0.5) : ceil((x) - 0.5)) -#define TRANSFORM(x,y) DROUND(efactor * (x) + sfactor * (y)) - - efactor = (double)map.extend / 10000.0; - sfactor = (double)map.slant / 10000.0; - DEBUG((DBG_FMAP, "(ps) %s: applying extend=%f, slant=%f\n", - efactor, sfactor)); - - nc = info->hic - info->loc + 1; - for(ch = info->chars; ch < info->chars + nc; ch++) { - /* the AFM bounding box is: - * wx = ch->advance - * llx = ch->left - * lly = -ch->depth - * urx = ch->right - * ury = ch->height - * what we do here is transform wx, llx, and urx by - * newX = efactor * oldX + sfactor * oldY - * where for `wx' oldY = 0. Also, these numbers are all in - * TFM units (i.e. TFM's fix-words, which is just the actual - * number times 2^20, no need to do anything to it). - */ - if(ch->present) { - ch->advance = TRANSFORM(ch->advance, 0); - ch->left = TRANSFORM(ch->left, -ch->depth); - ch->right = TRANSFORM(ch->right, ch->height); - } - } - - return info; -} |