summaryrefslogtreecommitdiff
path: root/Build/source/texk/kpathsea/pathsearch.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/kpathsea/pathsearch.c')
-rw-r--r--Build/source/texk/kpathsea/pathsearch.c932
1 files changed, 0 insertions, 932 deletions
diff --git a/Build/source/texk/kpathsea/pathsearch.c b/Build/source/texk/kpathsea/pathsearch.c
deleted file mode 100644
index 778b952a6b3..00000000000
--- a/Build/source/texk/kpathsea/pathsearch.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/* pathsearch.c: look up a filename in a path.
-
- Copyright 1993, 1994, 1995, 1997, 2007, 2009-2012, 2018, 2020 Karl Berry.
- Copyright 1997-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-pathch.h>
-#include <kpathsea/c-fopen.h>
-#include <kpathsea/absolute.h>
-#include <kpathsea/expand.h>
-#include <kpathsea/db.h>
-#include <kpathsea/pathsearch.h>
-#include <kpathsea/readable.h>
-#include <kpathsea/str-list.h>
-#include <kpathsea/str-llist.h>
-#include <kpathsea/variable.h>
-#include <kpathsea/xopendir.h>
-
-#include <time.h> /* for `time' */
-
-#ifdef __DJGPP__
-#include <sys/stat.h> /* for stat bits */
-#endif
-
-#ifdef WIN32
-#undef fputs
-#undef puts
-#define fputs win32_fputs
-#define puts win32_puts
-#endif
-
-/* The very first search is for texmf.cnf, called when someone tries to
- initialize the TFM path or whatever. init_path calls kpse_cnf_get
- which calls kpse_all_path_search to find all the texmf.cnf's. We
- need to do various special things in this case, since we obviously
- don't yet have the configuration files when we're searching for the
- configuration files. Therefore we have a followup_search member in
- kpathsea_instance to distinguish the first search from all others. */
-
-
-
-#ifdef KPSE_DEBUG
-/* Print on FH elements of L surrounded by brackets, separated by spaces. */
-
-static void
-print_space_list (FILE *fh, string *l)
-{
- fputs ("[", fh);
- while (l && *l) {
- fputs (*l, fh);
- l++;
- if (*l)
- fputs (" ", fh);
- }
- fputs ("]", fh);
-}
-#endif /* KPSE_DEBUG */
-
-/* This function is called after every search (except the first, since
- we definitely want to allow enabling the logging in texmf.cnf) to
- record the filename(s) found in $TEXMFLOG. */
-
-static void
-log_search (kpathsea kpse, str_list_type filenames)
-{
- if (kpse->log_opened == false) {
- /* Get name from either envvar or config file. Thus, the first time
- is called, for the first search, we will be opening texmf.cnf
- and ls-R just to resolve the variable. */
- string log_name = kpathsea_var_value (kpse, "TEXMFLOG");
- kpse->log_opened = true;
- if (log_name) {
- kpse->log_file = fopen (log_name, FOPEN_A_MODE);
- if (!kpse->log_file)
- perror (log_name);
- free (log_name);
- }
- }
-
- if (
-#ifdef KPSE_DEBUG
- KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH) ||
-#endif /* KPSE_DEBUG */
- kpse->log_file) {
- unsigned e;
-
- /* FILENAMES should never be null, but safety doesn't hurt. */
- for (e = 0; e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e);
- e++) {
- string filename = STR_LIST_ELT (filenames, e);
-
- /* Only record absolute filenames, for privacy. */
- if (kpse->log_file && kpathsea_absolute_p (kpse, filename, false)) {
- fprintf (kpse->log_file, "%lu %s\n", (long unsigned) time (NULL),
- filename);
- }
-
-#ifdef KPSE_DEBUG
- /* And show them online, if debugging. We've already started the
- debugging line in `search' and
- `kpathsea_path_search_list_generic', where this is called, so
- just print the filename here, don't use DEBUGF. */
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- putc (' ', stderr);
- fputs (filename, stderr);
- }
-#endif /* KPSE_DEBUG */
- }
- }
-}
-
-/* Either casefold_readable_file or kpathsea_readable_file. We need the
- type even if we don't have casefolding enabled at compile-time. */
-typedef string (*readable_file_fn_type) (kpathsea, string);
-
-#ifdef MONOCASE_FILENAMES
-/* Don't do any of this fallback casefolding stuff on Windows. */
-#undef KPSE_CASEFOLDING_SEARCH
-#else
-#define KPSE_CASEFOLDING_SEARCH 1
-#endif
-
-#ifdef KPSE_CASEFOLDING_SEARCH
-
-/* Same as kpathsea_readable_file (readable.c), but check
- case-insensitively on the last file name component. We return the
- first match (in new memory), or NULL. In practice this is always
- called after checking the filename as-is, so there's no use in
- continuing to look for an exact match. The KPSE arg is only passed
- to kpathsea_readable_file if we have a candidate match.
-
- Clearly we could do some caching here, but let's see if it's actually
- necessary, given all the other levels of caching (disk, memory, cpu)
- that are going on these days. */
-
-static string
-casefold_readable_file (kpathsea kpse, string name)
-{
- string ret = NULL;
- const_string this_base_name = xbasename (name);
- string this_dir_name = xdirname (name);
- DIR *thisdir = opendir (this_dir_name);
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF2 (" casefold_readable_file(%s) in %s => ",
- this_base_name, this_dir_name);
- }
-#endif
-
- /* We can be called with a name like `subdir/somefile', where subdir/
- does not exist. So the opendir might fail, and that's ok. */
- if (thisdir) {
- struct dirent *e;
-
- while ((e = readdir (thisdir)) != NULL) {
- /* The standard strcasecmp seems like enough for the comparison? */
- if (strcasecmp (e->d_name, this_base_name) == 0) {
- ret = concat3 (this_dir_name, DIR_SEP_STRING, e->d_name);
- if (kpathsea_readable_file (kpse, ret)) {
- break; /* success */
- } else {
- /* This only happens when the name matches, but the potential file is
- not actually readable, e.g., a broken symlink. It seems
- sufficiently unusual to be worth logging. */
- #ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- fprintf (stderr, "{casefolded candidate %s not readable, continuing}",ret);
- }
- #endif
- free (ret); /* not readable, keep looking */
- ret = NULL;
- }
- }
- } /* end of readdir loop */
- xclosedir (thisdir);
- }
- free (this_dir_name);
-
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- fputs (ret ? ret : "(nil)", stderr);
- fputc ('\n', stderr);
- }
- return ret;
-}
-#endif /* KPSE_CASEFOLDING_SEARCH */
-
-/* Return a str_list of matches in DIRS of NAME.
-
- Concatenate each element in DIRS with NAME, assuming each ends with /.
- If SEARCH_ALL is false, return a list containing just the first
- readable (according to the READABLE_FILE_P function) regular file.
- Else continue to search and return them all. In any case, if none,
- return a list containing just NULL.
-
- DIRS is modified only in that the directory where a search matches is
- floated toward the top of the list.
-
- We keep a single buffer for the potential filenames and reallocate
- only when necessary. I'm not sure it's noticeably faster, but it
- does seem cleaner. (We do waste a bit of space in the return
- value, since we don't shrink it to the final size returned.) */
-
-#define INIT_ALLOC 75 /* Doesn't much matter what this number is. */
-
-static str_list_type
-dir_list_search (kpathsea kpse, str_llist_type *dirs, const_string name,
- boolean search_all, readable_file_fn_type readable_file_p)
-{
- str_llist_elt_type *elt;
- str_llist_elt_type *next_elt;
- str_list_type ret;
- unsigned name_len = strlen (name);
- unsigned allocated = INIT_ALLOC;
- string potential = (string) xmalloc (allocated);
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- const_string casefold =
-#ifdef KPSE_CASEFOLDING_SEARCH
- (readable_file_p == casefold_readable_file) ? "yes" : "no";
-#else
- "No";
-#endif
- DEBUGF3 (" dir_list_search(file=%s, find_all=%d, casefold=%s)\n",
- name, search_all, casefold);
- }
-#endif
-
- ret = str_list_init ();
-
- for (elt = *dirs; elt; elt = next_elt) {
- string readable_name;
- const_string dir = STR_LLIST (*elt);
- unsigned dir_len = strlen (dir);
-
- next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
-
- while (dir_len + name_len + 1 > allocated) {
- allocated += allocated;
- XRETALLOC (potential, allocated, char);
- }
- strcpy (potential, dir);
- strcat (potential, name);
-
- readable_name = readable_file_p (kpse, potential);
- if (readable_name) {
- str_list_add (&ret, readable_name);
-
- /* Move this element towards the top of the list. */
- str_llist_float (dirs, elt);
-
- /* If caller only wanted one file returned, no need to
- terminate the list with NULL; the caller knows to only look
- at the first element. */
- if (!search_all)
- return ret;
-
- /* Start new filename. */
- allocated = INIT_ALLOC;
- potential = (string) xmalloc (allocated);
- }
- }
-
- /* If we get here, either we didn't find any files, or we were finding
- all the files. But we're done with the last filename, anyway. */
- free (potential);
-
- return ret;
-}
-
-/* This is analogous to dir_list_search above, except we search for
- multiple NAMES instead of one (unfortunately the code is duplicated).
- Absolute or explicitly relative items in NAMES are ignored; the
- caller (kpathsea_path_search_list_generic) deals with those
- separately. NAMES[i] is not modified. */
-
-
-static str_list_type
-dir_list_search_list (kpathsea kpse, str_llist_type *dirs, string* names,
- boolean search_all, readable_file_fn_type readable_file_p)
-{
- str_llist_elt_type *elt;
- str_llist_elt_type *next_elt;
- str_list_type ret;
- unsigned allocated = INIT_ALLOC;
- string potential = XTALLOC (allocated, char);
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- const_string casefold =
-#ifdef KPSE_CASEFOLDING_SEARCH
- (readable_file_p == casefold_readable_file) ? "yes" : "no";
-#else
- "No";
-#endif
- DEBUGF (" dir_list_search_list(files=");
- print_space_list (stderr, names);
- fprintf (stderr, ", find_all=%d, casefold=%s)\n", search_all, casefold);
- }
-#endif
-
- ret = str_list_init ();
-
- for (elt = *dirs; elt; elt = next_elt) {
- int i;
- string readable_name;
- const_string dir = STR_LLIST (*elt);
- unsigned dir_len = strlen (dir);
-
- next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
-
- for (i = 0; names[i]; i++) {
- const_string name = names[i];
- unsigned name_len;
-
- /* Don't bother with absolute & explicit relative. */
- if (kpathsea_absolute_p (kpse, name, true))
- continue;
-
- name_len = strlen (name);
-
- while (dir_len + name_len + 1 > allocated) {
- allocated += allocated;
- XRETALLOC (potential, allocated, char);
- }
-
- strcpy (potential, dir);
- strcat (potential + dir_len, name);
- readable_name = readable_file_p (kpse, potential);
- if (readable_name) {
- str_list_add (&ret, readable_name);
-
- /* Move this element towards the top of the list. */
- str_llist_float (dirs, elt);
-
- /* If caller only wanted one file returned, no need to
- terminate the list with NULL; the caller knows to only look
- at the first element. */
- if (!search_all)
- return ret;
-
- /* Start new filename. */
- allocated = INIT_ALLOC;
- potential = XTALLOC (allocated, char);
- }
- }
- }
-
- /* If we get here, either we didn't find any files, or we were finding
- all the files. But we're done with the last filename, anyway. */
- free (potential);
-
- return ret;
-}
-
-/* This is called when NAME is absolute or explicitly relative; if it's
- readable, return a one-element str_list containing it (in new
- memory); otherwise, return an empty list. (We return a list so as to
- have the same return value as the path_search function.) We also
- check case-insensitively if enabled and needed. */
-
-static str_list_type
-absolute_search (kpathsea kpse, string name)
-{
- str_list_type ret_list;
- string found;
-
- /* Some old compilers can't initialize structs. */
- ret_list = str_list_init ();
-
- /* Do the first check. */
- found = kpathsea_readable_file (kpse, name);
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF2 (" absolute_search(%s) => %s\n", name, found ? found : "(nil)");
- }
-#endif
- if (found) {
- found = xstrdup (found); /* Return new memory. */
- }
-
-#ifdef KPSE_CASEFOLDING_SEARCH
- /* Do the casefolding search only if both needed and enabled. */
- if (!found) {
- if (KPSE_CNF_P (kpathsea_var_value (kpse, "texmf_casefold_search"))) {
- found = casefold_readable_file (kpse, name);
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF2 (" casefold search(%s) => %s\n",name,found ? found : "(nil)");
- }
-#endif /* KPSE_DEBUG */
- }
- }
-#endif /* KPSE_CASEFOLDING_SEARCH */
-
- if (found) {
- /* If we didn't find anything, we'll return an empty list. */
- str_list_add (&ret_list, found);
- }
-
- return ret_list;
-}
-
-/* This is the hard case -- look for NAME in PATH. If ALL is false,
- return the first file found. Otherwise, search all elements of PATH.
- We also check case-insensitively if needed and requested. */
-
-static str_list_type
-path_search (kpathsea kpse, const_string path, string name,
- boolean must_exist, boolean all)
-{
- string elt;
- str_list_type ret_list;
- boolean done = false;
- ret_list = str_list_init (); /* some compilers lack struct initialization */
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF4 (" path_search(file=%s, must_exist=%d, find_all=%d, path=%s)\n",
- name, all, must_exist, path);
- }
-#endif
-
- for (elt = kpathsea_path_element (kpse, path); !done && elt;
- elt = kpathsea_path_element (kpse, NULL)) {
- str_list_type *found;
- boolean allow_disk_search = true;
-
- if (*elt == '!' && *(elt + 1) == '!') {
- /* Those magic leading chars in a path element means don't search the
- disk for this elt. And move past the magic to get to the name. */
- allow_disk_search = false;
- elt += 2;
- }
-
- /* See elt-dirs.c for side effects of this function. */
- kpathsea_normalize_path (kpse, elt);
-
- /* Try ls-R, unless we're searching for texmf.cnf. Our caller
- (search), also tests followup_search, and does the resetting. */
- found = kpse->followup_search ? kpathsea_db_search (kpse, name, elt, all)
- : NULL;
-
- /* Search the filesystem if (1) the path spec allows it, and either
- (2a) we are searching for texmf.cnf; or
- (2b) no db exists; or
- (2c) no db's are relevant to this elt; or
- (3) MUST_EXIST && NAME was not in the db.
- In (2*), `found' will be NULL.
- In (3), `found' will be an empty list. */
- if (allow_disk_search
- && (!found || (must_exist && !STR_LIST (*found)))) {
- /* Determine the directories in which to search: */
- str_llist_type *dirs = kpathsea_element_dirs (kpse, elt);
- if (dirs && *dirs) {
- if (!found) {
- found = XTALLOC1 (str_list_type);
- }
- /* Search in the directories: */
- *found = dir_list_search (kpse, dirs, name, all,
- kpathsea_readable_file);
-#ifdef KPSE_CASEFOLDING_SEARCH
- if (!STR_LIST (*found)
- && KPSE_CNF_P (kpathsea_var_value (kpse,
- "texmf_casefold_search"))) {
- /* Nothing found; search again, case-insensitively: */
- *found = dir_list_search (kpse, dirs, name, all,
- casefold_readable_file);
- }
-#endif /* KPSE_CASEFOLDING_SEARCH */
- }
- }
-
- /* Did we find anything? */
- if (found && STR_LIST (*found)) {
- if (all) {
- str_list_concat (&ret_list, *found);
- } else {
- str_list_add (&ret_list, STR_LIST_FIRST_ELT (*found));
- done = true;
- }
- }
-
- /* Free the list space, if any (but not the elements). */
- if (found) {
- str_list_free (found);
- free (found);
- }
- }
-
- return ret_list;
-}
-
-/* Search PATH for ORIGINAL_NAME. If ALL is false, or ORIGINAL_NAME is
- absolute_p, check ORIGINAL_NAME itself. Otherwise, look at each
- element of PATH for the first readable ORIGINAL_NAME.
-
- Always return a list; if no files are found, the list will
- contain just NULL. If ALL is true, the list will be
- terminated with NULL.
-
- This function is a special case of kpathsea_path_search_list_generic
- below (which takes a list of names, instead of a single name, to
- search for), and so should be rewritten to call it. But this
- function came first, and life is short, so the code duplication
- is here. Sorry. Please fix. */
-
-static string *
-search (kpathsea kpse, const_string path, const_string original_name,
- boolean must_exist, boolean all)
-{
- str_list_type ret_list;
- string name;
- boolean absolute_p;
-#ifdef __DJGPP__
- /* We will use `stat' heavily, so let's request for
- the fastest possible version of `stat', by telling
- it what members of struct stat do we really need.
-
- We need to set this on each call because this is a
- library function; the caller might need other options
- from `stat'. Thus save the flags and restore them
- before exit.
-
- This call tells `stat' that we do NOT need to recognize
- executable files (neither by an extension nor by a magic
- signature); that we do NOT need time stamp of root directories;
- and that we do NOT need the write access bit in st_mode.
-
- Note that `kpse_set_program_name' needs the EXEC bits,
- but it was already called by the time we get here. */
- unsigned short save_djgpp_flags = _djstat_flags;
-
- _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
- | _STAT_ROOT_TIME | _STAT_WRITEBIT;
-#endif
-
- /* Make a leading ~ count as an absolute filename, and expand $FOO's. */
- name = kpathsea_expand (kpse, original_name);
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
- DEBUGF4 ("start search(xname=%s, must_exist=%d, find_all=%d, path=%s).\n",
- name, must_exist, all, path);
-#endif /* KPSE_DEBUG */
-
- /* If the first name is absolute or explicitly relative, no need to
- consider PATH at all. */
- absolute_p = kpathsea_absolute_p (kpse, name, true);
-
- /* Find the file(s). */
- ret_list = absolute_p ? absolute_search (kpse, name)
- : path_search (kpse, path, name, must_exist, all);
-
- /* Append NULL terminator if we didn't find anything at all, or we're
- supposed to find ALL and the list doesn't end in NULL now. */
- if (STR_LIST_EMPTY (ret_list)
- || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
- str_list_add (&ret_list, NULL);
-
- /* The very first search is for texmf.cnf. We can't log that, since
- we want to allow setting TEXMFLOG in texmf.cnf. */
- if (kpse->followup_search == false) {
- kpse->followup_search = true;
- } else {
- /* Record the filenames we found, if desired. And wrap them in a
- debugging line if we're doing that. */
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
- DEBUGF1 ("returning from search(%s) =>", original_name);
-#endif /* KPSE_DEBUG */
- log_search (kpse, ret_list);
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
- putc ('\n', stderr);
-#endif /* KPSE_DEBUG */
- }
-
-#ifdef __DJGPP__
- /* Undo any side effects. */
- _djstat_flags = save_djgpp_flags;
-#endif
-
- /* Free the expanded name we were passed. It can't be in the return
- list, since the path directories got unconditionally prepended. */
- free (name);
-
- return STR_LIST (ret_list);
-}
-
-/* Search PATH for null-terminated array of NAMES. Always return a list;
- if no files are found, the list will contain just NULL. If ALL is
- true, the list will be terminated with NULL (but no NULL terminator
- if ALL is false). This is a generalization of the `search' fn above. */
-
-string *
-kpathsea_path_search_list_generic (kpathsea kpse,
- const_string path, string* names,
- boolean must_exist, boolean all)
-{
- str_list_type ret_list;
- string* namep;
- string elt;
- boolean done = false;
- boolean all_absolute = true;
-#ifdef __DJGPP__
- /* See DJGPP comments above. */
- unsigned short save_djgpp_flags = _djstat_flags;
-
- _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
- | _STAT_ROOT_TIME | _STAT_WRITEBIT;
-#endif
-
- ret_list = str_list_init ();
-
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF ("start generic search(files=");
- print_space_list (stderr, names);
- fprintf (stderr, ", must_exist=%d, find_all=%d, path=%s)\n",
- must_exist, all, path);
- }
-#endif /* KPSE_DEBUG */
-
- /* kpathsea_find_file_generic in tex-file.c does the variable and
- tilde expansion, so don't redo that here. Maybe we should have
- done it differently, but we certainly don't want to create an
- incompatibility now. */
-
- /* First catch any absolute or explicit relative names. */
- for (namep = names; *namep; namep++) {
- if (kpathsea_absolute_p (kpse, *namep, true)) {
- str_list_type abs_ret_list = absolute_search (kpse, *namep);
- /* That search can only return a zero- or one-element list, so: */
- if (!STR_LIST_EMPTY (abs_ret_list)) {
- str_list_add (&ret_list, STR_LIST_FIRST_ELT (abs_ret_list));
- if (!all) { /* if they only wanted one, we're done */
- goto out;
- }
- }
- } else {
- all_absolute = false;
- }
- }
- /* Shortcut: if we were only given absolute/explicit relative names,
- we can skip the rest. Typically, if one name is absolute, they
- all are, because our caller derived them from each other. */
- if (all_absolute) {
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- unsigned i;
- DEBUGF (" generic search: all absolute, candidates are:");
- /* List might not be NULL-terminated, so can't use print_space_list. */
- for (i = 0; i < STR_LIST_LENGTH (ret_list); i++) {
- fprintf (stderr, " %s", STR_LIST_ELT (ret_list, i));
- }
- fputs (".\n", stderr);
- }
-#endif
- goto out;
- }
-
- /* Look at each path element in turn. This is essentially the same
- code as `path_search' above, unfortunately. */
- for (elt = kpathsea_path_element (kpse, path); !done && elt;
- elt = kpathsea_path_element (kpse, NULL)) {
- str_list_type *found;
- boolean allow_disk_search = true;
-
- if (elt[0] == '!' && elt[1] == '!') {
- /* !! magic string -> disallow disk searches. */
- allow_disk_search = false;
- elt += 2;
- }
-
- /* See elt-dirs.c for side effects of this function. */
- kpathsea_normalize_path (kpse, elt);
-
- /* Try ls-R, unless we're searching for texmf.cnf. */
- found = kpse->followup_search
- ? kpathsea_db_search_list (kpse, names, elt, all) : NULL;
-
- /* Search the filesystem in the same cases as `path_search' above. */
- if (allow_disk_search
- && (!found || (must_exist && !STR_LIST (*found)))) {
- str_llist_type *dirs = kpathsea_element_dirs (kpse, elt);
- if (dirs && *dirs) {
- if (!found) {
- found = XTALLOC1 (str_list_type);
- }
- /* Search in the directories: */
- *found = dir_list_search_list (kpse, dirs, names, all,
- kpathsea_readable_file);
-#ifdef KPSE_CASEFOLDING_SEARCH
- if (!STR_LIST (*found) && KPSE_CNF_P (kpathsea_var_value (kpse,
- "texmf_casefold_search"))) {
- /* Still nothing; search again, case-insensitively: */
- *found = dir_list_search_list (kpse, dirs, names, all,
- casefold_readable_file);
- }
-#endif
- }
- }
-
- /* Did we find anything? */
- if (found && STR_LIST (*found)) {
- if (all) {
- str_list_concat (&ret_list, *found);
- } else {
- str_list_add (&ret_list, STR_LIST_FIRST_ELT (*found));
- done = true;
- }
- }
- }
-
- out:
- /* Uniqify, since our paths can often end up finding the same file
- more than once. */
- str_list_uniqify (&ret_list);
-
- /* Add NULL element to terminate return list if empty or multiple. */
- if (STR_LIST_EMPTY (ret_list)
- || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
- str_list_add (&ret_list, NULL);
-
- if (kpse->followup_search == false) {
- kpse->followup_search = true;
- } else {
- /* Record the filenames we found, if desired. And wrap them in a
- debugging line if we're doing that. */
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
- DEBUGF ("returning from generic search(");
- print_space_list (stderr, names);
- fputs (") =>", stderr);
- }
-#endif /* KPSE_DEBUG */
- log_search (kpse, ret_list);
-#ifdef KPSE_DEBUG
- if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
- putc ('\n', stderr);
-#endif /* KPSE_DEBUG */
- }
-
-#ifdef __DJGPP__
- /* Undo any side effects. */
- _djstat_flags = save_djgpp_flags;
-#endif
-
- return STR_LIST (ret_list);
-}
-
-/* Search PATH for the first NAME according to MUST_EXIST. */
-
-string
-kpathsea_path_search (kpathsea kpse, const_string path, const_string name,
- boolean must_exist)
-{
- string *ret_list = search (kpse, path, name, must_exist, false);
- string ret = *ret_list;
- free (ret_list);
- return ret;
-}
-
-/* Search PATH for all files named NAME. Might have been better not
- to assert `must_exist' here, but it's too late to change. */
-
-string *
-kpathsea_all_path_search (kpathsea kpse, const_string path, const_string name)
-{
- string *ret = search (kpse, path, name, true, true);
- return ret;
-}
-
-#if defined (KPSE_COMPAT_API)
-string
-kpse_path_search (const_string path, const_string name, boolean must_exist)
-{
- return kpathsea_path_search (kpse_def, path, name, must_exist);
-}
-
-string *
-kpse_all_path_search (const_string path, const_string name)
-{
- return kpathsea_all_path_search (kpse_def, path, name);
-}
-#endif /* KPSE_COMPAT_API */
-
-
-#ifdef TEST
-
-/* Each element of L on its own line, prefixed by a tab. */
-
-static void
-print_tab_list (string *l)
-{
- while (l && *l) {
- if (*l)
- putchar ('\t');
- printf ("%s\n", *l);
- l++;
- }
-}
-
-static void
-test_path_search (const_string path, const_string file)
-{
- string answer;
- string *answer_list;
-
- printf ("\nSearch %s for %s:\t", path, file);
- answer = kpse_path_search (path, file, 0);
- puts (answer ? answer : "(nil)");
-
- printf ("Search %s for all %s:\t", path, file);
- answer_list = kpse_all_path_search (path, file);
- putchar ('\n');
- print_tab_list (answer_list);
-}
-
-static void
-test_path_search_list_generic (void)
-{
- const_string path = "/u/karl/.fonts";
- /* absolute: should return just console/both, because no case
- sensitive match */
- // string names[] = { "/u/karl/.fonts/lucidaConsoleDK.otf",
- // "/u/karl/.fonts/lucidaGrandeMonoDK.otf", NULL };
-
- /* dirs: should return just grande, because case sensitive wins */
- // string names[] = { "lucidaConsoleDK.otf", "LucidaGrandeMonoDK.otf", NULL };
-
- /* dirs: should return just console/both, because no case sensitive match */
- string names[] = { "lucidaConsoleDK.otf", "lucidaGrandeMonoDK.otf", NULL };
-
- boolean all;
- string *answer_list;
-
- printf ("\nGeneric search %s for ", path);
- print_space_list (stdout, names);
- puts (":\t");
-
- all = false; answer_list
- = kpathsea_path_search_list_generic (kpse_def, path, names, false, all);
- puts (answer_list && *answer_list ? *answer_list : "(nil)");
-
- printf ("\nGeneric search %s for all ", path);
- print_space_list (stdout, names);
- puts (":");
-
- all = true; answer_list
- = kpathsea_path_search_list_generic (kpse_def, path, names, false, all);
- print_tab_list (answer_list);
-}
-
-#define TEXFONTS "/usr/local/texlive-rel/texmf-dist/fonts"
-
-int
-main (int argc, char **argv)
-{
- xputenv ("KPATHSEA_DEBUG", "-1"); /* must be before setting progname */
- kpse_set_program_name (argv[0], NULL);
-
- xputenv ("MALLOC_CHECK_", "3");
- xputenv ("MALLOC_PERTURB_", "75");
-
- xputenv ("texmf_casefold_search", "1");
- test_path_search (".:/k", "readme");
- exit (0);
- test_path_search_list_generic ();
- exit (0);
-
- xputenv ("TEXMFCNF", "/nc");
- /* casefolding with absolute search: */
- test_path_search ("/k", "/u/karl/.fonts/lucidaConsoleDK.otf");
- /* casefolding with directory search: */
- test_path_search ("/u/karl/.fonts", "Lucidaconsoledk.otf");
- /* exit (0); */
- xputenv ("texmf_casefold_search", "0");
- /* should fail since no casefolding: */
- test_path_search ("/u/karl/.fonts", "lucidaconsoledk.otf");
-
- /* All lists end with NULL. */
- test_path_search (".", "nonexistent");
- test_path_search (".", "/nonexistent");
- test_path_search ("/k" ENV_SEP_STRING ".", "README");
- test_path_search ("/k" ENV_SEP_STRING ".", "/etc/fstab");
- test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "cmr10.tfm");
- test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "logo10.tfm");
- test_path_search (TEXFONTS "//times" ENV_SEP_STRING "."
- ENV_SEP_STRING ENV_SEP_STRING, "ptmr.vf");
- test_path_search (TEXFONTS ENV_SEP_STRING
- "/u/karl/.fonts", "LucidaConsoleDK.otf");
-
- test_path_search ("~karl", ".profile"); // nil, no ~ expansion on path
- test_path_search ("/k", "~karl/.profile");
-
- xputenv ("NONEXIST", "nonexistent");
- test_path_search (".", "$NONEXIST");
- xputenv ("KPATHSEA", "kpathsea");
- test_path_search ("/k" ENV_SEP_STRING "./doc", "$KPATHSEA.texi");
- test_path_search ("/k" ENV_SEP_STRING "./doc", "${KPATHSEA}.texi");
- test_path_search ("$KPATHSEA" ENV_SEP_STRING ".", "README");
- test_path_search ("." ENV_SEP_STRING "$KPATHSEA", "README");
-
- return 0;
-}
-
-#endif /* TEST */
-
-
-/* ${wc} is the corresponding build directory.
- -DMAKE_KPSE_DLL for inlined str_list_init etc.
- Memory checking: -fsanitize=address or -lefence.
-Local variables:
-standalone-compile-command: "make --no-print-dir -C ${wc} && gcc -g -I. -I.. -I${wc}/.. -DMAKE_KPSE_DLL -DTEST pathsearch.c ${wc}/.libs/libkpathsea.a && ./a.out"
-End:
-*/