summaryrefslogtreecommitdiff
path: root/Build/source/texk/kpathsea/tex-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/kpathsea/tex-file.c')
-rw-r--r--Build/source/texk/kpathsea/tex-file.c1480
1 files changed, 1480 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..335f13b45f4
--- /dev/null
+++ b/Build/source/texk/kpathsea/tex-file.c
@@ -0,0 +1,1480 @@
+/* tex-file.c: high-level file searching by format.
+
+ Copyright 1993, 1994, 1995, 1996, 1997, 2007, 2008, 2009, 2010, 2011
+ 2012, 2014, 2016, 2017, 2019 Karl Berry.
+ Copyright 1998-2005 Olaf Weber.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/c-pathch.h>
+#include <stdarg.h>
+#include <kpathsea/cnf.h>
+#include <kpathsea/absolute.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>
+#include <kpathsea/c-ctype.h>
+
+/* 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"
+#define LUA_ENVS "LUAINPUTS"
+#define FONTFEATURES_ENVS "FONTFEATURES"
+#define FONTCIDMAPS_ENVS "FONTCIDMAPS"
+#define MLBIB_ENVS "MLBIBINPUTS", BIB_ENVS
+#define MLBST_ENVS "MLBSTINPUTS", BST_ENVS
+#define CLUA_ENVS "CLUAINPUTS"
+#define RIS_ENVS "RISINPUTS"
+#define BLTXML_ENVS "BLTXMLINPUTS"
+
+/* 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
+kpathsea_init_fallback_resolutions (kpathsea kpse, 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 = kpathsea_expand_default (kpse, size_str, default_sizes);
+
+ /* Initialize the list of last-resort sizes. */
+ for (size = kpathsea_path_element (kpse, size_list); size != NULL;
+ size = kpathsea_path_element (kpse, 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;
+}
+
+#if defined (KPSE_COMPAT_API)
+void
+kpse_init_fallback_resolutions ( string envvar)
+{
+ kpathsea_init_fallback_resolutions (kpse_def, envvar);
+}
+#endif
+
+
+/* We should be able to set the program arguments in the same way. Not
+ to mention the path values themselves. */
+
+void
+kpathsea_set_program_enabled (kpathsea kpse, 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;
+ }
+}
+
+
+#if defined (KPSE_COMPAT_API)
+void
+kpse_set_program_enabled (kpse_file_format_type fmt,
+ boolean value, kpse_src_type level)
+{
+ kpathsea_set_program_enabled (kpse_def, fmt, value, level);
+}
+
+#endif
+
+
+/* Web2c and kpsewhich have command-line options to set this stuff. May
+ as well have a common place. */
+
+void
+kpathsea_maketex_option (kpathsea kpse, 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. */
+ 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, "fmt")) {
+ fmt = kpse_fmt_format;
+ } else if (FILESTRCASEEQ (fmtname, "ofm")) {
+ fmt = kpse_ofm_format;
+ } else if (FILESTRCASEEQ (fmtname, "ocp")) {
+ fmt = kpse_ocp_format;
+ } else {
+ fprintf (stderr, "\nkpathsea: Unknown mktex format: %s\n", fmtname);
+ }
+
+ if (fmt != kpse_last_format) {
+ kpathsea_set_program_enabled (kpse, fmt, value, kpse_src_cmdline);
+ }
+}
+
+#if defined (KPSE_COMPAT_API)
+void
+kpse_maketex_option (const_string fmtname, boolean value)
+{
+ kpathsea_maketex_option (kpse_def, fmtname, value);
+}
+#endif
+
+
+/* Macro subroutine for `init_path'. 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; \
+ tmp = info->path; \
+ info->path = kpathsea_expand_default (kpse, try_path, info->path); \
+ free (tmp); \
+ 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 (kpathsea kpse, kpse_format_info_type *info,
+ const_string default_path, ...)
+{
+ string env_name;
+ string env_value = NULL;
+ string var = NULL;
+ string tmp;
+ va_list ap;
+
+ info->default_path = default_path;
+
+ va_start (ap, 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 value simultaneously with the envvar value, to avoid having to
+ go through the envvar list twice,
+ that would mean having to create a str_list and use it twice. */
+ 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 { /* Try PATH_prog. */
+ free (evar);
+ evar = concat3 (env_name, "_", kpse->program_name);
+ env_value = getenv (evar);
+ if (env_value && *env_value) {
+ var = evar;
+ } else { /* Try simply PATH. */
+ free (evar);
+ 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 = kpathsea_cnf_get (kpse, 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->raw_path = info->default_path;
+ info->path = xstrdup (info->raw_path);
+ info->path_source = "compile-time paths.h";
+
+ EXPAND_DEFAULT (info->cnf_path, "texmf.cnf");
+ EXPAND_DEFAULT (info->client_path, "program config file");
+
+ if (var) {
+ /* Translate `;' in the envvar into `:' if that's our ENV_SEP. */
+ if (IS_ENV_SEP (':')) {
+ string loc;
+ env_value = xstrdup (env_value); /* Freed below. */
+ for (loc = env_value; *loc; loc++) {
+ if (*loc == ';')
+ *loc = ':';
+ }
+ }
+ EXPAND_DEFAULT (env_value, concat (var, " environment variable"));
+ /* Do not free the copied env_value, because EXPAND_DEFAULT set
+ raw_path to point to it. If it gets overwritten again, tough. */
+ }
+
+ EXPAND_DEFAULT (info->override_path, "application override variable");
+ tmp = info->path;
+ info->path = kpathsea_brace_expand (kpse, info->path);
+ free (tmp);
+}
+
+
+/* Some file types have more than one suffix, and sometimes it is
+ convenient to modify the list of searched suffixes. */
+
+static void
+kpathsea_set_suffixes_va_list (kpathsea kpse, kpse_file_format_type format,
+ boolean alternate, va_list 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++;
+ /* This is essentially
+ XRETALLOC (*list, count + 1, const_string);
+ except that MSVC warns without the cast to `void *'. */
+ *list = (const_string *) xrealloc ((void *) *list,
+ (count + 1) * sizeof(const_string));
+ (*list)[count - 1] = s;
+ }
+ (*list)[count] = NULL;
+}
+
+void
+kpathsea_set_suffixes (kpathsea kpse, kpse_file_format_type format,
+ boolean alternate, ...)
+{
+ va_list ap;
+ va_start (ap, alternate);
+ kpathsea_set_suffixes_va_list (kpse, format, alternate, ap);
+ va_end (ap);
+}
+
+
+#if defined (KPSE_COMPAT_API)
+void
+kpse_set_suffixes (kpse_file_format_type format,
+ boolean alternate, ...)
+{
+ va_list ap;
+ va_start (ap, alternate);
+ kpathsea_set_suffixes_va_list (kpse_def, format, alternate, ap);
+ va_end (ap);
+}
+#endif
+
+
+/* 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) kpathsea_set_suffixes(kpse, format, false, args, NULL)
+#define ALT_SUFFIXES(args) kpathsea_set_suffixes(kpse, 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 (kpse, &FMT_INFO, default_path, envs, NULL); \
+ envvar_list = concatn_with_spaces (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 (kpathsea kpse, kpse_file_format_type fmt,
+ const_string dflt_prog, ...)
+{
+ 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 = kpathsea_var_value (kpse, PROG); /* $ENV/cnf{"MKTEXPK"} */
+ const_string arg;
+ va_list ap;
+
+ /* 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;
+ va_start (ap, dflt_prog);
+ while ((arg = va_arg (ap, string)) != NULL) {
+ f->argc++;
+ f->argv = (const_string *) xrealloc ((void *) f->argv,
+ (f->argc + 1) * sizeof(const_string));
+ f->argv[f->argc - 1] = arg;
+ }
+ va_end (ap);
+ 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. */
+ kpathsea_set_program_enabled (kpse, 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 (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);
+}
+
+/* Same as concatn but puts a space between each element. All this just
+ for nice debugging output. But it's useful. */
+
+static string
+concatn_with_spaces (const_string str1, ...)
+{
+ string arg;
+ string ret;
+ va_list ap;
+
+ if (!str1)
+ return NULL;
+
+ ret = xstrdup (str1);
+
+ va_start (ap, str1);
+ while ((arg = va_arg (ap, string)) != NULL)
+ {
+ string temp = concat3 (ret, " ", arg);
+ free (ret);
+ ret = temp;
+ }
+ va_end (ap);
+
+ return ret;
+}
+
+
+/* Initialize everything for FORMAT. Return its search path. */
+
+const_string
+kpathsea_init_format (kpathsea kpse, kpse_file_format_type format)
+{
+ /* If we get called twice, don't redo all the work. */
+ if (! FMT_INFO.path) {
+ /* Don't care about the list of variable names. */
+ (void) kpathsea_init_format_return_varlist (kpse, format);
+ }
+
+ return FMT_INFO.path;
+}
+
+/* Initialize everything for FORMAT. Return the list of
+ environment/config variable names considered, which is not otherwise
+ saved. Although in principle we could add that list to our format
+ struct, it seems a waste, since this is only used by kpsewhich --help. */
+
+const_string
+kpathsea_init_format_return_varlist(kpathsea kpse,kpse_file_format_type format)
+{
+ string envvar_list; /* only for debug output, set in INIT_FORMAT */
+
+ 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 (kpse, 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 (kpse, 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 (kpse, 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 (kpse, 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 (kpse, format, "mktexfmt", NULL);
+ INIT_FORMAT ("fmt", DEFAULT_TEXFORMATS, FMT_ENVS);
+ SUFFIXES (".fmt");
+ 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 (kpse, format, "mktexfmt", NULL);
+ INIT_FORMAT ("mem", DEFAULT_MPMEMS, MEM_ENVS);
+ SUFFIXES (".mem");
+ FMT_INFO.binmode = true;
+ break;
+ case kpse_mf_format:
+ init_maketex (kpse, 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 (kpse, 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 (kpse, 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");
+ ALT_SUFFIXES (".pl");
+ 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);
+#define OVF_SUFFIXES ".ovf", ".vf"
+ SUFFIXES (OVF_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ FMT_INFO.binmode = true;
+ break;
+ case kpse_ovp_format:
+ INIT_FORMAT ("ovp", DEFAULT_OVPFONTS, OVP_ENVS);
+ SUFFIXES (".ovp");
+ ALT_SUFFIXES (".vpl");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_pict_format:
+ INIT_FORMAT ("graphic/figure", DEFAULT_TEXINPUTS, PICT_ENVS);
+#define ALT_PICT_SUFFIXES ".eps", ".epsi"
+ ALT_SUFFIXES (ALT_PICT_SUFFIXES);
+ FMT_INFO.binmode = true;
+ break;
+ case kpse_tex_format:
+ init_maketex (kpse, format, "mktextex", NULL);
+ INIT_FORMAT ("tex", DEFAULT_TEXINPUTS, TEX_ENVS);
+ SUFFIXES (".tex");
+ /* TeX files can have any obscure suffix in the world (or none at
+ all). Only check for the most common ones. */
+#define ALT_TEX_SUFFIXES ".sty",".cls",".fd",".aux",".bbl",".def",".clo",".ldf"
+ ALT_SUFFIXES (ALT_TEX_SUFFIXES);
+ break;
+ case kpse_tex_ps_header_format:
+ INIT_FORMAT ("PostScript header", DEFAULT_TEXPSHEADERS,
+ TEX_PS_HEADER_ENVS);
+/* Unfortunately, at one time dvips used this format for type1 fonts. */
+#define ALT_TEXPSHEADER_SUFFIXES ".pro"
+ ALT_SUFFIXES (ALT_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);
+#define ALT_SOURCES_SUFFIXES ".dtx", ".ins"
+ ALT_SUFFIXES (ALT_SOURCES_SUFFIXES);
+ 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", ".dfont"
+ 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);
+#define TYPE42_SUFFIXES ".t42", ".T42"
+ SUFFIXES (TYPE42_SUFFIXES);
+ 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", DIR_SEP_STRING,
+ kpse->program_name,
+ DIR_SEP_STRING, DIR_SEP_STRING, NULL),
+ concat (uppercasify (kpse->program_name), "INPUTS"));
+ break;
+ case kpse_program_binary_format:
+ INIT_FORMAT ("other binary files",
+ concatn (".", ENV_SEP_STRING, "$TEXMF", DIR_SEP_STRING,
+ kpse->program_name,
+ DIR_SEP_STRING, DIR_SEP_STRING, 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");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_cmap_format:
+ INIT_FORMAT ("cmap files", DEFAULT_CMAPFONTS, CMAP_ENVS);
+ break;
+ case kpse_sfd_format:
+ INIT_FORMAT ("subfont definition files", DEFAULT_SFDFONTS, SFD_ENVS);
+ SUFFIXES (".sfd");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_opentype_format:
+ INIT_FORMAT ("opentype fonts", DEFAULT_OPENTYPEFONTS, OPENTYPE_ENVS);
+#define OPENTYPE_SUFFIXES ".otf", ".OTF"
+ SUFFIXES (OPENTYPE_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ 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");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_texmfscripts_format:
+ INIT_FORMAT ("texmfscripts", DEFAULT_TEXMFSCRIPTS, TEXMFSCRIPTS_ENVS);
+ break;
+ case kpse_lua_format:
+ INIT_FORMAT ("lua", DEFAULT_LUAINPUTS, LUA_ENVS);
+#define LUA_SUFFIXES \
+ ".lua", ".luatex", ".luc", ".luctex", ".texlua", ".texluc", ".tlu"
+ SUFFIXES (LUA_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_fea_format:
+ INIT_FORMAT("font feature files", DEFAULT_FONTFEATURES, FONTFEATURES_ENVS);
+ SUFFIXES (".fea");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_cid_format:
+ INIT_FORMAT ("cid maps", DEFAULT_FONTCIDMAPS, FONTCIDMAPS_ENVS);
+#define CID_SUFFIXES ".cid", ".cidmap"
+ SUFFIXES (CID_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_mlbib_format:
+ INIT_FORMAT ("mlbib", DEFAULT_MLBIBINPUTS, MLBIB_ENVS);
+#define MLBIB_SUFFIXES ".mlbib", ".bib"
+ SUFFIXES (MLBIB_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_mlbst_format:
+ INIT_FORMAT ("mlbst", DEFAULT_MLBSTINPUTS, MLBST_ENVS);
+#define MLBST_SUFFIXES ".mlbst", ".bst"
+ SUFFIXES (MLBST_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_clua_format:
+ INIT_FORMAT ("clua", DEFAULT_CLUAINPUTS, CLUA_ENVS);
+#define CLUA_SUFFIXES ".dll", ".so"
+ SUFFIXES (CLUA_SUFFIXES);
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_ris_format:
+ INIT_FORMAT ("ris", DEFAULT_RISINPUTS, RIS_ENVS);
+ SUFFIXES (".ris");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ case kpse_bltxml_format:
+ INIT_FORMAT ("bltxml", DEFAULT_BLTXMLINPUTS, BLTXML_ENVS);
+ SUFFIXES (".bltxml");
+ FMT_INFO.suffix_search_only = true;
+ break;
+ default:
+ LIB_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 (KPATHSEA_DEBUG_P (KPSE_DEBUG_PATHS)) {
+ if (format == kpse_cnf_format)
+ fputs ("\n", stderr); /* always mid-search, so break log output */
+
+ 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));
+ DEBUGF1 (" environment variables = %s\n", envvar_list);
+ 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 (" 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);
+ DEBUGF1 (" open files in binary mode = %d\n", FMT_INFO.binmode);
+ DEBUGF1 (" numeric format value = %d\n", format);
+}
+#endif /* KPSE_DEBUG */
+
+ return envvar_list;
+}
+
+#if defined (KPSE_COMPAT_API)
+const_string
+kpse_init_format (kpse_file_format_type format)
+{
+ return kpathsea_init_format (kpse_def, format);
+}
+#endif
+
+
+/* These are subroutines called twice when finding file, to construct
+ the list of names to search for. */
+
+/* We don't even use fontmaps any more in practice, they were for things
+ like the lcircle10/lcirc10 name change many years ago, but let's keep
+ the support working nonetheless. */
+
+static void
+target_fontmaps (kpathsea kpse, string **target, unsigned *count,
+ const_string name)
+{
+ const_string *mapped_names = kpathsea_fontmap_lookup (kpse, name);
+
+ if (mapped_names != NULL) {
+ const_string mapped_name;
+ /* We leak mapped_names and its elements, some of the time. */
+ while ((mapped_name = *mapped_names++) != NULL) {
+ (*target)[(*count)] = xstrdup (mapped_name);
+ (*count)++;
+ XRETALLOC ((*target), (*count)+1, string);
+ }
+ }
+}
+
+
+/* Possibly add NAME (and any fontmap equivalents) to the string list
+ in TARGET, depending on the various other parameters. */
+
+static void
+target_asis_name (kpathsea kpse, string **target, unsigned *count,
+ kpse_file_format_type format,
+ const_string name, boolean use_fontmaps, boolean has_potential_suffix,
+ string has_any_suffix)
+{
+ (void) has_any_suffix; /* -Wunused */
+ /* Look for the name we've been given, provided non-suffix
+ searches are allowed or the name already includes a suffix. */
+ if (has_potential_suffix || !FMT_INFO.suffix_search_only) {
+ (*target)[(*count)] = xstrdup (name);
+ (*count)++;
+ XRETALLOC ((*target), (*count)+1, string);
+
+ if (use_fontmaps) {
+ target_fontmaps (kpse, target, count, name);
+ }
+ }
+}
+
+
+/* Possibly add NAME (and any fontmap equivalents), with any suffixes
+ for this FORMAT appended, to TARGET -- if it doesn't already have one
+ of the potential suffixes for FORMAT. */
+
+static void
+target_suffixed_names (kpathsea kpse, string **target, unsigned *count,
+ kpse_file_format_type format,
+ const_string name, boolean use_fontmaps, boolean has_potential_suffix)
+{
+ const_string *ext;
+ if (has_potential_suffix || !FMT_INFO.suffix) {
+ return;
+ }
+
+ for (ext = FMT_INFO.suffix; *ext; ext++) {
+ string name_with_suffix = concat (name, *ext);
+ (*target)[(*count)] = name_with_suffix;
+ (*count)++;
+ XRETALLOC ((*target), (*count)+1, string);
+
+ if (use_fontmaps) {
+ target_fontmaps (kpse, target, count, name_with_suffix);
+ }
+ }
+}
+
+/* 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
+kpathsea_find_file (kpathsea kpse, const_string name,
+ kpse_file_format_type format, boolean must_exist)
+{
+ string *ret_list = kpathsea_find_file_generic (kpse, name, format,
+ must_exist, false);
+ string ret = *ret_list;
+ free (ret_list);
+ return ret;
+}
+
+#if defined (KPSE_COMPAT_API)
+string
+kpse_find_file (const_string name, kpse_file_format_type format,
+ boolean must_exist)
+{
+ return kpathsea_find_file(kpse_def, name, format, must_exist);
+}
+#endif
+
+/* As with `kpse_find_file', but also allow passing ALL for the search,
+ hence we always return a NULL-terminated list. */
+
+string *
+kpathsea_find_file_generic (kpathsea kpse, const_string const_name,
+ kpse_file_format_type format,
+ boolean must_exist, boolean all)
+{
+#if defined(_WIN32) && !defined(__MINGW32__)
+ char tmpbuffer1[512], tmpbuffer2[512];
+#endif
+ string *target, name;
+ const_string *ext;
+ unsigned count;
+ unsigned name_len = 0;
+ boolean has_potential_suffix = false;
+ string has_any_suffix = NULL;
+ string try_std_extension_first = NULL;
+ 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 (const_name);
+
+ if (FMT_INFO.path == NULL)
+ kpathsea_init_format (kpse, format);
+
+#ifdef KPSE_DEBUG
+ if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
+ DEBUGF3 ("kpse_find_file: searching for %s of type %s (from %s)\n",
+ const_name, FMT_INFO.type, FMT_INFO.path_source);
+#endif /* KPSE_DEBUG */
+
+ /* Do variable and tilde expansion. */
+ name = kpathsea_expand (kpse, const_name);
+
+ has_any_suffix = strrchr (name, '.');
+ if (has_any_suffix) {
+ string p = strchr (has_any_suffix, DIR_SEP);
+ if (p) {
+ has_any_suffix = NULL;
+ }
+ }
+
+ /* Does NAME already end in a possible suffix? */
+ name_len = strlen (name);
+ if (FMT_INFO.suffix) {
+ for (ext = FMT_INFO.suffix; !has_potential_suffix && *ext; ext++) {
+ unsigned suffix_len = strlen (*ext);
+ has_potential_suffix = (name_len >= suffix_len
+ && FILESTRCASEEQ (*ext, name + name_len - suffix_len));
+ }
+ }
+ if (!has_potential_suffix && FMT_INFO.alt_suffix) {
+ for (ext = FMT_INFO.alt_suffix; !has_potential_suffix && *ext; ext++) {
+ unsigned suffix_len = strlen (*ext);
+ has_potential_suffix = (name_len >= suffix_len
+ && FILESTRCASEEQ (*ext, name + name_len - suffix_len));
+ }
+ }
+
+ /* Set up list of target names to search for, the order depending on
+ try_std_extension_first. */
+ count = 0;
+ target = XTALLOC1 (string);
+ try_std_extension_first
+ = kpathsea_var_value (kpse, "try_std_extension_first");
+
+ if (has_any_suffix && !KPSE_CNF_P (try_std_extension_first)) {
+ target_asis_name (kpse, &target, &count, format, name, use_fontmaps,
+ has_potential_suffix, has_any_suffix);
+ target_suffixed_names (kpse, &target, &count, format, name, use_fontmaps,
+ has_potential_suffix);
+ } else {
+ target_suffixed_names (kpse, &target, &count, format, name, use_fontmaps,
+ has_potential_suffix);
+ target_asis_name (kpse, &target, &count, format, name, use_fontmaps,
+ has_potential_suffix, has_any_suffix);
+ }
+
+ /* Terminate list. */
+ target[count] = NULL;
+
+ if (try_std_extension_first) {
+ free (try_std_extension_first);
+ }
+
+ /* Search, trying to minimize disk-pounding. */
+ ret = kpathsea_path_search_list_generic (kpse, FMT_INFO.path,
+ target, false, all);
+
+ /* Do we need to pound the disk? */
+ if (! *ret && must_exist) {
+ for (count = 0; target[count]; count++)
+ free (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. */
+ if (!has_potential_suffix && FMT_INFO.suffix_search_only) {
+ for (ext = FMT_INFO.suffix; *ext; ext++)
+ target[count++] = concat (name, *ext);
+ }
+ if (has_potential_suffix || !FMT_INFO.suffix_search_only) {
+ target[count++] = xstrdup (name);
+ }
+ target[count] = NULL;
+ ret = kpathsea_path_search_list_generic (kpse, FMT_INFO.path,
+ target, true, all);
+ }
+
+ /* Free the list we created. */
+ for (count = 0; target[count]; count++)
+ free (target[count]);
+ free (target);
+
+ /* If nothing was found, call mktex* to create a missing file. Since
+ this returns a single string, morph it into a list. */
+ if (! *ret && must_exist) {
+ ret = XTALLOC (2, string);
+ ret[0] = kpathsea_make_tex (kpse, format, name);
+ if (ret[0]) {
+ ret[1] = NULL;
+ }
+ }
+
+ free (name);
+#if defined(_WIN32) && !defined(__MINGW32__)
+ if (ret && *ret) {
+ if (all) {
+ for (count = 0; ret[count] != NULL; count++) {
+ strcpy (tmpbuffer2, ret[count]);
+ if (kpathsea_getlongpath (kpse, tmpbuffer1, tmpbuffer2, 500)) {
+ if (strlen (tmpbuffer1) > strlen (ret[count]))
+ ret[count] = realloc (ret[count], strlen (tmpbuffer1) + 1);
+ strcpy (ret[count], tmpbuffer1);
+ }
+ }
+ } else {
+ strcpy (tmpbuffer2, *ret);
+ if (kpathsea_getlongpath (kpse, tmpbuffer1, tmpbuffer2, 500)) {
+ if (strlen (tmpbuffer1) > strlen (*ret))
+ *ret = realloc (*ret, strlen (tmpbuffer1) + 1);
+ strcpy (*ret, tmpbuffer1);
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+#if defined (KPSE_COMPAT_API)
+string *
+kpse_find_file_generic (const_string name, kpse_file_format_type format,
+ boolean must_exist, boolean all)
+{
+ return kpathsea_find_file_generic(kpse_def, name, format, must_exist, all);
+}
+#endif
+
+
+
+/* Return true if FNAME is acceptable to open for reading or writing. */
+
+typedef enum ok_type {
+ ok_reading,
+ ok_writing
+} ok_type;
+
+static const_string ok_type_name[] = {
+ "reading from",
+ "writing to"
+};
+
+static boolean
+kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var,
+ const_string default_choice, ok_type action, boolean silent)
+{
+ /* We distinguish three cases:
+ 'a' (any) allows any file to be opened.
+ 'r' (restricted) means disallowing special file names.
+ 'p' (paranoid) means being really paranoid: disallowing special file
+ names and restricting output files to be in or below
+ the working directory or $TEXMFOUTPUT, while input files
+ must be below the current directory, $TEXMFOUTPUT, or
+ (implicitly) in the system areas.
+ We default to "paranoid". The error messages from TeX may be puzzling.
+ This function contains several return and goto statements, be careful. */
+
+ const_string open_choice = kpathsea_var_value (kpse, check_var);
+
+ if (!open_choice)
+ open_choice = default_choice;
+
+ if (*open_choice == 'a' || *open_choice == 'y' || *open_choice == '1')
+ return true;
+
+#if defined (unix) && !defined (MSDOS)
+ {
+ /* Disallow .rhosts, .login, .ssh/, ..somefile, ..somedir/somefile,
+ etc. But allow .tex (for base LaTeX). */
+ const_string q;
+ const_string qq = fname;
+ while ((q = strchr (qq, '.'))) { /* at each dot */
+ if ((q == fname || IS_DIR_SEP (*(q - 1))) /* start or / precedes dot? */
+ && !IS_DIR_SEP (*(q + 1)) /* ok if /./ */
+ && !(*(q + 1) == '.' && IS_DIR_SEP (*(q + 2))) /* ok if /../ */
+ && !STREQ (q, ".tex")) { /* specially allow .tex */
+ goto not_ok;
+ }
+ qq = q + 1;
+ }
+ }
+#else
+ /* Other OSs don't have special names? */
+#endif
+
+ if (*open_choice == 'r' || *open_choice == 'n' || *open_choice == '0')
+ return true;
+
+ /* Paranoia originally supplied by Charles Karney. */
+ if (kpathsea_absolute_p (kpse, fname, false)) {
+ const_string texmfoutput = kpathsea_var_value (kpse, "TEXMFOUTPUT");
+ /* Absolute pathname is only OK if TEXMFOUTPUT is set, it's not empty,
+ fname begins the TEXMFOUTPUT, and is followed by / */
+ if (!texmfoutput || *texmfoutput == '\0'
+ || fname != strstr (fname, texmfoutput)
+ || !IS_DIR_SEP (fname[strlen (texmfoutput)]))
+ goto not_ok;
+ }
+ /* For all pathnames, we disallow "../" at the beginning or "/../"
+ anywhere. */
+ if (fname[0] == '.' && fname[1] == '.' && IS_DIR_SEP(fname[2]))
+ goto not_ok;
+ else {
+ /* Check for "/../". Since more than one character can be matched
+ by IS_DIR_SEP, we cannot use "/../" itself. */
+ const_string dotpair = strstr (fname, "..");
+ while (dotpair) {
+ /* If dotpair[2] == DIR_SEP, then dotpair[-1] is well-defined,
+ because the "../" case was handled above. */
+ if (IS_DIR_SEP (dotpair[2]) && IS_DIR_SEP (dotpair[-1]))
+ goto not_ok;
+ /* Continue after the dotpair. */
+ dotpair = strstr (dotpair+2, "..");
+ }
+ }
+
+ /* We passed all tests. */
+ return true;
+
+ not_ok: /* Some test failed. */
+ if (!silent)
+ fprintf (stderr, "\n%s: Not %s %s (%s = %s).\n",
+ kpse->invocation_name, ok_type_name[action], fname,
+ check_var, open_choice);
+ return false;
+}
+
+/* For input default to all. */
+
+boolean
+kpathsea_in_name_ok_silent (kpathsea kpse, const_string fname)
+{
+ return kpathsea_name_ok (kpse, fname, "openin_any", "a", ok_reading, true);
+}
+
+boolean
+kpathsea_in_name_ok (kpathsea kpse, const_string fname)
+{
+ return kpathsea_name_ok (kpse, fname, "openin_any", "a", ok_reading, false);
+}
+
+
+#if defined(WIN32) || defined(__CYGWIN__)
+static int
+Isspace (char c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+static boolean
+executable_filep (kpathsea kpse, const_string fname, boolean silent)
+{
+ const_string fn;
+ string p, q, base;
+ string *pp;
+
+/* check openout_any */
+ p = kpathsea_var_value (kpse, "openout_any");
+ if (p && *p == 'p') {
+ free (p);
+/* get base name
+ we cannot use xbasename() for abnormal names.
+*/
+ p = strrchr (fname, '/');
+ if (p)
+ fn = p + 1;
+ else
+ fn = fname;
+ p = strrchr (fn, '\\');
+ if (p)
+ fn = p + 1;
+ base = xstrdup (fn);
+#if defined(__CYGWIN__)
+ for (p = base; *p; p++)
+ *p = TOLOWER (*p);
+ p = base;
+#else
+ p = (char *) strlwr (base);
+#endif
+ for (q = p + strlen (p) - 1;
+ (q >= p) && ((*q == '.') || (Isspace (*q))); q--) {
+ *q = '\0'; /* remove trailing '.' , ' ' and '\t' */
+ }
+ q = strrchr (p, '.'); /* get extension part */
+ pp = kpse->suffixlist;
+ if (pp && q) {
+ while (*pp) {
+ if (!strcmp (q, *pp)) {
+ if (!silent)
+ fprintf (stderr, "\n%s: Forbidden to open for writing\n", fname);
+ free (base);
+ return true;
+ }
+ pp++;
+ }
+ }
+ free (base);
+ } else if (p) {
+ free (p);
+ }
+ return false;
+}
+#endif /* WIN32 || __CYGWIN__ */
+
+static boolean
+kpathsea_out_name_ok_1 (kpathsea kpse, const_string fname, boolean silent)
+{
+#if defined(WIN32) || defined(__CYGWIN__)
+ /* Output of an executable file is restricted on Windows */
+ if (executable_filep (kpse, fname, silent))
+ return false;
+#endif /* WIN32 || __CYGWIN__ */
+ /* For output, default to paranoid. */
+ return kpathsea_name_ok (kpse, fname, "openout_any", "p", ok_writing,silent);
+}
+
+boolean
+kpathsea_out_name_ok_silent (kpathsea kpse, const_string fname)
+{
+ return kpathsea_out_name_ok_1 (kpse, fname, true);
+}
+
+boolean
+kpathsea_out_name_ok (kpathsea kpse, const_string fname)
+{
+ return kpathsea_out_name_ok_1 (kpse, fname, false);
+}
+
+#if defined (KPSE_COMPAT_API)
+boolean
+kpse_in_name_ok (const_string fname)
+{
+ /* For input default to all. */
+ return kpathsea_in_name_ok (kpse_def, fname);
+}
+
+boolean
+kpse_out_name_ok (const_string fname)
+{
+ /* For output, default to paranoid. */
+ return kpathsea_out_name_ok (kpse_def, fname);
+}
+#endif
+
+
+
+/* Open NAME along the search path for TYPE for reading and return the
+ resulting file, or exit with an error message. */
+
+FILE *
+kpathsea_open_file (kpathsea kpse, const_string name,
+ kpse_file_format_type type)
+{
+ string fullname = kpathsea_find_file (kpse, 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 {
+ LIB_FATAL2 ("%s file `%s' not found", kpse->format_info[type].type, name);
+ }
+ }
+
+ return f;
+}
+
+#if defined (KPSE_COMPAT_API)
+FILE *
+kpse_open_file (const_string name, kpse_file_format_type type)
+{
+ return kpathsea_open_file(kpse_def, name, type);
+}
+#endif
+
+
+/* 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
+ needs format_info, and would cause all of tex-file to be pulled
+ in by programs that do not need it. */
+
+void
+kpathsea_reset_program_name (kpathsea kpse, 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);
+ kpathsea_xputenv (kpse, "progname", kpse->program_name);
+
+ /* Go through all paths ... */
+ for (i = 0; i != kpse_last_format; ++i) {
+ /* Do not erase the cnf or 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 because their
+ values may differ with the new program name. */
+ if (kpse->format_info[i].path != NULL) {
+ free (kpse->format_info[i].path);
+ kpse->format_info[i].path = NULL;
+ }
+ /* We cannot free cnf_path: it points into the cnf hash. */
+ 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. */
+ }
+}
+
+#if defined (KPSE_COMPAT_API)
+void
+kpse_reset_program_name (const_string progname)
+{
+ kpathsea_reset_program_name (kpse_def, progname);
+}
+#endif