diff options
Diffstat (limited to 'Build/source/texk/xdvik/font-open.c')
-rw-r--r-- | Build/source/texk/xdvik/font-open.c | 1463 |
1 files changed, 1421 insertions, 42 deletions
diff --git a/Build/source/texk/xdvik/font-open.c b/Build/source/texk/xdvik/font-open.c index ac5a1476766..d0a3cef062f 100644 --- a/Build/source/texk/xdvik/font-open.c +++ b/Build/source/texk/xdvik/font-open.c @@ -1,8 +1,8 @@ /* - font_open.c: find font filenames. This bears no relation (but the - interface) to the original font_open.c. + font-open.c: find font files. The routine font_open() itself bears + no relation (except for the interface) to the original font_open(). - Copyright (c) 1999-2004 The texk project + Copyright (c) 1999-2013 The texk project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -34,6 +34,7 @@ #include "print-log.h" #include "statusline.h" +#include "message-window.h" #include "font-open.h" #include "kpathsea/c-fopen.h" @@ -87,6 +88,1395 @@ # define XIO_OUT 2 #endif /* HAVE_POLL */ + + /* see just above the second init_t1_lookup for why this was chosen */ +#define DVIPS_SETUP 1 + +#if FREETYPE || PS + +/* + * The following code handles lookup of Type 1 fonts for use as FreeType + * fonts, and for use within MetaPost output. + * The system psfonts.map file is read into an AVL tree as needed (lazy + * evaluation), and searched for Type 1 fonts. + */ + +struct p_list { /* list of map file names */ + struct p_list *next; + const char *value; +}; + + /* Initialize this list to "psfonts.map". */ + +static struct p_list psfonts_map = {NULL, "psfonts.map"}; + +static struct p_list *p_head = &psfonts_map; +static struct p_list **p_tail = &psfonts_map.next; + +static FILE *mapfile = NULL; + +static char *ffline = NULL; /* an array used to store */ + /* the file name being formed. */ + /* It expands as needed. */ + /* Also used elsewhere. */ +static size_t ffline_len = 0; /* current length of ffline[] */ + +/* + * Expand ffline[] to at least the given size. + */ + +static void +expandline(int n) +{ + int newlen = n + 128; + + ffline = (ffline == NULL) ? xmalloc(newlen) : xrealloc(ffline, newlen); + ffline_len = newlen; +} + + +/* + * Like fgets(), but read an arbitrarily long line into ffline[]. + */ + +static Boolean +fgets_long(FILE *f) +{ + int len; + + if (fgets(ffline, ffline_len, f) == NULL) + return False; + + len = 0; + for (;;) { + len += strlen(ffline + len); + if (len > 0 && ffline[len - 1] == '\n') { + ffline[--len] = '\0'; + break; + } + if (len < ffline_len - 1) + break; + expandline(len); + fgets(ffline + len, ffline_len - len, f); + } + + return True; +} + +# if DVIPS_SETUP + +/* + * Get list of map files from dvips config file(s). + */ + +static void +getdefaults(FILE *f) +{ + char *p, *q; + int len; + struct p_list *p_node; + + while (fgets_long(f)) { + p = ffline; + while (*p == ' ' || *p == '\t') ++p; + if (*p == 'p') { + do ++p; + while (*p == ' ' || *p == '\t'); + + if (*p == '+') + do ++p; + while (*p == ' ' || *p == '\t'); + else { /* discard old list */ + struct p_list *pl, *pl2; + + *p_tail = NULL; + pl = p_head; + if (pl == &psfonts_map) pl = pl->next; + while (pl != NULL) { + free((char *) pl->value); + pl2 = pl->next; + free(pl); + pl = pl2; + } + p_tail = &p_head; + } + + /* get white-delimited argument */ + len = strlen(p); + q = memchr(p, ' ', len); + if (q != NULL) len = q - p; + q = memchr(p, '\t', len); + if (q != NULL) len = q - p; + p[len] = '\0'; + + p_node = xmalloc(sizeof *p_node); + p_node->value = xmemdup(p, len + 1); + *p_tail = p_node; + p_tail = &p_node->next; + } + } + + fclose(f); +} + +# endif /* DVIPS_SETUP */ + +/* + * Open the next (available) map file. + */ + +static Boolean +open_next_mapfile(void) +{ + char *filename; + + /* + * Look for the first (openable) map file. Others will be read later + * as needed. + */ + + while (p_head != NULL) { + filename = kpse_find_file(p_head->value, kpse_program_text_format, + True); + if (filename == NULL) + filename = kpse_find_file(p_head->value, kpse_fontmap_format, + True); + if (filename == NULL) { + XDVI_WARNING((stderr, + "could not find dvips map file %s; skipping\n", + p_head->value)); + } + else { + mapfile = XFOPEN(filename, OPEN_MODE); + if (mapfile == NULL) { + XDVI_WARNING((stderr, + "could not open dvips map file %s: %s\n", + filename, strerror(errno))); + free(filename); + } + else { + TRACE_FT((stderr, "Map file: %s\n", filename)); + free(filename); + return True; + } + } + p_head = p_head->next; + } + + return False; +} + + +/* + * Initialize these lookup routines. + */ + +# if DVIPS_SETUP + +Boolean +init_t1_lookup(void) +{ + char *filename; + struct stat statbuf; + FILE *f; + char *dvipsrc; + + if (ffline == NULL) expandline(80); + + filename = find_file("config.ps", &statbuf, kpse_dvips_config_format); + if (filename == NULL) { + TRACE_FT((stderr, "could not find file config.ps; skipping")); + } + else { + f = XFOPEN(filename, OPEN_MODE); + if (f == NULL) { + TRACE_FT((stderr, "could not open file %s: %s", + filename, strerror(errno))); + } + else + getdefaults(f); + free(filename); + } + + dvipsrc = getenv("DVIPSRC"); + if (dvipsrc == NULL) { + dvipsrc = getenv("HOME"); + if (dvipsrc != NULL) { + size_t n; + + n = strlen(dvipsrc); + if (n + 10 > ffline_len) expandline(n + 10); + memcpy(ffline, dvipsrc, n); + memcpy(ffline + n, "/.dvipsrc", 10); + dvipsrc = ffline; + } + } + if (dvipsrc != NULL) { + f = XFOPEN(dvipsrc, OPEN_MODE); + if (f == NULL) { + TRACE_FT((stderr, + "could not open dvipsrc file %s: %s; skipping", + dvipsrc, strerror(errno))); + } + else + getdefaults(f); + } + + filename = find_file("config.xdvi", &statbuf, kpse_dvips_config_format); + if (filename == NULL) { + TRACE_FT((stderr, "could not find file config.xdvi; skipping")); + } + else { + f = XFOPEN(filename, OPEN_MODE); + if (f == NULL) { + TRACE_FT((stderr, "could not open file %s: %s", + filename, strerror(errno))); + } + else + getdefaults(f); + free(filename); + } + + *p_tail = NULL; + + return open_next_mapfile(); +} + +# else /* !DVIPS_SETUP */ + +/* + * Under the earlier regime, T1 lookup was controlled by xdvi.cfg. + * + * This has been disabled, for the following reasons. + * + * It only supported "enc" and "dvipsmap" directives. + * + * The "enc" directives selected implicit encoding files for fonts ending + * in certain character strings (8r, 8c, 8y), unless the map file + * explicitly referenced a .enc file. However, among the dvips map files + * supplied with TeX Live 2012 (at least) there were no such fonts ending + * in 8r and 8y, and the encoding file for the 8c fonts was cork.enc, + * which is no longer included in TeX Live. + * + * As for the dvipsmap directives, it seemed better to use the dvips + * configuration method. + */ + +Boolean +init_t1_lookup(void) +{ + char *filename; + FILE *fp; + char *keyword; + char *ptr; + struct p_list *p_node; + char *enc; + char *name; + static const char delim[] = "\t \n\r"; + + if (ffline == NULL) expandline(80); + + filename = kpse_find_file("xdvi.cfg", kpse_program_text_format, 1); + if (filename == NULL) { + statusline_error(STATUS_MEDIUM, + "Warning: Unable to find \"xdvi.cfg\"!"); + return open_next_mapfile(); + } + + if ((fp = XFOPEN(filename, "r")) == NULL) { + XDVI_ERROR((stderr, "Cannot open config file `%s' for reading: %s", + filename, strerror(errno))); + free(filename); + return open_next_mapfile(); + } + + TRACE_FT((stderr, "Reading cfg file %s", filename)); + + while (fgets_long(fp)) { + keyword = ffline; + + /* Skip leading whitespace */ + while (*keyword == ' ' || *keyword == '\t') + keyword++; + + /* % in first column is a correct comment */ + if (*keyword == '%' || *keyword == '\0' || *keyword == '\n') + continue; + + keyword = strtok(keyword, delim); + + if (strcmp(keyword, "dvipsmap") == 0) { + if ((ptr = strtok(NULL, delim)) == NULL) { + XDVI_WARNING((stderr, "Syntax error in entry \"%s\"", + ffline)); + continue; + } + TRACE_FT((stderr, "DVIPSMAP: '%s'", ptr)); + + /* Add it to the list for later reading */ + p_node = xmalloc(sizeof *p_node); + p_node->value = xmemdup(ptr, strlen(ptr) + 1); + /* If we're still pointing to the default list, remove it */ + if (p_tail == &psfonts_map.next) + p_tail = &p_head; + *p_tail = p_node; + p_tail = &p_node->next; + } + else if (strcmp(keyword, "encmap") == 0) { + popup_message(globals.widgets.top_level, + MSG_ERR, + "Your xdvi.cfg file is for a previous version " + "of xdvik. Please replace it with the xdvi.cfg file " + "in the current xdvik distribution.", + "The keyword \"encmap\" in xdvi.cfg is no longer " + "supported. Please update the config file %s.", + filename); + } + else if (strcmp(keyword, "enc") == 0) { + enc = strtok(NULL, delim); + name = strtok(NULL, delim); + if ((ptr = strtok(NULL, delim)) == NULL) { + XDVI_WARNING((stderr, + "Syntax error in entry \"%s\" (skipping line)", + ffline)); + continue; + } +# if 0 + i = new_encoding(enc, ptr); + TRACE_FT((stderr, "Encoding[%d]: '%s' = '%s' -> '%s'", + i, enc, name, ptr)); +# endif + } else { + /* again, nag them with a popup so that they'll do something + about this ... */ + popup_message(globals.widgets.top_level, + MSG_ERR, + "Please check the syntax of your config file. " + "Valid keywords are: \"enc\" and \"dvipsmap\".", + "Skipping unknown keyword \"%s\" in config file %s.", + keyword, filename); + } + } + *p_tail = NULL; /* terminate linked list of map files */ + + fclose(fp); + free(filename); + + return open_next_mapfile(); +} + +# endif /* not DVIPS_SETUP */ + + +/* + * Information about Type 1 fonts is stored in an AVL tree. + */ + +static struct avl_t1 *t1_head = NULL; + + +/* + * Parse line from psfonts.map file. + */ + +static struct avl_t1 * +dvips_parse(const char *line) +{ + const char *w1p, *encp, *pfp, *qp; + size_t w1l, encl, pfl, ql; + const char *w2p; + size_t w2l; + const char *p, *p0; + const char *err; + struct avl_t1 *t1p; + char *q; + + w2l = w1l = encl = pfl = ql = 0; + err = NULL; + p = line; + for (;;) { /* loop over words */ + while (*p == ' ' || *p == '\t') ++p; + if (*p == '\0') + break; + + if (*p == '"') { /* quoted string */ + const char *p_end; + + p0 = p + 1; + p_end = p0 + strlen(p0); + p = memchr(p0, '"', p_end - p0); + if (p == NULL) p = p_end; + qp = (ql == 0 ? p0 : NULL); + ql += p - p0 + 1; + if (*p == '"') ++p; + continue; + } + + if (*p == '<') { /* encoding or pfa/b file */ + int wtype = 0; + + ++p; + if (*p == '<') { + wtype = 1; /* font file */ + ++p; + } + else if (*p == '[') { + wtype = -1; /* encoding file */ + ++p; + } + + /* find word */ + while (*p == ' ' || *p == '\t') ++p; + p0 = p; + while (*p != '\0' && *p != ' ' && *p != '\t') ++p; + + if (wtype == 0 && p > p0 + 4 && p[-4] == '.') { + if (memcmp(p - 3, "enc", 3) == 0 + || memcmp(p - 3, "ENC", 3) == 0) + wtype = -1; + else if (memcmp(p - 3, "pfa", 3) == 0 + || memcmp(p - 3, "pfb", 3) == 0 + || memcmp(p - 3, "PFA", 3) == 0 + || memcmp(p - 3, "PFB", 3) == 0) + wtype = 1; + } + + if (wtype > 0) { + if (pfl != 0) + err = "more than one font file given"; + else { + pfp = p0; + pfl = p - p0 + 1; + } + } + else if (wtype < 0) { + if (encl != 0) + err = "more than one encoding file given"; + else { + encp = p0; + encl = p - p0 + 1; + } + } + else + err = "cannot identify file type"; + } + else { /* if ordinary word */ + p0 = p; + while (*p != '\0' && *p != ' ' && *p != '\t') ++p; + if (w1l == 0) { + w1p = p0; + w1l = p - p0; + } + else if (w2l == 0) { + w2p = p0; + w2l = p - p0; + } + else + err = "more than two non-download words given"; + } + } /* end loop over words */ + + if (w1l == 0) { + TRACE_FT((stderr, + "map file %s: line \"%s\" does not give a font name.", + p_head->value, line)); + return NULL; + } + + if (err != NULL) { + TRACE_FT((stderr, "map file %s, font %.*s: %s", p_head->value, + (int) w1l, w1p, err)); + return NULL; + } + + t1p = (struct avl_t1 *) avladd(w1p, w1l, (struct avl **) &t1_head, + sizeof(struct avl_t1)); + + if (t1p->key != w1p) { /* if existing record */ + TRACE_FT((stderr, + "map file %s, font %.*s: duplicate record; using first one", + p_head->value, (int) w1l, w1p)); + return NULL; + } + + t1p->key = q = xmalloc(w1l + w2l + 1 + pfl + encl + ql); + + memcpy(q, w1p, w1l); + q += w1l; + t1p->psname = t1p->key; + if (w2l != 0) { + t1p->psname = q; + memcpy(q, w2p, w2l); + q += w2l; + } + *q++ = '\0'; + + t1p->fontfile = NULL; + if (pfl != 0) { + t1p->fontfile = q; + memcpy(q, pfp, pfl - 1); + q += pfl; + q[-1] = '\0'; + } + + t1p->encname = t1p->addinfo = NULL; +# if FREETYPE + t1p->bad = False; + t1p->ft = NULL; +# endif + + if (encl != 0) { + t1p->encname = q; + memcpy(q, encp, encl - 1); + q += encl; + q[-1] = '\0'; + } + + if (ql != 0) { + t1p->addinfo = q; + if (qp != 0) { + memcpy(q, qp, ql - 1); + q += ql; + } + else { /* multiple quoted strings; rescan to get them */ + const char *p_end; + + p = line; + p_end = p + strlen(p); + for (;;) { + while (*p == ' ' || *p == '\t') ++p; + if (*p == '\0') + break; + + /* found a word */ + if (*p == '"') { + ++p; + p0 = p; + p = memchr(p0, '"', p_end - p0); + if (p == NULL) p = p_end; + memcpy(q, p0, p - p0); + q += p - p0; + *q++ = ' '; + if (*p == '\0') break; + ++p; + } + else /* skip unquoted word */ + while (*p != '\0' && *p != ' ' && *p != '\t') ++p; + } + } + q[-1] = '\0'; + } + + return t1p; +} + +/* + * Information on the Ghostscript font aliasing mechanism is kept in + * another AVL tree. Each identifier points to a list of strings, + * up to one from each Fontmap file. Within a Fontmap file, later entries + * for a given string override earlier ones. + */ + +struct avl_gs { /* structure for gs font information */ + AVL_COMMON; + short fontmap_number; /* sequence of most recent entry */ + Boolean in_use; + struct gs_list *list; +}; + +struct gs_list { /* list of Fontmap entries for this font name */ + struct gs_list *next; + const char value[0]; +}; + +static struct avl_gs *gs_head = NULL; + +typedef void (*gs_path_proc)(FILE *); + +static const char *env_gs_lib; + +static FILE * +gs_try_fopen(const char *str, unsigned int len, const char *name) +{ + unsigned int namelen = strlen(name) + 1; + FILE *f; + + if (len + namelen + 1 > ffline_len) expandline(len + namelen + 1); + memcpy(ffline, str, len); + ffline[len] = '/'; + memcpy(ffline + len + 1, name, namelen); + + f = XFOPEN(ffline, OPEN_MODE); + + TRACE_FT((stderr, "gs_try_fopen: %s: %s", ffline, + f != NULL ? "file opened" : strerror(errno))); + + return f; +} + +static FILE * +gs_path_fopen(const char *name, gs_path_proc proc) +{ + const char *str1 = env_gs_lib; + const char *str2 = DEFAULT_GS_LIB_PATH; + const char *str1_end, *str2_end; + const char *p1, *p2; + FILE *f; + + if (str1 == NULL) { + str1 = str2; + str2 = NULL; + } + + str1_end = str1 + strlen(str1); + + for (;;) { + p1 = memchr(str1, ':', str1_end - str1); + if (p1 == NULL) p1 = str1_end; + if (p1 == str1) { + if (str2 != NULL) { + str2_end = str2 + strlen(str2); + for (;;) { + p2 = memchr(str2, ':', str2_end - str2); + if (p2 == NULL) p2 = str2_end; + if (p2 > str2) { + f = gs_try_fopen(str2, p2 - str2, name); + if (f != NULL) { + if (proc != NULL) + proc(f); + else + return f; + } + } + if (*p2 == '\0') + break; + str2 = p2 + 1; + } + str2 = NULL; + } + } + else { + f = gs_try_fopen(str1, p1 - str1, name); + if (f != NULL) { + if (proc != NULL) + proc(f); + else + return f; + } + } + + if (*p1 == '\0') + break; + str1 = p1 + 1; + } + + return NULL; +} + + +static FILE * +lookup_gs_font(const char *font, const char **path_ret) +{ + struct avl_gs *gsfp; + int font_len; + int i; + + font_len = strlen(font); + gsfp = gs_head; + for (;;) { + if (gsfp == NULL) /* if not found */ + return NULL; + + i = font_len - gsfp->key_len; + if (i == 0) + i = memcmp(font, gsfp->key, font_len); + if (i == 0) { /* if found */ + struct gs_list *gl, *gl2, *gl3; + FILE *f; + + if (gsfp->in_use) { + TRACE_FT((stderr, "Alias loop for %s detected; ignoring.", + font)); + return NULL; + } + + /* If we haven't done it yet, reverse the linked list */ + if (gsfp->fontmap_number != 0) { + gsfp->fontmap_number = 0; + gl = gsfp->list; + gl2 = NULL; + while (gl != NULL) { + gl3 = gl->next; + gl->next = gl2; + gl2 = gl; + gl = gl3; + } + gsfp->list = gl2; + } + gsfp->in_use = True; + f = NULL; + for (gl = gsfp->list; gl != NULL; gl = gl->next) { + if (gl->value[0] == '\0') { /* if alias */ + TRACE_FT((stderr, "Found alias %s --> %s", + font, gl->value + 1)); + f = lookup_gs_font(gl->value + 1, path_ret); + if (f == NULL) + TRACE_FT((stderr, "Alias %s not found.", + gl->value + 1)); + if (f != NULL) break; + } + else { + TRACE_FT((stderr, "Checking file %s", gl->value)); + if (gl->value[0] == '/' || (gl->value[0] == '.' + && (gl->value[1] == '/' || (gl->value[1] == '.' + && gl->value[2] == '/')))) { + f = XFOPEN(gl->value, OPEN_MODE); + if (f != NULL) { + *path_ret = xstrdup(gl->value); + break; + } + } + else { + f = gs_path_fopen(gl->value, NULL); + if (f != NULL) { + *path_ret = xstrdup(ffline); + break; + } + } + } + } + gsfp->in_use = False; + return f; + } + gsfp = (struct avl_gs *) (i < 0 ? gsfp->left : gsfp->right); + } +} + + +#define GS_BUF_SIZE 4096 + +struct gsfile { + FILE *f; + unsigned char *buffer; + const unsigned char *bufpos; + const unsigned char *buf_end; +}; + +static Boolean +gs_fillbuf(struct gsfile *gsf) +{ + unsigned char *p; + unsigned int len; + + if (gsf->buf_end < gsf->buffer + GS_BUF_SIZE) + return False; + + gsf->bufpos = p = gsf->buffer; + for (;;) { + len = gsf->buf_end - p; + if (len <= 0) break; + len = fread(p, 1, len, gsf->f); + if (len <= 0) break; + p += len; + } + gsf->buf_end = p; + return (p > gsf->buffer); +} + +static unsigned char gs_ctype[256]; + +#define GS_EOF '\0' +#define GS_ERR '%' +#define LPAREN '(' +#define RPAREN ')' + +static void +init_gs_ctype(void) +{ + const char *p; + + for (p = " \t\f\n\r";; ++p) { + gs_ctype[(unsigned char) *p] = 1; /* white space */ + if (*p == '\0') break; + } + gs_ctype['/'] = 2; /* literal token */ + gs_ctype['('] = 3; /* string */ + for (p = ")<>[]{}%"; *p != '\0'; ++p) + gs_ctype[(unsigned char) *p] = 4; /* delimiter */ +} + +static unsigned char +get_gs_character(struct gsfile *gsfp) +{ + unsigned char c; + + for (;;) { + if (gsfp->bufpos >= gsfp->buf_end && !gs_fillbuf(gsfp)) + return '%'; + c = *gsfp->bufpos++; + + /* Check for comments */ + if (c == '%') { + for (;;) { + const unsigned char *p1, *p2; + + p1 = memchr(gsfp->bufpos, '\n', + gsfp->buf_end - gsfp->bufpos); + if (p1 == NULL) p1 = gsfp->buf_end; + p2 = memchr(gsfp->bufpos, '\r', p1 - gsfp->bufpos); + if (p2 != NULL) p1 = p2; + p2 = memchr(gsfp->bufpos, '\f', p1 - gsfp->bufpos); + if (p2 != NULL) p1 = p2; + if (p1 < gsfp->buf_end) { + gsfp->bufpos = p1 + 1; + break; + } + if (!gs_fillbuf(gsfp)) + return '%'; + } + continue; + } + + if (gs_ctype[c] != 1) + break; + } + + return c; +} + +static unsigned char +get_gs_token(struct gsfile *gsfp, + unsigned int pos, + unsigned int *pos_ret, + const char *file_type) +{ + unsigned char gs_t_type; + unsigned char c; + const unsigned char *p0; + unsigned int pos0; + unsigned int depth; + + gs_t_type = c = get_gs_character(gsfp); + if (c == '%') + return GS_EOF; + + p0 = gsfp->bufpos; + switch (gs_ctype[c]) { + case 0: /* most characters */ + case 2: /* '/' */ + --p0; /* retain initial character */ + pos0 = pos; + for (;;) { + if (gsfp->bufpos >= gsfp->buf_end) { + unsigned int len = gsfp->bufpos - p0; + + if (pos + len >= ffline_len) expandline(pos + len); + bcopy(p0, ffline + pos, len); + pos += len; + if (!gs_fillbuf(gsfp)) + break; + p0 = gsfp->buffer; + } + if (gs_ctype[*gsfp->bufpos] != 0) { + unsigned int len = gsfp->bufpos - p0; + + if (pos + len >= ffline_len) expandline(pos + len); + bcopy(p0, ffline + pos, len); + pos += len; + break; + } + ++gsfp->bufpos; + } + /* Filter out DOS ^Z */ + if (pos == pos0 + 1 && ffline[pos0] == '\032') + return GS_EOF; + break; + + case 3: /* left parenthesis */ + depth = 1; + for (;;) { + const unsigned char *p1, *p2, *p3; + + if (gsfp->bufpos >= gsfp->buf_end) { + unsigned int len = gsfp->bufpos - p0; + + if (pos + len >= ffline_len) expandline(pos + len); + bcopy(p0, ffline + pos, len); + pos += len; + if (!gs_fillbuf(gsfp)) { + TRACE_FT((stderr, + "unterminated string in %s file; giving up.", + file_type)); + return GS_ERR; + } + p0 = gsfp->buffer; + } + p1 = memchr(gsfp->bufpos, RPAREN, + gsfp->buf_end - gsfp->bufpos); + if (p1 == NULL) p1 = gsfp->buf_end; + for (;;) { + p2 = memchr(gsfp->bufpos, LPAREN, p1 - gsfp->bufpos); + if (p2 == NULL) p2 = p1; + p3 = p2; + for (;;) { + if (p3 <= gsfp->bufpos) { + if (c == '\\') --p3; + break; + } + if (p3[-1] != '\\') break; + --p3; + } + c = '\\' - 1 + ((p2 - p3) & 1); + if (p2 >= p1) + break; + if (c != '\\') + ++depth; + gsfp->bufpos = p2 + 1; + c = '\0'; + } + if (p1 < gsfp->buf_end) { /* if left parenthesis at p1 */ + if (c != '\\') { + if (--depth == 0) { + unsigned int len = p1 - p0; + + if (pos + len >= ffline_len) + expandline(pos + len); + bcopy(p0, ffline + pos, len); + pos += len; + gsfp->bufpos = p1 + 1; + break; + } + } + ++p1; + } + gsfp->bufpos = p1; + } + /* We could do backslash escaping here, but it's probably + unnecessary. */ + break; + + default: + TRACE_FT((stderr, + "invalid character `%c' encountered in %s file; giving up.", + c, file_type)); + return GS_ERR; + } + + *pos_ret = pos; + return gs_t_type; +} + + +static short gs_fontmap_number = 0; + +static void +process_gs_fontmap(FILE *f) +{ + struct gsfile gsf; + unsigned char buffer[GS_BUF_SIZE]; + unsigned char ttype; + unsigned int pos1, pos2, pos3; + + ++gs_fontmap_number; + + gsf.f = f; + gsf.buffer = buffer; + gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE; + + /* + * Allow entries of the following types: + * + * (string) .runlibfile + * /identifier (string) ; + * /identifier /alias ; + */ + + for (;;) { + ttype = get_gs_token(&gsf, 0, &pos1, "Fontmap"); + if (ttype == GS_EOF || ttype == GS_ERR) + break; + if (ttype == LPAREN) { + FILE *f1; + + ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap"); + if (ttype == GS_ERR) + break; + if (ttype == GS_EOF) { + TRACE_FT((stderr, + "unexpected end of Fontmap file; giving up.")); + break; + } + if (ttype != '.' || pos2 - pos1 != 11 + || memcmp(ffline + pos1, ".runlibfile", 11) != 0) { + TRACE_FT((stderr, "invalid token following \"(%.*s)\" in Fontmap file; giving up.", + (int) pos1, ffline)); + break; + } + + ffline[pos1] = '\0'; + if (ffline[0] == '/' || (ffline[0] == '.' && (ffline[1] == '/' + || (ffline[1] == '.' && ffline[2] == '/')))) + f1 = XFOPEN(ffline, OPEN_MODE); + else { + char *q; + + q = xmemdup(ffline, pos1 + 1); + f1 = gs_path_fopen(q, NULL); + free(q); + } + + if (f1 == NULL) + TRACE_FT((stderr, "Fontmap .runlibfile: %s: %s", + ffline, strerror(errno))); + else { + --gs_fontmap_number; + process_gs_fontmap(f1); + } + } + else if (ttype == '/') { + struct avl_gs *gsfp; + struct gs_list *gslp; + + ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap"); + if (ttype == GS_ERR) + break; + if (ttype == GS_EOF) { + TRACE_FT((stderr, + "unexpected end of Fontmap file; giving up.")); + break; + } + if ((ttype != '/' && ttype != LPAREN) + || pos2 == pos1 /* empty string would mess things up */ + || get_gs_token(&gsf, pos2, &pos3, "Fontmap") != ';' + || pos3 != pos2 + 1) { + TRACE_FT((stderr, + "invalid token following \"%.*s\" in Fontmap file; giving up.", + (int) pos1, ffline)); + break; + } + if (ttype == '/') + ffline[pos1] = '\0'; /* mark aliases by initial \0 */ + ffline[pos2++] = '\0'; /* terminate string */ + + /* Add to database */ + gsfp = (struct avl_gs *) avladd(ffline + 1, pos1 - 1, + (struct avl **) &gs_head, sizeof *gsfp); + + if (gsfp->key == ffline + 1) { /* if new record */ + gsfp->key = xmemdup(ffline + 1, pos1 - 1); + gsfp->in_use = False; + gsfp->list = NULL; + } + else { + if (strlen(gsfp->list->value + 1) + 2 == pos2 - pos1 + && memcmp(gsfp->list->value, ffline + pos1, pos2 - pos1) + == 0) + continue; /* ignore duplicate entry */ + if (gsfp->fontmap_number == gs_fontmap_number) { + /* Later entries in a Fontmap file override earlier + ones */ + gslp = gsfp->list; + gsfp->list = gslp->next; + free(gslp); + } + } + gslp = xmalloc(sizeof *gslp + pos2 - pos1); + gslp->next = gsfp->list; + gsfp->list = gslp; + memcpy((char *) gslp->value, ffline + pos1, pos2 - pos1); + + gsfp->fontmap_number = gs_fontmap_number; + } + else { + TRACE_FT((stderr, + "invalid token \"%s\" in Fontmap file; giving up.", + ffline)); + } + } + + fclose(f); +} + +/* + * Read Ghostscript Fontmap files. These are used if the line in + * psfonts.map does not contain a filename for the font. + * + * For example: + * n019003l NimbusSanL-Regu + */ + +static void +read_gs_fontmaps(void) +{ + env_gs_lib = getenv("XDVI_GS_LIB"); + if (env_gs_lib == NULL) + env_gs_lib = getenv("GS_LIB"); + + if (gs_ctype[0] == 0) + init_gs_ctype(); + + (void) gs_path_fopen("Fontmap", process_gs_fontmap); +} + + +/* + * pre_lookup_t1_font - Find a Type 1 font (or return NULL). + */ + +static struct avl_t1 * +pre_lookup_t1_font(const char *fontname) +{ + struct avl_t1 *t1p; + size_t len; + int i; + + /* first, search for the font */ + + len = strlen(fontname); + t1p = t1_head; + while (t1p != NULL) { + i = len - t1p->key_len; + if (i == 0) + i = memcmp(fontname, t1p->key, len); + if (i == 0) + return t1p; /* found it */ + t1p = (struct avl_t1 *) (i < 0 ? t1p->left : t1p->right); + } + + /* next, read in more records in hopes of finding the font */ + + if (p_head != NULL) + for (;;) { + if (!fgets_long(mapfile)) { /* if end of file */ + fclose(mapfile); + p_head = p_head->next; + if (!open_next_mapfile()) + return NULL; + continue; + } + + if (*ffline < ' ' || *ffline == '*' || *ffline == '#' + || *ffline == ';' || *ffline == '%') + continue; + + t1p = dvips_parse(ffline); + + if (t1p != NULL && t1p->key_len == len + && memcmp(t1p->key, fontname, len) == 0) + return t1p; /* found it */ + } + + return NULL; +} + +/* + * lookup_t1_font - Find a Type 1 font (or return NULL). + */ + +Boolean +lookup_t1_font(struct font *fontp, + const char *fontname) +{ + struct avl_t1 *t1p; + struct ftfont *ftp; + + t1p = pre_lookup_t1_font(fontname); + + if (t1p == NULL) + return False; + + if (t1p->bad) { + TRACE_FT((stderr, + "Font %s is marked as bad: skipping scalable version", + fontname)); + return False; + } + + ftp = t1p->ft; + if (ftp != NULL) { /* if it's is already in use at another size */ + struct font *first_size; + + /* The first node in the linked list of sizes contains the file */ + /* reference, so we link in the new node after the first node */ + first_size = ftp->first_size; + fontp->next_size = first_size->next_size; + first_size->next_size = fontp; + } + else { /* first use at this size */ + t1p->ft = ftp = xmalloc(sizeof *ftp); + ftp->face = NULL; + ftp->t1 = t1p; + ftp->first_size = fontp; + fontp->next_size = NULL; + } + fontp->ft = ftp; + fontp->size = NULL; + + return True; +} + +FILE * +open_t1_font(struct avl_t1 *t1p, + const char **path_ret) +{ + FILE *f; + + if (t1p->fontfile == NULL) { /* look up in GS Fontmap */ + static Boolean gs_fontmap_initialized = False; + + if (!gs_fontmap_initialized) { + read_gs_fontmaps(); + gs_fontmap_initialized = True; + } + + TRACE_FT((stderr, + "Looking for font %.*s using gs method (PS name %s) --", + t1p->key_len, t1p->key, t1p->psname)); + f = lookup_gs_font(t1p->psname, path_ret); + + if (f == NULL) { + TRACE_FT((stderr, "cannot find Type 1 font %s", + t1p->psname)); + return NULL; + } + + TRACE_FT((stderr, "Found file %s", *path_ret)); + } + else { + char *filename; + + filename = kpse_find_file(t1p->fontfile, kpse_type1_format, 0); + if (filename == NULL) { + XDVI_WARNING((stderr, "cannot find Type 1 font file %s " + "(will try PK version instead).", + t1p->fontfile)); + return NULL; + } + + f = XFOPEN(filename, OPEN_MODE); + if (f == NULL) { + TRACE_FT((stderr, "cannot open Type 1 font file %s: %s", + filename, strerror(errno))); + free(filename); + return NULL; + } + *path_ret = filename; + } + + return f; +} + + +/* + * Read the encoding vector file. This assumes the same format as afm2tfm. + */ + +extern struct findrec search_header; /* from special.c */ + +void +read_encoding(struct avl_enc *encp) +{ + char *filename; + FILE *f; + struct gsfile gsf; + unsigned char buffer[GS_BUF_SIZE]; + jmp_buf err_env; + unsigned char ttype; + unsigned int pos1, pos2; + unsigned int identindex[256]; + const char *str; + unsigned int i; + + TRACE_FT((stderr, "Reading encoding file %s", encp->key)); + + encp->valid = False; + + /* + * With TDS 1.0/kpathsea 3.5.2(?), encoding files are in texmf/fonts/enc + * and accessed via kpse_enc_format; see e.g.: + * http://tug.org/mailman/htdig/tex-live/2004-January/004734.html + * + * The lookups under kpse_program_text_format and + * kpse_tex_ps_header_format are kept for backwards compatibility. + */ + + filename = kpse_find_file(encp->key, kpse_enc_format, 0); + if (filename == NULL) { + filename = kpse_find_file(filename, kpse_program_text_format, 0); + if (filename == NULL) + filename = kpse_find_file(filename, kpse_tex_ps_header_format, + True); + } + if (filename == NULL) { + TRACE_FT((stderr, + "cannot find encoding file %s; ignoring encoding", encp->key)); + return; + } + + f = XFOPEN(filename, OPEN_MODE); + if (f == NULL) { + TRACE_FT((stderr, "cannot open encoding file %s: %s", + filename, strerror(errno))); + free(filename); + return; + } + free(filename); + + if (gs_ctype[0] == 0) + init_gs_ctype(); + + gsf.f = f; + gsf.buffer = buffer; + gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE; + + if (!setjmp(err_env)) { + if (get_gs_token(&gsf, 0, &pos1, "encoding") != '/' + || get_gs_character(&gsf) != '[') + longjmp(err_env, 1); + + pos1 = 0; + for (i = 0; i < 256; ++i) { + if (get_gs_token(&gsf, pos1, &pos2, "encoding") != '/') + longjmp(err_env, 1); + if (pos2 == pos1 + 8 + && memcmp(ffline + pos1, "/.notdef", 8) == 0) + identindex[i] = 0; + else { + ffline[pos1] = '\0'; + identindex[i] = pos1 + 1; + pos1 = pos2; + } + } + + if (get_gs_character(&gsf) != ']') + longjmp(err_env, 1); + + ttype = get_gs_token(&gsf, pos1, &pos2, "encoding"); + if (!(ttype == GS_EOF + || (ttype == 'd' && pos2 == pos1 + 3 + && memcmp(ffline + pos1, "def", 3) == 0 + && get_gs_token(&gsf, pos2, &pos2, "encoding") == GS_EOF))) + longjmp(err_env, 1); + + if (pos1 >= ffline_len) expandline(pos1 + 1); + ffline[pos1] = '\0'; + str = xmemdup(ffline + 1, pos1); + for (i = 0; i < 256; ++i) + encp->vec[i] = + (identindex[i] != 0 ? str + identindex[i] - 1 : NULL); + + encp->valid = True; + } + else /* if error */ + TRACE_FT((stderr, + "invalid format in encoding file %s; giving up.", encp->key)); + + fclose(f); +} + +#endif /* FREETYPE || PS */ + + #if 0 static int mktexpk_io[2]; static struct xchild mktexpk_child = { NULL, 0, True, "font creation", NULL, NULL, mktexpk_ended }; @@ -283,11 +1673,7 @@ font_open( #endif struct font *fontp, const char **font_ret, - int *dpi_ret, -#ifdef T1LIB - int *t1id, -#endif - Boolean use_t1lib) + int *dpi_ret) { char *name; kpse_glyph_file_type file_ret; @@ -312,12 +1698,6 @@ font_open( name = kpse_find_vf(fontp->fontname); } -#ifdef T1LIB - if (resource.t1lib) { - *t1id = -1; - } -#endif /* T1LIB */ - if (name) { /* found a vf font */ /* pretend it has the expected dpi value, else caller will complain */ *dpi_ret = fontp->fsize; @@ -325,27 +1705,26 @@ font_open( return XFOPEN(name, FOPEN_R_MODE); } -#ifdef T1LIB - if (resource.t1lib && use_t1lib -#if DELAYED_MKTEXPK +#if FREETYPE + if (resource.freetype +# if DELAYED_MKTEXPK && load_font_now -#endif +# endif ) { - /* First attempt: T1 font of correct size + /* First attempt: freetype font of correct size * (for delayed_mtkexpk, only when scanning postamble for the first time) */ - *t1id = find_T1_font(fontp->fontname); - if (*t1id >= 0) { - TRACE_T1((stderr, "found T1 font %s", fontp->fontname)); + if (lookup_t1_font(fontp, fontp->fontname)) { + TRACE_FT((stderr, "found freetype font %s", fontp->fontname)); return NULL; } - TRACE_T1((stderr, - "T1 version of font %s not found, trying pixel version next, then fallback", + TRACE_FT((stderr, + "Freetype version of font %s not found, trying pixel version next, then fallback", fontp->fontname)); } -#endif /* T1LIB */ - - +#endif /* FREETYPE */ + + /* TODO: @@ -441,7 +1820,7 @@ font_open( *dpi_ret = file_ret.dpi; fontp->filename = name; *font_ret = file_ret.name; - TRACE_T1((stderr, "Found pixel version: %s at %d dpi", file_ret.name, *dpi_ret)); + TRACE_FT((stderr, "Found pixel version: %s at %d dpi", file_ret.name, *dpi_ret)); #if DELAYED_MKTEXPK if (message_done) { statusline_append(STATUS_VERYSHORT, "DUMMY", /* append text, don't overwrite */ @@ -463,41 +1842,41 @@ font_open( already exist. So we invoke it explicitly a second time for that one. */ - TRACE_T1((stderr, "Trying fallback")); -#ifdef T1LIB - if (resource.t1lib + TRACE_FT((stderr, "Trying fallback")); +#if FREETYPE + if (resource.freetype #if DELAYED_MKTEXPK && load_font_now #endif ) { - /* Third attempt: T1 version of fallback font */ - *t1id = find_T1_font(resource.alt_font); - if (*t1id >= 0) { - TRACE_T1((stderr, "found fallback font for %s: %s", fontp->fontname, resource.alt_font)); + /* Third attempt: freetype version of fallback font */ + if (lookup_t1_font(fontp, resource.alt_font)) { + TRACE_FT((stderr, "found fallback font for %s: %s", + fontp->fontname, resource.alt_font)); *font_ret = xstrdup(resource.alt_font); return NULL; } - TRACE_T1((stderr, - "Type1 version of fallback font %s not found, trying pixel version", + TRACE_FT((stderr, + "Freetype version of fallback font %s not found, trying pixel version", resource.alt_font)); } -#endif /* T1LIB */ - /* Forth attempt: PK version of fallback font */ +#endif /* FREETYPE */ + /* Fourth attempt: PK version of fallback font */ name = kpse_find_glyph(resource.alt_font, (unsigned)(fontp->fsize + .5), kpse_any_glyph_format, &file_ret); if (name) { /* success */ - TRACE_T1((stderr, "Success for PK version of fallback")); + TRACE_FT((stderr, "Success for PK version of fallback")); *dpi_ret = file_ret.dpi; fontp->filename = name; *font_ret = xstrdup(resource.alt_font); return XFOPEN(name, FOPEN_R_MODE); } else { - TRACE_T1((stderr, "Failure for PK version of fallback")); + TRACE_FT((stderr, "Failure for PK version of fallback")); } } /* all other cases are failure */ - TRACE_T1((stderr, "Failure")); + TRACE_FT((stderr, "Failure")); return NULL; } |