summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mpdir/mapfile.c
diff options
context:
space:
mode:
authorTaco Hoekwater <taco@elvenkind.com>2006-11-20 14:43:48 +0000
committerTaco Hoekwater <taco@elvenkind.com>2006-11-20 14:43:48 +0000
commit5952e40b396499c0cd62bdbcf1853538873b76c1 (patch)
tree968b37e966ba1825e2de091a071774af1a7ffa9b /Build/source/texk/web2c/mpdir/mapfile.c
parent9fcf4d90b8b3a11712287d4ddf3fd47614a7ea68 (diff)
Metapost 0.99 sources, except dmp
git-svn-id: svn://tug.org/texlive/trunk@2470 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/mpdir/mapfile.c')
-rw-r--r--Build/source/texk/web2c/mpdir/mapfile.c993
1 files changed, 993 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mpdir/mapfile.c b/Build/source/texk/web2c/mpdir/mapfile.c
new file mode 100644
index 00000000000..25d5818f5c0
--- /dev/null
+++ b/Build/source/texk/web2c/mpdir/mapfile.c
@@ -0,0 +1,993 @@
+/* Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com>
+
+This file is part of MetaPost.
+
+MetaPost 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.
+
+MetaPost 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 MetaPost; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+$Id: mapfile.c,v 1.20 2005/10/16 17:41:51 hahe Exp hahe $
+
+*/
+
+#include <math.h>
+#include "mplib.h"
+#include <kpathsea/c-auto.h>
+#include <kpathsea/c-memstr.h>
+#include <string.h>
+
+static const char perforce_id[] =
+ "$Id: mapfile.c,v 1.20 2005/10/16 17:41:51 hahe Exp hahe $";
+
+#define FM_BUF_SIZE 1024
+
+static FILE *fm_file;
+
+#define fm_open() \
+ open_input (&fm_file, kpse_fontmap_format, FOPEN_RBIN_MODE)
+#define fm_close() xfclose(fm_file, cur_file_name)
+#define fm_getchar() xgetc(fm_file)
+#define fm_eof() feof(fm_file)
+
+enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
+enum _ltype { MAPFILE, MAPLINE };
+enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
+
+typedef struct mitem {
+ int mode; /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE */
+ int type; /* map file or map line */
+ char *line; /* pointer to map file name or map line */
+ int lineno; /* line number in map file */
+} mapitem;
+mapitem *mitem = NULL;
+
+fm_entry *fm_cur;
+static const char nontfm[] = "<nontfm>";
+static fm_entry *loaded_tfm_found;
+static fm_entry *avail_tfm_found;
+static fm_entry *non_tfm_found;
+static fm_entry *not_avail_tfm_found;
+
+#define read_field(r, q, buf) do { \
+ q = buf; \
+ while (*r != ' ' && *r != '\0') \
+ *q++ = *r++; \
+ *q = '\0'; \
+ skip (r, ' '); \
+} while (0)
+
+#define set_field(F) do { \
+ if (q > buf) \
+ fm->F = xstrdup(buf); \
+ if (*r == '\0') \
+ goto done; \
+} while (0)
+
+#define cmp_return(a, b) \
+ if (a > b) \
+ return 1; \
+ if (a < b) \
+ return -1
+
+fm_entry *new_fm_entry (void)
+{
+ fm_entry *fm;
+ fm = xtalloc (1, fm_entry);
+ fm->tfm_name = NULL;
+ fm->ps_name = NULL;
+ fm->flags = 4;
+ fm->ff_name = NULL;
+ fm->subset_tag = NULL;
+ fm->encoding = NULL;
+ fm->tfm_num = getnullfont ();
+ fm->tfm_avail = TFM_UNCHECKED;
+ fm->type = 0;
+ fm->slant = 0;
+ fm->extend = 0;
+ fm->ff_objnum = 0;
+ fm->fn_objnum = 0;
+ fm->fd_objnum = 0;
+ fm->charset = NULL;
+ fm->all_glyphs = false;
+ fm->links = 0;
+ fm->pid = -1;
+ fm->eid = -1;
+ fm->subfont = NULL;
+ return fm;
+}
+
+void delete_fm_entry (fm_entry * fm)
+{
+ xfree (fm->tfm_name);
+ xfree (fm->ps_name);
+ xfree (fm->ff_name);
+ xfree (fm->subset_tag);
+ xfree (fm->charset);
+ xfree (fm);
+}
+
+static ff_entry *new_ff_entry (void)
+{
+ ff_entry *ff;
+ ff = xtalloc (1, ff_entry);
+ ff->ff_name = NULL;
+ ff->ff_path = NULL;
+ return ff;
+}
+
+static void delete_ff_entry (ff_entry * ff)
+{
+ xfree (ff->ff_name);
+ xfree (ff->ff_path);
+ xfree (ff);
+}
+
+static fm_entry *dummy_fm_entry ()
+{
+ static const fm_entry const_fm_entry;
+ return (fm_entry *) & const_fm_entry;
+}
+
+char *mk_base_tfm (char *tfmname, int *i)
+{
+ static char buf[SMALL_BUF_SIZE];
+ char *p = tfmname, *r = strend (p) - 1, *q = r;
+ while (q > p && isdigit (*q))
+ --q;
+ if (!(q > p) || q == r || (*q != '+' && *q != '-'))
+ return NULL;
+ check_buf (q - p + 1, SMALL_BUF_SIZE);
+ strncpy (buf, p, (size_t) (q - p));
+ buf[q - p] = '\0';
+ *i = atoi (q);
+ return buf;
+}
+
+static fmentryptr fmlookup (fontnumber);
+
+boolean hasfmentry (fontnumber f)
+{
+ if (mpfontmap[f] == NULL)
+ mpfontmap[f] = fmlookup (f);
+ assert (mpfontmap[f] != NULL);
+ return mpfontmap[f] != (fmentryptr) dummy_fm_entry ();
+}
+
+/**********************************************************************/
+
+struct avl_table *tfm_tree = NULL;
+struct avl_table *ps_tree = NULL;
+struct avl_table *ff_tree = NULL;
+
+/* AVL sort fm_entry into tfm_tree by tfm_name */
+
+static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p)
+{
+ return strcmp (((const fm_entry *) pa)->tfm_name,
+ ((const fm_entry *) pb)->tfm_name);
+}
+
+/* AVL sort fm_entry into ps_tree by ps_name, slant, and extend */
+
+static int comp_fm_entry_ps (const void *pa, const void *pb, void *p)
+{
+ const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
+ int i;
+ assert (p1->ps_name != NULL && p2->ps_name != NULL);
+ if ((i = strcmp (p1->ps_name, p2->ps_name)))
+ return i;
+ cmp_return (p1->slant, p2->slant);
+ cmp_return (p1->extend, p2->extend);
+ if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
+ (i = strcmp (p1->tfm_name, p2->tfm_name)))
+ return i;
+ return 0;
+}
+
+/* AVL sort ff_entry into ff_tree by ff_name */
+
+static int comp_ff_entry (const void *pa, const void *pb, void *p)
+{
+ return strcmp (((const ff_entry *) pa)->ff_name,
+ ((const ff_entry *) pb)->ff_name);
+}
+
+static void create_avl_trees ()
+{
+ if (tfm_tree == NULL) {
+ tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &avl_xallocator);
+ assert (tfm_tree != NULL);
+ }
+ if (ps_tree == NULL) {
+ ps_tree = avl_create (comp_fm_entry_ps, NULL, &avl_xallocator);
+ assert (ps_tree != NULL);
+ }
+ if (ff_tree == NULL) {
+ ff_tree = avl_create (comp_ff_entry, NULL, &avl_xallocator);
+ assert (ff_tree != NULL);
+ }
+}
+
+/*
+The function avl_do_entry() is not completely symmetrical with regards
+to tfm_name and ps_name handling, e. g. a duplicate tfm_name gives a
+"goto exit", and no ps_name link is tried. This is to keep it compatible
+with the original version.
+*/
+
+int avl_do_entry (fm_entry * fp, int mode)
+{
+ fm_entry *p;
+ void *a;
+ void **aa;
+
+ /* handle tfm_name link */
+
+ if (strcmp (fp->tfm_name, nontfm)) {
+ p = (fm_entry *) avl_find (tfm_tree, fp);
+ if (p != NULL) {
+ if (mode == FM_DUPIGNORE) {
+ pdftex_warn
+ ("fontmap entry for `%s' already exists, duplicates ignored",
+ fp->tfm_name);
+ goto exit;
+ } else { /* mode == FM_REPLACE / FM_DELETE */
+ if (fontsizes[p->tfm_num]!=0) {
+ pdftex_warn
+ ("fontmap entry for `%s' has been used, replace/delete not allowed",
+ fp->tfm_name);
+ goto exit;
+ }
+ a = avl_delete (tfm_tree, p);
+ assert (a != NULL);
+ unset_tfmlink (p);
+ if (!has_pslink (p))
+ delete_fm_entry (p);
+ }
+ }
+ if (mode != FM_DELETE) {
+ aa = avl_probe (tfm_tree, fp);
+ assert (aa != NULL);
+ set_tfmlink (fp);
+ }
+ }
+
+ /* handle ps_name link */
+
+ if (fp->ps_name != NULL) {
+ assert (fp->tfm_name != NULL);
+ p = (fm_entry *) avl_find (ps_tree, fp);
+ if (p != NULL) {
+ if (mode == FM_DUPIGNORE) {
+ pdftex_warn
+ ("ps_name entry for `%s' already exists, duplicates ignored",
+ fp->ps_name);
+ goto exit;
+ } else { /* mode == FM_REPLACE / FM_DELETE */
+ if (fontsizes[p->tfm_num]!=0) {
+ /* REPLACE/DELETE not allowed */
+ pdftex_warn
+ ("fontmap entry for `%s' has been used, replace/delete not allowed",
+ p->tfm_name);
+ goto exit;
+ }
+ a = avl_delete (ps_tree, p);
+ assert (a != NULL);
+ unset_pslink (p);
+ if (!has_tfmlink (p))
+ delete_fm_entry (p);
+ }
+ }
+ if (mode != FM_DELETE) {
+ aa = avl_probe (ps_tree, fp);
+ assert (aa != NULL);
+ set_pslink (fp);
+ }
+ }
+ exit:
+ if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after FM_DELETE */
+ return 1; /* deallocation of fm_entry structure required */
+ else
+ return 0;
+}
+
+/**********************************************************************/
+/* consistency check for map entry, with warn flag */
+
+int check_fm_entry (fm_entry * fm, boolean warn)
+{
+ int a = 0;
+ assert (fm != NULL);
+ if (fm->ps_name != NULL) {
+ if (is_basefont (fm)) {
+ if (is_fontfile (fm) && !is_included (fm)) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': font file must be included or omitted for base fonts",
+ fm->tfm_name);
+ a += 1;
+ }
+ } else { /* not a base font */
+ /* if no font file given, drop this entry */
+ /* if (!is_fontfile (fm)) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': font file missing",
+ fm->tfm_name);
+ a += 2;
+ }
+ */
+ }
+ }
+ if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': only subsetted TrueType font can be reencoded",
+ fm->tfm_name);
+ a += 4;
+ }
+ if ((fm->slant != 0 || fm->extend != 0) &&
+ (is_truetype (fm))) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': SlantFont/ExtendFont can be used only with embedded T1 fonts",
+ fm->tfm_name);
+ a += 8;
+ }
+ if (abs (fm->slant) > 1000) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': too big value of SlantFont (%g)",
+ fm->tfm_name, fm->slant / 1000.0);
+ a += 16;
+ }
+ if (abs (fm->extend) > 2000) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': too big value of ExtendFont (%g)",
+ fm->tfm_name, fm->extend / 1000.0);
+ a += 32;
+ }
+ if (fm->pid != -1 &&
+ !(is_truetype (fm) && is_included (fm) &&
+ is_subsetted (fm) && !is_reencoded (fm))) {
+ if (warn)
+ pdftex_warn
+ ("invalid entry for `%s': PidEid can be used only with subsetted non-reencoded TrueType fonts",
+ fm->tfm_name);
+ a += 64;
+ }
+ return a;
+}
+
+/**********************************************************************/
+/* returns true if s is one of the 14 std. font names; speed-trimmed. */
+
+boolean check_basefont (char *s)
+{
+ static const char *basefont_names[] = {
+ "Courier", /* 0:7 */
+ "Courier-Bold", /* 1:12 */
+ "Courier-Oblique", /* 2:15 */
+ "Courier-BoldOblique", /* 3:19 */
+ "Helvetica", /* 4:9 */
+ "Helvetica-Bold", /* 5:14 */
+ "Helvetica-Oblique", /* 6:17 */
+ "Helvetica-BoldOblique", /* 7:21 */
+ "Symbol", /* 8:6 */
+ "Times-Roman", /* 9:11 */
+ "Times-Bold", /* 10:10 */
+ "Times-Italic", /* 11:12 */
+ "Times-BoldItalic", /* 12:16 */
+ "ZapfDingbats" /* 13:12 */
+ };
+ static const int index[] =
+ { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
+ -1, 3, -1, 7
+ };
+ const size_t n = strlen (s);
+ int k = -1;
+ if (n > 21)
+ return false;
+ if (n == 12) { /* three names have length 12 */
+ switch (*s) {
+ case 'C':
+ k = 1; /* Courier-Bold */
+ break;
+ case 'T':
+ k = 11; /* Times-Italic */
+ break;
+ case 'Z':
+ k = 13; /* ZapfDingbats */
+ break;
+ default:
+ return false;
+ }
+ } else
+ k = index[n];
+ if (k > -1 && !strcmp (basefont_names[k], s))
+ return true;
+ return false;
+};
+
+/**********************************************************************/
+
+static void fm_scan_line ()
+{
+ int a, b, c, j, u = 0, v = 0;
+ float d;
+ fm_entry *fm;
+ char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
+ char *p, *q, *r, *s;
+ switch (mitem->type) {
+ case MAPFILE:
+ p = fm_line;
+ do {
+ c = fm_getchar ();
+ append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
+ }
+ while (c != 10);
+ *(--p) = '\0';
+ r = fm_line;
+ break;
+ case MAPLINE:
+ r = mitem->line; /* work on string from makecstring() */
+ break;
+ default:
+ assert (0);
+ }
+ if (*r == '\0' || is_cfg_comment (*r))
+ return;
+ fm = new_fm_entry ();
+ read_field (r, q, buf);
+ set_field (tfm_name);
+ p = r;
+ read_field (r, q, buf);
+ if (*buf != '<' && *buf != '"')
+ set_field (ps_name);
+ else
+ r = p; /* unget the field */
+ if (isdigit (*r)) { /* font flags given */
+ fm->flags = atoi (r);
+ while (isdigit (*r))
+ r++;
+ }
+ while (1) { /* loop through "specials", encoding, font file */
+ skip (r, ' ');
+ switch (*r) {
+ case '\0':
+ goto done;
+ case '"': /* opening quote */
+ r++;
+ u = v = 0;
+ do {
+ skip (r, ' ');
+ if (sscanf (r, "%f %n", &d, &j) > 0) {
+ s = r + j; /* jump behind number, eat also blanks, if any */
+ if (*(s - 1) == 'E' || *(s - 1) == 'e')
+ s--; /* e. g. 0.5ExtendFont: %f = 0.5E */
+ if (str_prefix (s, "SlantFont")) {
+ d *= 1000.0; /* correct rounding also for neg. numbers */
+ fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
+ r = s + strlen ("SlantFont");
+ } else if (str_prefix (s, "ExtendFont")) {
+ d *= 1000.0;
+ fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
+ if (fm->extend == 1000)
+ fm->extend = 0;
+ r = s + strlen ("ExtendFont");
+ } else { /* unknown name */
+ for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++); /* jump over name */
+ c = *r; /* remember char for temporary end of string */
+ *r = '\0';
+ pdftex_warn
+ ("invalid entry for `%s': unknown name `%s' ignored",
+ fm->tfm_name, s);
+ *r = c;
+ }
+ } else
+ for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
+ }
+ while (*r == ' ');
+ if (*r == '"') /* closing quote */
+ r++;
+ else {
+ pdftex_warn
+ ("invalid entry for `%s': closing quote missing",
+ fm->tfm_name);
+ goto bad_line;
+ }
+ break;
+ case 'P': /* handle cases for subfonts like 'PidEid=3,1' */
+ if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
+ fm->pid = a;
+ fm->eid = b;
+ r += c;
+ break;
+ }
+ default: /* encoding or font file specification */
+ a = b = 0;
+ if (*r == '<') {
+ a = *r++;
+ if (*r == '<' || *r == '[')
+ b = *r++;
+ }
+ read_field (r, q, buf);
+ /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
+ if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
+ fm->encoding = add_enc (buf);
+ u = v = 0; /* u, v used if intervening blank: "<< foo" */
+ } else if (strlen (buf) > 0) { /* file name given */
+ /* font file, formats:
+ * subsetting: '<cmr10.pfa'
+ * no subsetting: '<<cmr10.pfa'
+ * no embedding: 'cmr10.pfa'
+ */
+ if (a == '<' || u == '<') {
+ set_included (fm);
+ if ((a == '<' && b == 0) || (a == 0 && v == 0))
+ set_subsetted (fm);
+ /* otherwise b == '<' (or '[') => no subsetting */
+ }
+ set_field (ff_name);
+ u = v = 0;
+ } else {
+ u = a;
+ v = b;
+ }
+ }
+ }
+ done:
+ if (fm->ps_name != NULL && check_basefont (fm->ps_name))
+ set_basefont (fm);
+ if (is_fontfile (fm)
+ && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
+ set_truetype (fm);
+ if (check_fm_entry (fm, true) != 0)
+ goto bad_line;
+ /*
+ Until here the map line has been completely scanned without errors;
+ fm points to a valid, freshly filled-out fm_entry structure.
+ Now follows the actual work of registering/deleting.
+ */
+ // if (handle_subfont_fm (fm, mitem->mode)) /* is this a subfont? */
+ // return;
+ if (avl_do_entry (fm, mitem->mode) == 0) /* if success */
+ return;
+ bad_line:
+ delete_fm_entry (fm);
+}
+
+/**********************************************************************/
+
+void fm_read_info ()
+{
+ if (tfm_tree == NULL)
+ create_avl_trees ();
+ if (mitem->line == NULL) /* nothing to do */
+ return;
+ mitem->lineno = 1;
+ switch (mitem->type) {
+ case MAPFILE:
+ set_cur_file_name (mitem->line);
+ if (!fm_open ()) {
+ pdftex_warn ("cannot open font map file");
+ } else {
+ cur_file_name = (char *) nameoffile + 1;
+ mp_printf ("{%s", cur_file_name);
+ while (!fm_eof ()) {
+ fm_scan_line ();
+ mitem->lineno++;
+ }
+ fm_close ();
+ mp_printf ("}");
+ fm_file = NULL;
+ }
+ break;
+ case MAPLINE:
+ cur_file_name = NULL; /* makes pdftex_warn() shorter */
+ fm_scan_line ();
+ break;
+ default:
+ assert (0);
+ }
+ mitem->line = NULL; /* done with this line */
+ cur_file_name = NULL;
+ return;
+}
+
+/**********************************************************************/
+
+fontnumber tfmoffm (fmentryptr fm_pt)
+{
+ return ((fm_entry *) fm_pt)->tfm_num;
+}
+
+static fm_entry *mk_ex_fm (fontnumber f, fm_entry * basefm, int ex)
+{
+ fm_entry *fm;
+ integer e = basefm->extend;
+ if (e == 0)
+ e = 1000;
+ fm = new_fm_entry ();
+ fm->flags = basefm->flags;
+ fm->encoding = basefm->encoding;
+ fm->type = basefm->type;
+ fm->slant = basefm->slant;
+ fm->extend = roundxnoverd (e, 1000 + ex, 1000); /* modify ExtentFont to simulate expansion */
+ if (fm->extend == 1000)
+ fm->extend = 0;
+ fm->tfm_name = xstrdup (makecstring (fontname[f]));
+ if (basefm->ps_name != NULL)
+ fm->ps_name = xstrdup (basefm->ps_name);
+ fm->ff_name = xstrdup (basefm->ff_name);
+ fm->ff_objnum = 0;
+ fm->tfm_num = f;
+ fm->tfm_avail = TFM_FOUND;
+ assert (strcmp (fm->tfm_name, nontfm));
+ return fm;
+}
+
+static void init_fm (fm_entry * fm, fontnumber f)
+{
+ // if (fm->fd_objnum == 0 && !no_font_desc (fm))
+ // fm->fd_objnum = pdfnewobjnum ();
+ // if (fm->ff_objnum == 0 && is_included (fm))
+ // fm->ff_objnum = pdfnewobjnum ();
+ if (fm->tfm_num == getnullfont ()) {
+ fm->tfm_num = f;
+ fm->tfm_avail = TFM_FOUND;
+ }
+}
+
+static fmentryptr fmlookup (fontnumber f)
+{
+ char *tfm;
+ fm_entry *fm, *exfm;
+ fm_entry tmp;
+ int ai, e;
+ if (tfm_tree == NULL)
+ fm_read_info (); /* only to read default map file */
+ tfm = makecstring (fontname[f]);
+ assert (strcmp (tfm, nontfm));
+
+ /* Look up for full <tfmname>[+-]<expand> */
+ tmp.tfm_name = tfm;
+ fm = (fm_entry *) avl_find (tfm_tree, &tmp);
+ if (fm != NULL) {
+ init_fm (fm, f);
+ return (fmentryptr) fm;
+ }
+ tfm = mk_base_tfm (makecstring (fontname[f]), &e);
+ if (tfm == NULL) /* not an expanded font, nothing to do */
+ return (fmentryptr) dummy_fm_entry ();
+
+ tmp.tfm_name = tfm;
+ fm = (fm_entry *) avl_find (tfm_tree, &tmp);
+ if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */
+ return (fmentryptr) fm; /* font expansion uses the base font */
+ /* the following code would be obsolete, as would be mk_ex_fm() */
+ if (!is_t1fontfile (fm) || !is_included (fm)) {
+ pdftex_warn
+ ("font %s cannot be expanded (not an included Type1 font)",
+ tfm);
+ return (fmentryptr) dummy_fm_entry ();
+ }
+ exfm = mk_ex_fm (f, fm, e); /* copies all fields from fm except tfm name */
+ init_fm (exfm, f);
+ ai = avl_do_entry (exfm, FM_DUPIGNORE);
+ assert (ai == 0);
+ return (fmentryptr) exfm;
+ }
+ return (fmentryptr) dummy_fm_entry ();
+}
+
+/*
+ Early check whether a font file exists. Used e. g. for replacing fonts
+ of embedded PDF files: Without font file, the font within the embedded
+ PDF-file is used. Search tree ff_tree is used in 1st instance, as it
+ may be faster than the kpse_find_file(), and kpse_find_file() is called
+ only once per font file name + expansion parameter. This might help
+ keeping speed, if many PDF pages with same fonts are to be embedded.
+
+ The ff_tree contains only font files, which are actually needed,
+ so this tree typically is much smaller than the tfm_tree or ps_tree.
+*/
+
+ff_entry *check_ff_exist (fm_entry * fm)
+{
+ ff_entry *ff;
+ ff_entry tmp;
+ void **aa;
+
+ assert (fm->ff_name != NULL);
+ tmp.ff_name = fm->ff_name;
+ ff = (ff_entry *) avl_find (ff_tree, &tmp);
+ if (ff == NULL) { /* not yet in database */
+ ff = new_ff_entry ();
+ ff->ff_name = xstrdup (fm->ff_name);
+ if (is_truetype (fm))
+ ff->ff_path = kpse_find_file (fm->ff_name, kpse_truetype_format, 0);
+ else
+ ff->ff_path = kpse_find_file (fm->ff_name, kpse_type1_format, 0);
+ aa = avl_probe (ff_tree, ff);
+ assert (aa != NULL);
+ }
+ return ff;
+}
+
+/**********************************************************************/
+
+static boolean used_tfm (fm_entry * p)
+{
+ fontnumber f;
+ strnumber s;
+ ff_entry *ff;
+
+ /* check if the font file is not a TrueType font */
+ /* font replacement makes sense only for included Type1 files */
+ if (is_truetype (p) || !is_included (p))
+ return false;
+
+ /* check if the font file is available */
+ ff = check_ff_exist (p);
+ if (ff->ff_path == NULL)
+ return false;
+
+ /* check whether this font has been used */
+ if (fontsizes[p->tfm_num]!=0)
+ return true;
+ assert (p->tfm_name != NULL);
+
+ /* check whether we didn't find a loaded font yet,
+ * and this font has been loaded */
+ if (loaded_tfm_found == NULL && strcmp (p->tfm_name, nontfm)) {
+ s = maketexstring (p->tfm_name);
+ if ((f = tfmlookup (s, 0)) != getnullfont ()) {
+ loaded_tfm_found = p;
+ if (mpfontmap[f] == NULL)
+ mpfontmap[f] = (fmentryptr) p;
+ if (p->tfm_num == getnullfont ())
+ p->tfm_num = f;
+ assert (p->tfm_num == f);
+ /* don't call flushstr() here as it has been called by tfmlookup() */
+ } else
+ flushstr (s);
+ }
+
+ /* check whether we didn't find either a loaded or a loadable font yet,
+ * and this font is loadable */
+ if (avail_tfm_found == NULL && loaded_tfm_found == NULL &&
+ strcmp (p->tfm_name, nontfm)) {
+ if (p->tfm_avail == TFM_UNCHECKED) {
+ if (kpse_find_file (p->tfm_name, kpse_tfm_format, 0) != NULL) {
+ avail_tfm_found = p;
+ p->tfm_avail = TFM_FOUND;
+ } else {
+ p->tfm_avail = TFM_NOTFOUND;
+ if (not_avail_tfm_found == NULL)
+ not_avail_tfm_found = p;
+ }
+ }
+ }
+
+ /* check whether the current entry is a <nontfm> entry */
+ if (non_tfm_found == NULL && !strcmp (p->tfm_name, nontfm))
+ non_tfm_found = p;
+
+ return false;
+}
+
+/* lookup_ps_name looks for an entry with a given ps name + slant + extend;
+ * return NULL if not found.
+ *
+ * As there may exist several such entries, we need to select the `right'
+ * one. We do so by checking all such entries and return the first one that
+ * fulfils the following criteria (in descending priority):
+ *
+ * - the tfm has been used (some char from this font has been typeset)
+ * - the tfm has been loaded (but not used yet)
+ * - the tfm can be loaded (but not loaded yet)
+ * - the tfm is present in map files, but cannot be loaded. In this case a
+ * dummy tfm can be loaded instead, and a warning should be written out
+ */
+
+static fm_entry *lookup_ps_name (fm_entry * fm)
+{
+ fm_entry *p, *p2;
+ struct avl_traverser t, t2;
+ int a;
+
+ loaded_tfm_found = NULL;
+ avail_tfm_found = NULL;
+ non_tfm_found = NULL;
+ not_avail_tfm_found = NULL;
+
+ assert (fm->tfm_name == NULL);
+ p = (fm_entry *) avl_t_find (&t, ps_tree, fm);
+ if (p == NULL)
+ return NULL;
+ t2 = t;
+ p2 = (fm_entry *) avl_t_prev (&t2);
+
+ /* search forward */
+ do {
+ if (used_tfm (p))
+ return p;
+ p = (fm_entry *) avl_t_next (&t);
+ }
+ while (p != NULL && comp_fm_entry_ps (fm, p, NULL) == 0);
+
+ /* search backward */
+ while (p2 != NULL && comp_fm_entry_ps (fm, p2, NULL) == 0) {
+ if (used_tfm (p2))
+ return p2;
+ p2 = (fm_entry *) avl_t_prev (&t2);
+ }
+
+ if (loaded_tfm_found != NULL)
+ p = loaded_tfm_found;
+ else if (avail_tfm_found != NULL) {
+ /* TH: do not do this for metapost, there is no embedding anyway */
+ /* p = avail_tfm_found;
+ * p->tfm_num = readfontinfo (getnullcs (), maketexstring (p->tfm_name),
+ * getnullstr (), -1000);
+ * p->tfm_avail = TFM_FOUND;
+ */
+ } else if (non_tfm_found != NULL) {
+ p = non_tfm_found;
+ p->tfm_num = newdummyfont ();
+ p->tfm_avail = TFM_FOUND;
+ } else if (not_avail_tfm_found != NULL) {
+ p = not_avail_tfm_found;
+ pdftex_warn ("`%s' not loadable, use a dummy tfm instead", p->tfm_name);
+ p2 = new_fm_entry ();
+ p2->flags = p->flags;
+ p2->encoding = p->encoding;
+ p2->type = p->type;
+ p2->slant = p->slant;
+ p2->extend = p->extend;
+ p2->tfm_name = xstrdup (nontfm);
+ p2->ps_name = xstrdup (p->ps_name);
+ if (p->ff_name != NULL)
+ p2->ff_name = xstrdup (p->ff_name);
+ p2->tfm_num = newdummyfont ();
+ p2->tfm_avail = TFM_FOUND;
+ a = avl_do_entry (p2, FM_DUPIGNORE);
+ assert (a == 0);
+ p = p2;
+ } else
+ return NULL;
+ assert (p->tfm_num != getnullfont ());
+ return p;
+}
+
+
+/**********************************************************************/
+/*
+Process map file given by its name or map line contents. Items not
+beginning with [+-=] flush default map file, if it has not yet been
+read. Leading blanks and blanks immediately following [+-=] are ignored.
+*/
+
+void process_map_item (char *s, int type)
+{
+ char *p;
+ int mode;
+ if (*s == ' ')
+ s++; /* ignore leading blank */
+ switch (*s) {
+ case '+': /* +mapfile.map, +mapline */
+ mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
+ s++;
+ break;
+ case '=': /* =mapfile.map, =mapline */
+ mode = FM_REPLACE; /* try to replace earlier entry */
+ s++;
+ break;
+ case '-': /* -mapfile.map, -mapline */
+ mode = FM_DELETE; /* try to delete entry */
+ s++;
+ break;
+ default:
+ mode = FM_DUPIGNORE; /* like +, but also: */
+ mitem->line = NULL; /* flush default map file name */
+ }
+ if (*s == ' ')
+ s++; /* ignore blank after [+-=] */
+ p = s; /* map item starts here */
+ switch (type) {
+ case MAPFILE: /* remove blank at end */
+ while (*p != '\0' && *p != ' ')
+ p++;
+ *p = '\0';
+ break;
+ case MAPLINE: /* blank at end allowed */
+ break;
+ default:
+ assert (0);
+ }
+ if (mitem->line != NULL) /* read default map file first */
+ fm_read_info ();
+ if (*s != '\0') { /* only if real item to process */
+ mitem->mode = mode;
+ mitem->type = type;
+ mitem->line = s;
+ fm_read_info ();
+ }
+}
+
+void mpmapfile (strnumber t)
+{
+ char *s = xstrdup(makecstring (t));
+ process_map_item (s, MAPFILE);
+ xfree (s);
+}
+
+void mpmapline (strnumber t)
+{
+ char *s = xstrdup(makecstring (t));
+ process_map_item (s, MAPLINE);
+ xfree (s);
+}
+
+void mpinitmapfile (void)
+{
+ assert (mitem == NULL);
+ mitem = xtalloc (1, mapitem);
+ mitem->mode = FM_DUPIGNORE;
+ mitem->type = MAPFILE;
+ if (kpse_find_file("mpost.map", kpse_fontmap_format,0))
+ mitem->line = xstrdup ("mpost.map");
+ else
+ mitem->line = xstrdup ("pdftex.map");
+}
+
+/**********************************************************************/
+/* cleaning up... */
+
+static void destroy_fm_entry_tfm (void *pa, void *pb)
+{
+ fm_entry *fm;
+ fm = (fm_entry *) pa;
+ if (!has_pslink (fm))
+ delete_fm_entry (fm);
+ else
+ unset_tfmlink (fm);
+}
+static void destroy_fm_entry_ps (void *pa, void *pb)
+{
+ fm_entry *fm;
+ fm = (fm_entry *) pa;
+ if (!has_tfmlink (fm))
+ delete_fm_entry (fm);
+ else
+ unset_pslink (fm);
+}
+static void destroy_ff_entry (void *pa, void *pb)
+{
+ ff_entry *ff;
+ ff = (ff_entry *) pa;
+ delete_ff_entry (ff);
+} void fm_free (void)
+{
+ if (tfm_tree != NULL)
+ avl_destroy (tfm_tree, destroy_fm_entry_tfm);
+ if (ps_tree != NULL)
+ avl_destroy (ps_tree, destroy_fm_entry_ps);
+ if (ff_tree != NULL)
+ avl_destroy (ff_tree, destroy_ff_entry);
+}
+
+/**********************************************************************/
+/* end of mapfile.c */