diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/kpathsea/tex-file.c | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/kpathsea/tex-file.c')
-rw-r--r-- | Build/source/texk/kpathsea/tex-file.c | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/Build/source/texk/kpathsea/tex-file.c b/Build/source/texk/kpathsea/tex-file.c new file mode 100644 index 00000000000..6fabb311b9d --- /dev/null +++ b/Build/source/texk/kpathsea/tex-file.c @@ -0,0 +1,949 @@ +/* tex-file.c: high-level file searching by format. + + Copyright 1998-2005 Olaf Weber. + Copyright 1993, 94, 95, 96, 97 Karl Berry. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include <kpathsea/config.h> + +#include <kpathsea/c-fopen.h> +#include <kpathsea/c-pathch.h> +#include <kpathsea/c-vararg.h> +#include <kpathsea/cnf.h> +#include <kpathsea/concatn.h> +#include <kpathsea/default.h> +#include <kpathsea/expand.h> +#include <kpathsea/fontmap.h> +#include <kpathsea/paths.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/tex-file.h> +#include <kpathsea/tex-make.h> +#include <kpathsea/variable.h> + + +/* See tex-file.h. */ +const_string kpse_fallback_font = NULL; +const_string kpse_fallback_resolutions_string = NULL; +unsigned *kpse_fallback_resolutions = NULL; +kpse_format_info_type kpse_format_info[kpse_last_format]; + +/* These are not in the structure + because it's annoying to initialize lists in C. */ +#define GF_ENVS "GFFONTS", GLYPH_ENVS +#define PK_ENVS "PKFONTS", "TEXPKS", GLYPH_ENVS +#define GLYPH_ENVS "GLYPHFONTS", "TEXFONTS" +#define TFM_ENVS "TFMFONTS", "TEXFONTS" +#define AFM_ENVS "AFMFONTS", "TEXFONTS" +#define BASE_ENVS "MFBASES", "TEXMFINI" +#define BIB_ENVS "BIBINPUTS", "TEXBIB" +#define BST_ENVS "BSTINPUTS" +#define CNF_ENVS "TEXMFCNF" +#define DB_ENVS "TEXMFDBS" +#define FMT_ENVS "TEXFORMATS", "TEXMFINI" +#define FONTMAP_ENVS "TEXFONTMAPS", "TEXFONTS" +#define MEM_ENVS "MPMEMS", "TEXMFINI" +#define MF_ENVS "MFINPUTS" +#define MFPOOL_ENVS "MFPOOL", "TEXMFINI" +#define MFT_ENVS "MFTINPUTS" +#define MP_ENVS "MPINPUTS" +#define MPPOOL_ENVS "MPPOOL", "TEXMFINI" +#define MPSUPPORT_ENVS "MPSUPPORT" +#define OCP_ENVS "OCPINPUTS" +#define OFM_ENVS "OFMFONTS", "TEXFONTS" +#define OPL_ENVS "OPLFONTS", "TEXFONTS" +#define OTP_ENVS "OTPINPUTS" +#define OVF_ENVS "OVFFONTS", "TEXFONTS" +#define OVP_ENVS "OVPFONTS", "TEXFONTS" +#define PICT_ENVS "TEXPICTS", TEX_ENVS +#define TEX_ENVS "TEXINPUTS" +#define TEXDOC_ENVS "TEXDOCS" +#define TEXPOOL_ENVS "TEXPOOL", "TEXMFINI" +#define TEXSOURCE_ENVS "TEXSOURCES" +#define TEX_PS_HEADER_ENVS "TEXPSHEADERS", "PSHEADERS" +#define TROFF_FONT_ENVS "TRFONTS" +#define TYPE1_ENVS "T1FONTS", "T1INPUTS", "TEXFONTS", TEX_PS_HEADER_ENVS +#define VF_ENVS "VFFONTS", "TEXFONTS" +#define DVIPS_CONFIG_ENVS "TEXCONFIG" +#define IST_ENVS "TEXINDEXSTYLE", "INDEXSTYLE" +#define TRUETYPE_ENVS "TTFONTS", "TEXFONTS" +#define TYPE42_ENVS "T42FONTS", "TEXFONTS" +#define WEB2C_ENVS "WEB2C" +#define MISCFONTS_ENVS "MISCFONTS", "TEXFONTS" +#define WEB_ENVS "WEBINPUTS" +#define CWEB_ENVS "CWEBINPUTS" +#define ENC_ENVS "ENCFONTS", "TEXFONTS" +#define CMAP_ENVS "CMAPFONTS", "TEXFONTS" +#define SFD_ENVS "SFDFONTS", "TEXFONTS" +#define OPENTYPE_ENVS "OPENTYPEFONTS", "TEXFONTS" +#define PDFTEXCONFIG_ENVS "PDFTEXCONFIG" +#define LIG_ENVS "LIGFONTS", "TEXFONTS" +#define TEXMFSCRIPTS_ENVS "TEXMFSCRIPTS" + +/* The compiled-in default list, DEFAULT_FONT_SIZES, is intended to be + set from the command line (presumably via the Makefile). */ + +#ifndef DEFAULT_FONT_SIZES +#define DEFAULT_FONT_SIZES "" +#endif + +void +kpse_init_fallback_resolutions P1C(string, envvar) +{ + string size; + const_string size_var = ENVVAR (envvar, "TEXSIZES"); + string size_str = getenv (size_var); + unsigned *last_resort_sizes = NULL; + unsigned size_count = 0; + const_string default_sizes = kpse_fallback_resolutions_string + ? kpse_fallback_resolutions_string + : DEFAULT_FONT_SIZES; + string size_list = kpse_expand_default (size_str, default_sizes); + + /* Initialize the list of last-resort sizes. */ + for (size = kpse_path_element (size_list); size != NULL; + size = kpse_path_element (NULL)) + { + unsigned s; + if (! *size) /* Skip empty elements. */ + continue; + + s = atoi (size); + if (size_count && s < last_resort_sizes[size_count - 1]) { + WARNING1 ("kpathsea: last resort size %s not in ascending order, ignored", + size); + } else { + size_count++; + XRETALLOC (last_resort_sizes, size_count, unsigned); + last_resort_sizes[size_count - 1] = atoi (size); + } + } + + /* Add a zero to mark the end of the list. */ + size_count++; + XRETALLOC (last_resort_sizes, size_count, unsigned); + last_resort_sizes[size_count - 1] = 0; + + free (size_list); + + kpse_fallback_resolutions = last_resort_sizes; +} + +/* We should be able to set the program arguments in the same way. Not + to mention the path values themselves. */ + +void +kpse_set_program_enabled P3C(kpse_file_format_type, fmt, boolean, value, + kpse_src_type, level) +{ + kpse_format_info_type *f = &kpse_format_info[fmt]; + if (level >= f->program_enable_level) { + f->program_enabled_p = value; + f->program_enable_level = level; + } +} + + +/* Web2c and kpsewhich have command-line options to set this stuff. May + as well have a common place. */ + +void +kpse_maketex_option P2C(const_string, fmtname, boolean, value) +{ + kpse_file_format_type fmt = kpse_last_format; + + /* Trying to match up with the suffix lists unfortunately doesn't work + well, since that would require initializing the formats. */ + /* FIXME: Currently the function silently ignores unrecognized arguments.*/ + if (FILESTRCASEEQ (fmtname, "pk")) { + fmt = kpse_pk_format; + } else if (FILESTRCASEEQ (fmtname, "mf")) { + fmt = kpse_mf_format; + } else if (FILESTRCASEEQ (fmtname, "tex")) { + fmt = kpse_tex_format; + } else if (FILESTRCASEEQ (fmtname, "tfm")) { + fmt = kpse_tfm_format; + } else if (FILESTRCASEEQ (fmtname, "ofm")) { + fmt = kpse_ofm_format; + } else if (FILESTRCASEEQ (fmtname, "ocp")) { + fmt = kpse_ocp_format; + } + if (fmt != kpse_last_format) { + kpse_set_program_enabled (fmt, value, kpse_src_cmdline); + } +} + +/* Macro subroutines for `init_path'. TRY_ENV checks if an envvar ENAME + is set and non-null, and sets var to ENAME if so. */ +#define TRY_ENV(ename) do { \ + string evar = ename; \ +} while (0) + +/* And EXPAND_DEFAULT calls kpse_expand_default on try_path and the + present info->path. */ +#define EXPAND_DEFAULT(try_path, source_string) \ + if (try_path) { \ + info->raw_path = try_path; \ + info->path = kpse_expand_default (try_path, info->path); \ + info->path_source = source_string; \ + } + +/* Find the final search path to use for the format entry INFO, given + the compile-time default (DEFAULT_PATH), and the environment + variables to check (the remaining arguments, terminated with NULL). + We set the `path' and `path_source' members of INFO. The + `client_path' member must already be set upon entry. */ + +static void +init_path PVAR2C(kpse_format_info_type *, info, const_string, default_path, ap) +{ + string env_name; + string env_value = NULL; + string var = NULL; + + info->default_path = default_path; + + /* First envvar that's set to a nonempty value will exit the loop. If + none are set, we want the first cnf entry that matches. Find the + cnf entries simultaneously, to avoid having to go through envvar + list twice -- because of the PVAR?C macro, that would mean having + to create a str_list and then use it twice. Yuck. */ + while ((env_name = va_arg (ap, string)) != NULL) { + /* Since sh doesn't like envvar names with `.', check PATH_prog + as well as PATH.prog. */ + if (!var) { + /* Try PATH.prog. */ + string evar = concat3 (env_name, ".", kpse_program_name); + env_value = getenv (evar); + if (env_value && *env_value) { + var = evar; + } else { + free (evar); + /* Try PATH_prog. */ + evar = concat3 (env_name, "_", kpse_program_name); + env_value = getenv (evar); + if (env_value && *env_value) { + var = evar; + } else { + free (evar); + /* Try simply PATH. */ + env_value = getenv (env_name); + if (env_value && *env_value) { + var = env_name; + } + } + } + } + + /* If we are initializing the cnf path, don't try to get any + values from the cnf files; that's infinite loop time. */ + if (!info->cnf_path && info != &kpse_format_info[kpse_cnf_format]) + info->cnf_path = kpse_cnf_get (env_name); + + if (var && info->cnf_path) + break; + } + va_end (ap); + + /* Expand any extra :'s. For each level, we replace an extra : with + the path at the next lower level. For example, an extra : in a + user-set envvar should be replaced with the path from the cnf file. + things are complicated because none of the levels above the very + bottom are guaranteed to exist. */ + + /* Assume we can reliably start with the compile-time default. */ + info->path = info->raw_path = info->default_path; + info->path_source = "compile-time paths.h"; + + /* Translate ';' in the envvar into ':' if that's our ENV_SEP. */ + if (IS_ENV_SEP(':') && env_value) { + string loc; + env_value = xstrdup(env_value); /* Freed below. */ + for (loc = env_value; *loc; loc++) { + if (*loc == ';') + *loc = ':'; + } + } + + EXPAND_DEFAULT (info->cnf_path, "texmf.cnf"); + EXPAND_DEFAULT (info->client_path, "program config file"); + if (var) + EXPAND_DEFAULT (env_value, concat (var, " environment variable")); + EXPAND_DEFAULT (info->override_path, "application override variable"); + info->path = kpse_brace_expand (info->path); + + /* Free the copied env_value. */ + if (IS_ENV_SEP(':') && env_value) + free(env_value); +}} + + +/* Some file types have more than one suffix. */ +/* Some times it is convenient to modify the list of searched suffixes. + *** Don't complain if this function goes away. *** + */ +void +kpse_set_suffixes PVAR2C(kpse_file_format_type, format, + boolean, alternate, ap) +{ + const_string **list; + const_string s; + int count = 0; + + if (alternate) { + list = &kpse_format_info[format].alt_suffix; + } + else { + list = &kpse_format_info[format].suffix; + } + + while ((s = va_arg (ap, string)) != NULL) { + count++; + XRETALLOC (*list, count + 1, const_string); + (*list)[count - 1] = s; + } + va_end (ap); + (*list)[count] = NULL; + +}} + +/* The path spec we are defining, one element of the global array. */ +#define FMT_INFO kpse_format_info[format] +/* Call kpse_set_add_suffixes. */ +#define SUFFIXES(args) kpse_set_suffixes(format, false, args, NULL) +#define ALT_SUFFIXES(args) kpse_set_suffixes(format, true, args, NULL) + +/* Call `init_path', including appending the trailing NULL to the envvar + list. Also initialize the fields not needed in setting the path. */ +#define INIT_FORMAT(text, default_path, envs) \ + FMT_INFO.type = text; \ + init_path (&FMT_INFO, default_path, envs, NULL) + + +/* A few file types allow for runtime generation by an external program. + kpse_init_prog may have already initialized it (the `program' + member). Here we allow people to turn it off or on in the config + file, by setting the variable whose name is the uppercasified program + name to 0 or 1. */ + +static void +init_maketex PVAR2C(kpse_file_format_type, fmt, const_string, dflt_prog, ap) +{ + kpse_format_info_type *f = &kpse_format_info[fmt]; + const_string prog = f->program ? f->program : dflt_prog; /* mktexpk */ + string PROG = uppercasify (prog); /* MKTEXPK */ + string progval = kpse_var_value (PROG); /* ENV/cnf{"MKTEXPK"} */ + const_string arg; + + /* Doesn't hurt to always set this info. */ + f->program = prog; + + /* Set up the argument vector. */ + f->argc = 0; + f->argv = XTALLOC(2, const_string); + f->argv[f->argc++] = dflt_prog; + while ((arg = va_arg (ap, string)) != NULL) { + f->argc++; + XRETALLOC (f->argv, f->argc + 1, const_string); + f->argv[f->argc - 1] = arg; + } + f->argv[f->argc] = NULL; + + if (progval && *progval) { + /* This might actually be from an environment variable value, but in + that case, we'll have previously set it from kpse_init_prog. */ + kpse_set_program_enabled (fmt, *progval == '1', kpse_src_client_cnf); + } + + free (PROG); +}} + +/* We need this twice, so ... */ +#define MKTEXPK_ARGS \ + "--mfmode","$MAKETEX_MODE",\ + "--bdpi","$MAKETEX_BASE_DPI",\ + "--mag","$MAKETEX_MAG",\ + "--dpi","$KPATHSEA_DPI",\ + NULL + +static string +remove_dbonly P1C(const_string, path) +{ + string ret = XTALLOC(strlen (path) + 1, char), q=ret; + const_string p=path; + boolean new_elt=true; + + while (*p) { + if (new_elt && *p && *p == '!' && *(p+1) == '!') + p += 2; + else { + new_elt = (*p == ENV_SEP); + *q++ = *p++; + } + } + *q = '\0'; + return(ret); +} + +/* Initialize everything for FORMAT. */ + +const_string +kpse_init_format P1C(kpse_file_format_type, format) +{ + /* If we get called twice, don't redo all the work. */ + if (FMT_INFO.path) + return FMT_INFO.path; + + switch (format) + { /* We might be able to avoid repeating `gf' or whatever so many + times with token pasting, but it doesn't seem worth it. */ + case kpse_gf_format: + INIT_FORMAT ("gf", DEFAULT_GFFONTS, GF_ENVS); + SUFFIXES ("gf"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_pk_format: + init_maketex (format, "mktexpk", MKTEXPK_ARGS); + INIT_FORMAT ("pk", DEFAULT_PKFONTS, PK_ENVS); + SUFFIXES ("pk"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_any_glyph_format: + init_maketex (format, "mktexpk", MKTEXPK_ARGS); + INIT_FORMAT ("bitmap font", DEFAULT_GLYPHFONTS, GLYPH_ENVS); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_tfm_format: + /* Must come before kpse_ofm_format. */ + init_maketex (format, "mktextfm", NULL); + INIT_FORMAT ("tfm", DEFAULT_TFMFONTS, TFM_ENVS); + SUFFIXES (".tfm"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_afm_format: + INIT_FORMAT ("afm", DEFAULT_AFMFONTS, AFM_ENVS); + SUFFIXES (".afm"); + break; + case kpse_base_format: + init_maketex (format, "mktexfmt", NULL); + INIT_FORMAT ("base", DEFAULT_MFBASES, BASE_ENVS); + SUFFIXES (".base"); + FMT_INFO.binmode = true; + break; + case kpse_bib_format: + INIT_FORMAT ("bib", DEFAULT_BIBINPUTS, BIB_ENVS); + SUFFIXES (".bib"); + FMT_INFO.suffix_search_only = true; + break; + case kpse_bst_format: + INIT_FORMAT ("bst", DEFAULT_BSTINPUTS, BST_ENVS); + SUFFIXES (".bst"); + break; + case kpse_cnf_format: + INIT_FORMAT ("cnf", DEFAULT_TEXMFCNF, CNF_ENVS); + SUFFIXES (".cnf"); + break; + case kpse_db_format: + INIT_FORMAT ("ls-R", DEFAULT_TEXMFDBS, DB_ENVS); +#define LSR_SUFFIXES "ls-R", "ls-r" + SUFFIXES (LSR_SUFFIXES); + FMT_INFO.path = remove_dbonly (FMT_INFO.path); + break; + case kpse_fmt_format: + init_maketex (format, "mktexfmt", NULL); + INIT_FORMAT ("fmt", DEFAULT_TEXFORMATS, FMT_ENVS); + SUFFIXES (".fmt"); +#define FMT_SUFFIXES ".efmt",".efm",".ofmt",".ofm",".oft",".eofmt",".eoft",".eof",".pfmt",".pfm",".epfmt",".epf",".xpfmt",".xpf",".afmt",".afm" + ALT_SUFFIXES (FMT_SUFFIXES); + FMT_INFO.binmode = true; + break; + case kpse_fontmap_format: + INIT_FORMAT ("map", DEFAULT_TEXFONTMAPS, FONTMAP_ENVS); + SUFFIXES (".map"); + break; + case kpse_mem_format: + init_maketex (format, "mktexfmt", NULL); + INIT_FORMAT ("mem", DEFAULT_MPMEMS, MEM_ENVS); + SUFFIXES (".mem"); + FMT_INFO.binmode = true; + break; + case kpse_mf_format: + init_maketex (format, "mktexmf", NULL); + INIT_FORMAT ("mf", DEFAULT_MFINPUTS, MF_ENVS); + SUFFIXES (".mf"); + break; + case kpse_mft_format: + INIT_FORMAT ("mft", DEFAULT_MFTINPUTS, MFT_ENVS); + SUFFIXES (".mft"); + break; + case kpse_mfpool_format: + INIT_FORMAT ("mfpool", DEFAULT_MFPOOL, MFPOOL_ENVS); + SUFFIXES (".pool"); + break; + case kpse_mp_format: + INIT_FORMAT ("mp", DEFAULT_MPINPUTS, MP_ENVS); + SUFFIXES (".mp"); + break; + case kpse_mppool_format: + INIT_FORMAT ("mppool", DEFAULT_MPPOOL, MPPOOL_ENVS); + SUFFIXES (".pool"); + break; + case kpse_mpsupport_format: + INIT_FORMAT ("MetaPost support", DEFAULT_MPSUPPORT, MPSUPPORT_ENVS); + break; + case kpse_ocp_format: + init_maketex (format, "mkocp", NULL); + INIT_FORMAT ("ocp", DEFAULT_OCPINPUTS, OCP_ENVS); + SUFFIXES (".ocp"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_ofm_format: + init_maketex (format, "mkofm", NULL); + INIT_FORMAT ("ofm", DEFAULT_OFMFONTS, OFM_ENVS); +#define OFM_SUFFIXES ".ofm", ".tfm" + SUFFIXES (OFM_SUFFIXES); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_opl_format: + INIT_FORMAT ("opl", DEFAULT_OPLFONTS, OPL_ENVS); + SUFFIXES (".opl"); + FMT_INFO.suffix_search_only = true; + break; + case kpse_otp_format: + INIT_FORMAT ("otp", DEFAULT_OTPINPUTS, OTP_ENVS); + SUFFIXES (".otp"); + FMT_INFO.suffix_search_only = true; + break; + case kpse_ovf_format: + INIT_FORMAT ("ovf", DEFAULT_OVFFONTS, OVF_ENVS); + SUFFIXES (".ovf"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_ovp_format: + INIT_FORMAT ("ovp", DEFAULT_OVPFONTS, OVP_ENVS); + SUFFIXES (".ovp"); + FMT_INFO.suffix_search_only = true; + break; + case kpse_pict_format: + INIT_FORMAT ("graphic/figure", DEFAULT_TEXINPUTS, PICT_ENVS); +#define PICT_SUFFIXES ".eps", ".epsi" + ALT_SUFFIXES (PICT_SUFFIXES); + FMT_INFO.binmode = true; + break; + case kpse_tex_format: + init_maketex (format, "mktextex", NULL); + INIT_FORMAT ("tex", DEFAULT_TEXINPUTS, TEX_ENVS); + SUFFIXES (".tex"); + /* We don't maintain a list of alternate TeX suffixes. Such a list + could never be complete. */ + break; + case kpse_tex_ps_header_format: + INIT_FORMAT ("PostScript header", DEFAULT_TEXPSHEADERS, + TEX_PS_HEADER_ENVS); +/* Unfortunately, dvipsk uses this format for type1 fonts. */ +#define TEXPSHEADER_SUFFIXES ".pro" + ALT_SUFFIXES (TEXPSHEADER_SUFFIXES); + FMT_INFO.binmode = true; + break; + case kpse_texdoc_format: + INIT_FORMAT ("TeX system documentation", DEFAULT_TEXDOCS, TEXDOC_ENVS); + break; + case kpse_texpool_format: + INIT_FORMAT ("texpool", DEFAULT_TEXPOOL, TEXPOOL_ENVS); + SUFFIXES (".pool"); + break; + case kpse_texsource_format: + INIT_FORMAT ("TeX system sources", DEFAULT_TEXSOURCES, TEXSOURCE_ENVS); + break; + case kpse_troff_font_format: + INIT_FORMAT ("Troff fonts", DEFAULT_TRFONTS, TROFF_FONT_ENVS); + FMT_INFO.binmode = true; + break; + case kpse_type1_format: + INIT_FORMAT ("type1 fonts", DEFAULT_T1FONTS, TYPE1_ENVS); +#define TYPE1_SUFFIXES ".pfa", ".pfb" + SUFFIXES (TYPE1_SUFFIXES); + FMT_INFO.binmode = true; + break; + case kpse_vf_format: + INIT_FORMAT ("vf", DEFAULT_VFFONTS, VF_ENVS); + SUFFIXES (".vf"); + FMT_INFO.suffix_search_only = true; + FMT_INFO.binmode = true; + break; + case kpse_dvips_config_format: + INIT_FORMAT ("dvips config", DEFAULT_TEXCONFIG, DVIPS_CONFIG_ENVS); + break; + case kpse_ist_format: + INIT_FORMAT ("ist", DEFAULT_INDEXSTYLE, IST_ENVS); + SUFFIXES (".ist"); + break; + case kpse_truetype_format: + INIT_FORMAT ("truetype fonts", DEFAULT_TTFONTS, TRUETYPE_ENVS); +#define TRUETYPE_SUFFIXES ".ttf", ".ttc", ".TTF", ".TTC" + SUFFIXES (TRUETYPE_SUFFIXES); + FMT_INFO.suffix_search_only = false; + FMT_INFO.binmode = true; + break; + case kpse_type42_format: + INIT_FORMAT ("type42 fonts", DEFAULT_T42FONTS, TYPE42_ENVS); + FMT_INFO.binmode = true; + break; + case kpse_web2c_format: + INIT_FORMAT ("web2c files", DEFAULT_WEB2C, WEB2C_ENVS); + break; + case kpse_program_text_format: + INIT_FORMAT ("other text files", + concatn (".", ENV_SEP_STRING, "$TEXMF/", + kpse_program_name, "//", NULL), + concat (uppercasify (kpse_program_name), "INPUTS")); + break; + case kpse_program_binary_format: + INIT_FORMAT ("other binary files", + concatn (".", ENV_SEP_STRING, "$TEXMF/", + kpse_program_name, "//", NULL), + concat (uppercasify (kpse_program_name), "INPUTS")); + FMT_INFO.binmode = true; + break; + case kpse_miscfonts_format: + INIT_FORMAT ("misc fonts", DEFAULT_MISCFONTS, MISCFONTS_ENVS); + FMT_INFO.binmode = true; + break; + case kpse_web_format: + INIT_FORMAT ("web", DEFAULT_WEBINPUTS, WEB_ENVS); + SUFFIXES (".web"); + ALT_SUFFIXES (".ch"); + break; + case kpse_cweb_format: + INIT_FORMAT ("cweb", DEFAULT_CWEBINPUTS, CWEB_ENVS); +#define CWEB_SUFFIXES ".w", ".web" + SUFFIXES (CWEB_SUFFIXES); + ALT_SUFFIXES (".ch"); + break; + case kpse_enc_format: + INIT_FORMAT ("enc files", DEFAULT_ENCFONTS, ENC_ENVS); + SUFFIXES (".enc"); + break; + case kpse_cmap_format: + INIT_FORMAT ("cmap files", DEFAULT_CMAPFONTS, CMAP_ENVS); + SUFFIXES (".cmap"); + break; + case kpse_sfd_format: + INIT_FORMAT ("subfont definition files", DEFAULT_SFDFONTS, SFD_ENVS); + SUFFIXES (".sfd"); + break; + case kpse_opentype_format: + INIT_FORMAT ("opentype fonts", DEFAULT_OPENTYPEFONTS, OPENTYPE_ENVS); + SUFFIXES (".otf"); + FMT_INFO.binmode = true; + break; + case kpse_pdftex_config_format: + INIT_FORMAT ("pdftex config", DEFAULT_PDFTEXCONFIG, PDFTEXCONFIG_ENVS); + break; + case kpse_lig_format: + INIT_FORMAT ("lig files", DEFAULT_LIGFONTS, LIG_ENVS); + SUFFIXES (".lig"); + break; + case kpse_texmfscripts_format: + INIT_FORMAT ("texmfscripts", DEFAULT_TEXMFSCRIPTS, TEXMFSCRIPTS_ENVS); + break; + default: + FATAL1 ("kpse_init_format: Unknown format %d", format); + } + +#ifdef KPSE_DEBUG +#define MAYBE(member) (FMT_INFO.member ? FMT_INFO.member : "(none)") + + /* Describe the monster we've created. */ + if (KPSE_DEBUG_P (KPSE_DEBUG_PATHS)) + { + DEBUGF2 ("Search path for %s files (from %s)\n", + FMT_INFO.type, FMT_INFO.path_source); + DEBUGF1 (" = %s\n", FMT_INFO.path); + DEBUGF1 (" before expansion = %s\n", FMT_INFO.raw_path); + DEBUGF1 (" application override path = %s\n", MAYBE (override_path)); + DEBUGF1 (" application config file path = %s\n", MAYBE (client_path)); + DEBUGF1 (" texmf.cnf path = %s\n", MAYBE (cnf_path)); + DEBUGF1 (" compile-time path = %s\n", MAYBE (default_path)); + DEBUGF (" default suffixes ="); + if (FMT_INFO.suffix) { + const_string *ext; + for (ext = FMT_INFO.suffix; ext && *ext; ext++) { + fprintf (stderr, " %s", *ext); + } + putc ('\n', stderr); + } else { + fputs (" (none)\n", stderr); + } + DEBUGF (" other suffixes ="); + if (FMT_INFO.alt_suffix) { + const_string *alt; + for (alt = FMT_INFO.alt_suffix; alt && *alt; alt++) { + fprintf (stderr, " %s", *alt); + } + putc ('\n', stderr); + } else { + fputs (" (none)\n", stderr); + } + DEBUGF1 (" search only with suffix = %d\n",FMT_INFO.suffix_search_only); + DEBUGF1 (" numeric format value = %d\n", format); + DEBUGF1 (" runtime generation program = %s\n", MAYBE (program)); + DEBUGF (" runtime generation command ="); + if (FMT_INFO.argv) { + const_string *arg; + for (arg = FMT_INFO.argv; *arg; arg++) { + fprintf (stderr, " %s", *arg); + } + putc ('\n', stderr); + } else { + fputs(" (none)\n", stderr); + } + DEBUGF1 (" program enabled = %d\n", FMT_INFO.program_enabled_p); + DEBUGF1 (" program enable level = %d\n", FMT_INFO.program_enable_level); + } +#endif /* KPSE_DEBUG */ + + return FMT_INFO.path; +} + +/* Look up a file NAME of type FORMAT, and the given MUST_EXIST. This + initializes the path spec for FORMAT if it's the first lookup of that + type. Return the filename found, or NULL. This is the most likely + thing for clients to call. */ + +string +kpse_find_file P3C(const_string, name, kpse_file_format_type, format, + boolean, must_exist) +{ + const_string *ext; + unsigned name_len = 0; + boolean name_has_suffix_already = false; + string mapped_name; + string *mapped_names; + const_string *target; + unsigned count; + boolean use_fontmaps = (format == kpse_tfm_format + || format == kpse_gf_format + || format == kpse_pk_format + || format == kpse_ofm_format); + string ret = NULL; + + /* NAME being NULL is a programming bug somewhere. NAME can be empty, + though; this happens with constructs like `\input\relax'. */ + assert (name); + + if (FMT_INFO.path == NULL) + kpse_init_format (format); + + if (KPSE_DEBUG_P(KPSE_DEBUG_SEARCH)) + DEBUGF3 ("kpse_find_file: searching for %s of type %s (from %s)\n", + name, FMT_INFO.type, FMT_INFO.path_source); + + /* Do variable and tilde expansion. */ + name = kpse_expand(name); + + /* Does NAME already end in a possible suffix? */ + name_len = strlen (name); + if (FMT_INFO.suffix) { + for (ext = FMT_INFO.suffix; !name_has_suffix_already && *ext; ext++) { + unsigned suffix_len = strlen (*ext); + name_has_suffix_already = (name_len >= suffix_len + && FILESTRCASEEQ (*ext, name + name_len - suffix_len)); + } + } + if (!name_has_suffix_already && FMT_INFO.alt_suffix) { + for (ext = FMT_INFO.alt_suffix; !name_has_suffix_already && *ext; ext++) { + unsigned suffix_len = strlen (*ext); + name_has_suffix_already = (name_len >= suffix_len + && FILESTRCASEEQ (*ext, name + name_len - suffix_len)); + } + } + + /* Set up target list. */ + count = 0; + target = XTALLOC1 (const_string); + /* Case #1: NAME doesn't have a suffix which is equal to a "standard" + suffix. For example, foo.bar, but not foo.tex. We look for the + name with the standard suffixes appended. */ + if (!name_has_suffix_already && FMT_INFO.suffix) { + for (ext = FMT_INFO.suffix; *ext; ext++) { + string name_with_suffix = concat (name, *ext); + target[count++] = name_with_suffix; + XRETALLOC(target, count+1, const_string); + if (use_fontmaps + && (mapped_names = kpse_fontmap_lookup (name_with_suffix)) != NULL) + { + /* FIXME: we leak mapped_names and its elements, some of the time */ + while ((mapped_name = *mapped_names++) != NULL) { + target[count++] = xstrdup (mapped_name); + XRETALLOC(target, count+1, const_string); + } + } + } + } + /* Case #2: Just look for the name we've been given, provided non-suffix + searches are allowed or the name already includes a suffix. */ + if (name_has_suffix_already || !FMT_INFO.suffix_search_only) { + target[count++] = xstrdup (name); + XRETALLOC(target, count+1, const_string); + if (use_fontmaps && (mapped_names = kpse_fontmap_lookup (name)) != NULL) { + /* FIXME: we leak mapped_names and its elements, some of the time */ + while ((mapped_name = *mapped_names++) != NULL) { + target[count++] = xstrdup (mapped_name); + XRETALLOC(target, count+1, const_string); + } + } + } + /* Terminate list. */ + target[count] = NULL; + + /* Search. */ +#if 0 + /* Simple version, just do the search for the list, and pound disk + * then and there if appropriate. + */ + ret = kpse_path_search_list (FMT_INFO.path, target, must_exist); +#elif 0 + /* Variant where we delay disk-pounding. */ + ret = kpse_path_search_list (FMT_INFO.path, target, false); + if (!ret && must_exist) + ret = kpse_path_search_list (FMT_INFO.path, target, true); +#else + /* Variant that tries the match the original behaviour more closely. + * The distinction is that we pound the disk for a far shorter list + * of names. + * + * This is the fastest variant, because it does fewer disk accesses + * than the two variants above -- for example some 750 calls of + * access(2) compared to 1500. + */ + ret = kpse_path_search_list (FMT_INFO.path, target, false); + /* Do we need to pound the disk? */ + if (!ret && must_exist) { + for (count = 0; target[count]; count++) + free((void*)target[count]); + count = 0; + /* We look for a subset of the previous set of names, so the + * target array is large enough. In particular, we don't pound + * the disk for alternate names from the fontmaps. Perhaps we + * should? + */ + if (!name_has_suffix_already && FMT_INFO.suffix_search_only) { + for (ext = FMT_INFO.suffix; !ret && *ext; ext++) + target[count++] = concat (name, *ext); + } + if (name_has_suffix_already || !FMT_INFO.suffix_search_only) { + target[count++] = xstrdup (name); + } + target[count] = NULL; + ret = kpse_path_search_list (FMT_INFO.path, target, true); + } +#endif + + /* Free the list we created. */ + for (count = 0; target[count]; count++) + free((void*)target[count]); + free(target); + + /* If nothing was found, call mktex* to create a missing file. */ + if (!ret && must_exist) { + ret = kpse_make_tex (format, name); + } + + free((void*)name); + + return ret; +} + +/* Open NAME along the search path for TYPE for reading and return the + resulting file, or exit with an error message. */ + +FILE * +kpse_open_file P2C(const_string, name, kpse_file_format_type, type) +{ + string fullname = kpse_find_file (name, type, true); + const_string mode = kpse_format_info[type].binmode + ? FOPEN_RBIN_MODE + : FOPEN_R_MODE; + FILE *f = fullname ? fopen (fullname, mode) : NULL; + if (!f) { + if (fullname) { + perror (fullname); + exit (1); + } else { + FATAL2 ("%s file `%s' not found", kpse_format_info[type].type, name); + } + } + + return f; +} + +/* When using the %&<format> construct, we'd like to use the paths for + that format, rather than those for the name we were called with. + Of course this happens after various initializations have been + performed, so we have this function to force the issue. Note that + the paths for kpse_cnf_format and kpse_db_format are not cleared. + + This function is defined here, and not in progname.c, because it + need kpse_format_info, and would cause all of tex-file to be pulled + in by programs that do not need it. */ +void +kpse_reset_program_name P1C(const_string, progname) +{ + int i; + + /* It is a fatal error for either of these to be NULL. */ + assert (progname && kpse_program_name); + /* Do nothing if the name is unchanged. */ + if (STREQ(kpse_program_name, progname)) + return; + + free (kpse_program_name); + kpse_program_name = xstrdup (progname); + xputenv("progname", kpse_program_name); + + /* Clear paths -- do we want the db path to be cleared? */ + for (i = 0; i != kpse_last_format; ++i) { + /* Do not erase the cnf of db paths. This means that the filename + database is not rebuilt, nor are different configuration files + searched. The alternative is to tolerate a memory leak of up + to 100k if this function is called. */ + if (i == kpse_cnf_format || i == kpse_db_format) + continue; + /* Wipe the path (it is tested) and the cnf_path and because their + values may differ with the new program name. */ + if (kpse_format_info[i].path != NULL) { + free ((string)kpse_format_info[i].path); + kpse_format_info[i].path = NULL; + } + /* We cannot free the cnf_path: it points into the cnf hash, which + means all hell will break loose if we did. */ + if (kpse_format_info[i].cnf_path != NULL) { + kpse_format_info[i].cnf_path = NULL; + } + /* We do not wipe the override_path at this point, though arguably + we should provide new values. It is not likely to matter for + the programs that call this function. */ + } +} |