diff options
Diffstat (limited to 'Build/source/texk/kpathsea/elt-dirs.c')
-rw-r--r-- | Build/source/texk/kpathsea/elt-dirs.c | 546 |
1 files changed, 0 insertions, 546 deletions
diff --git a/Build/source/texk/kpathsea/elt-dirs.c b/Build/source/texk/kpathsea/elt-dirs.c deleted file mode 100644 index ec60fe82d70..00000000000 --- a/Build/source/texk/kpathsea/elt-dirs.c +++ /dev/null @@ -1,546 +0,0 @@ -/* elt-dirs.c: Translate a path element to its corresponding director{y,ies}. - - Copyright 1993, 1994, 1995, 1996, 1997, 2008, 2009, 2010, 2011, 2016, - 2017, 2018 Karl Berry. - Copyright 1997, 1998, 1999, 2000, 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/expand.h> -#include <kpathsea/fn.h> -#include <kpathsea/pathsearch.h> -#include <kpathsea/xopendir.h> - -/* To avoid giving prototypes for all the routines and then their real - definitions, we give all the subroutines first. The entry point is - the last routine in the file. */ - -/* Make a copy of DIR (unless it's null) and save it in L. Ensure that - DIR ends with a DIR_SEP for the benefit of later searches. */ - -static void -dir_list_add (str_llist_type *l, string dir) -{ - char last_char = dir[strlen (dir) - 1]; - string saved_dir - = IS_DIR_SEP_CH (last_char) || IS_DEVICE_SEP (last_char) - ? xstrdup (dir) - : concat (dir, DIR_SEP_STRING); - - str_llist_add (l, saved_dir); -} - - -/* If DIR is a directory, add it to the list L. */ - -static void -checked_dir_list_add (kpathsea kpse, str_llist_type *l, string dir) -{ - if (kpathsea_dir_p (kpse, dir)) - dir_list_add (l, dir); -} - -/* The cache. Typically, several paths have the same element; for - example, /usr/local/lib/texmf/fonts//. We don't want to compute the - expansion of such a thing more than once. Even though we also cache - the dir_links call, that's not enough -- without this path element - caching as well, the execution time doubles. */ - -/* Associate KEY with VALUE. We implement the cache as a simple linear - list, since it's unlikely to ever be more than a dozen or so elements - long. We don't bother to check here if PATH has already been saved; - we always add it to our list. We copy KEY but not VALUE; not sure - that's right, but it seems to be all that's needed. */ - -static void -cache (kpathsea kpse, const_string key, str_llist_type *value) -{ - kpse->cache_length++; - XRETALLOC (kpse->the_cache, kpse->cache_length, cache_entry); - kpse->the_cache[kpse->cache_length - 1].key = xstrdup (key); - kpse->the_cache[kpse->cache_length - 1].value = value; -} - - -/* To retrieve, just check the list in order. */ - -static str_llist_type * -cached (kpathsea kpse, const_string key) -{ - unsigned p; - - for (p = 0; p < kpse->cache_length; p++) - { - if (FILESTRCASEEQ (kpse->the_cache[p].key, key)) - return kpse->the_cache[p].value; - } - - return NULL; -} - -/* Handle the magic path constructs. */ - -/* Declare recursively called routine. */ -static void expand_elt (kpathsea, str_llist_type *, string, unsigned); - - -/* POST is a pointer into the original element (which may no longer be - ELT) to just after the doubled DIR_SEP, perhaps to the null. Append - subdirectories of ELT (up to ELT_LENGTH, which must be a /) to - STR_LIST_PTR. ELT must not be the empty string (or NULL). */ - -#ifdef WIN32 -/* Shared across recursive calls, it acts like a stack. */ -static char dirname[MAX_PATH*2]; -static wchar_t dirnamew[MAX_PATH]; -static char *potname; -#endif - -static void -do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, - unsigned elt_length, string post) -{ -#ifdef WIN32 - WIN32_FIND_DATAW find_file_data; - HANDLE hnd; - int proceed; - int nlinks = 2; -#else - DIR *dir; - struct dirent *e; -#endif /* not WIN32 */ - fn_type name; - - /* Some old compilers don't allow aggregate initialization. */ - name = fn_copy0 (elt, elt_length); - - assert (elt_length > 0 - && (IS_DIR_SEP_CH (elt[elt_length - 1]) - || IS_DEVICE_SEP (elt[elt_length - 1]))); - -#if defined (WIN32) - strcpy(dirname, FN_STRING(name)); - strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */ - get_wstring_from_mbstring(kpse->File_system_codepage, dirname, dirnamew); - hnd = FindFirstFileW(dirnamew, &find_file_data); - - if (hnd == INVALID_HANDLE_VALUE) { - fn_free(&name); - return; - } - - /* Include top level before subdirectories, if nothing to match. */ - if (*post == 0) - dir_list_add (str_list_ptr, FN_STRING (name)); - else { - /* If we do have something to match, see if it exists. For - example, POST might be `pk/ljfour', and they might have a - directory `$TEXMF/fonts/pk/ljfour' that we should find. */ - fn_str_grow (&name, post); - expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length); - fn_shrink_to (&name, elt_length); - } - proceed = 1; - while (proceed) { - if (find_file_data.cFileName[0] != L'.') { - int links; - - /* Construct the potential subdirectory name. */ - potname = get_mbstring_from_wstring(kpse->File_system_codepage, find_file_data.cFileName, potname=NULL); - fn_str_grow (&name, potname); - free(potname); - - /* Maybe we have cached the leafness of this directory. - The function will return 0 if unknown, - else the actual (Unix-like) value. */ - links = kpathsea_dir_links (kpse, FN_STRING (name), 0); - - if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - unsigned potential_len = FN_LENGTH (name); - /* in any case, compute the leafness */ - nlinks++; - - /* It's a directory, so append the separator. */ - fn_str_grow (&name, DIR_SEP_STRING); - if (*post != 0) { - fn_str_grow (&name, post); - /* Unfortunately we can't check if the new element is - a leaf directory, because we don't have a directory - name here, we just have a path spec. This means we - may descend into a leaf directory cm/pk, if the - spec is ...fonts//pk//. */ - expand_elt (kpse, str_list_ptr, FN_STRING (name), potential_len); - fn_shrink_to (&name, potential_len); - } - /* Should we recurse? To see if the subdirectory is a - leaf, check if it has two links (one for . and one for - ..). This means that symbolic links to directories do - not affect the leaf-ness. This is arguably wrong, but - the only alternative I know of is to stat every entry - in the directory, and that is unacceptably slow. */ - - if (links == 0 || links > 2) - /* All criteria are met; find subdirectories. */ - do_subdir (kpse, str_list_ptr, FN_STRING (name), - potential_len, post); - else if (*post == 0) - /* Nothing to match, no recursive subdirectories to - look for: we're done with this branch. Add it. */ - dir_list_add (str_list_ptr, FN_STRING (name)); - } - fn_shrink_to (&name, elt_length); - } - proceed = FindNextFileW (hnd, &find_file_data); - } - /* Update the leafness of name. */ - kpathsea_dir_links(kpse, FN_STRING(name), nlinks); - fn_free (&name); - FindClose(hnd); - -#else /* not WIN32 */ - - /* If we can't open it, quit. */ - dir = opendir (FN_STRING (name)); - if (dir == NULL) - { - fn_free (&name); - return; - } - - /* Include top level before subdirectories, if nothing to match. */ - if (*post == 0) - dir_list_add (str_list_ptr, FN_STRING (name)); - else - { /* If we do have something to match, see if it exists. For - example, POST might be `pk/ljfour', and they might have a - directory `$TEXMF/fonts/pk/ljfour' that we should find. */ - fn_str_grow (&name, post); - expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length); - fn_shrink_to (&name, elt_length); - } - - while ((e = readdir (dir)) != NULL) - { /* If it begins with a `.', never mind. (This allows ``hidden'' - directories that the algorithm won't find.) */ - if (e->d_name[0] != '.') - { - int links; - - /* Construct the potential subdirectory name. */ - fn_str_grow (&name, e->d_name); - - /* If we can't stat it, or if it isn't a directory, continue. */ - links = kpathsea_dir_links (kpse, FN_STRING (name), 0); - - if (links >= 0) - { - unsigned potential_len = FN_LENGTH (name); - - /* It's a directory, so append the separator. */ - fn_str_grow (&name, DIR_SEP_STRING); - - if (*post != 0) - { - fn_str_grow (&name, post); - /* Unfortunately we can't check if the new element is - a leaf directory, because we don't have a directory - name here, we just have a path spec. This means we - may descend into a leaf directory cm/pk, if the - spec is ...fonts//pk//. */ - expand_elt (kpse, str_list_ptr, FN_STRING (name), - potential_len); - fn_shrink_to (&name, potential_len); - } - - /* Should we recurse? To see if the subdirectory is a - leaf, check if it has two links (one for . and one for - ..). This means that symbolic links to directories do - not affect the leaf-ness. This is arguably wrong, but - the only alternative I know of is to stat every entry - in the directory, and that is unacceptably slow. - - The #ifdef here makes all this configurable at - compile-time, so that if we're using VMS directories or - some such, we can still find subdirectories, even if it - is much slower. */ -#ifdef ST_NLINK_TRICK - /* With SAS/C++ 6.55 on the Amiga, stat sets the st_nlink - field to -1 for a file, or to 1 for a directory. - Cygwin 1.7 also leaves st_nlink as 1: - http://cygwin.com/ml/cygwin-developers/2008-04/msg00110.html - */ - if (links != 2) -#endif /* ST_NLINK_TRICK */ - /* All criteria are met; find subdirectories. */ - do_subdir (kpse, str_list_ptr, FN_STRING (name), - potential_len, post); -#ifdef ST_NLINK_TRICK - else if (*post == 0) - /* Nothing to match, no recursive subdirectories to - look for: we're done with this branch. Add it. */ - dir_list_add (str_list_ptr, FN_STRING (name)); -#endif - } - - /* Remove the directory entry we just checked from `name'. */ - fn_shrink_to (&name, elt_length); - } - } - - fn_free (&name); - xclosedir (dir); -#endif /* not WIN32 */ -} - - -/* Assume ELT is non-empty and non-NULL. Return list of corresponding - directories (with no terminating NULL entry) in STR_LIST_PTR. Start - looking for magic constructs at START. */ - -static void -expand_elt (kpathsea kpse, str_llist_type * str_list_ptr, string elt, - unsigned start) -{ - string dir = elt + start, post; - - while (*dir != 0) - { - if (IS_DIR_SEP_CH (*dir)) - { - /* If two or more consecutive /'s, find subdirectories. */ - if (IS_DIR_SEP_CH (dir[1])) - { - for (post = dir + 1; IS_DIR_SEP_CH (*post); post++) ; - do_subdir (kpse, str_list_ptr, elt, dir - elt + 1, post); - return; - } - - /* No special stuff at this slash. Keep going. */ - } - - dir++; - } - - /* When we reach the end of ELT, it will be a normal filename. */ - checked_dir_list_add (kpse, str_list_ptr, elt); -} - -/* On win32 we slashify ELT, i.e., change '\\' to '/', and then can use - IS_DIR_SEP_CH instead of IS_DIR_SEP and need not test for the presence - of 2-Byte Kanji (CP 932, SJIS) codes. */ - -/* The first bits of a path element can be problematic because they - look like a request to expand a whole disk, rather than a subtree. - - It can contain a drive specification. - - It can be a UNC path (w32, but they are part of the single - Unix specification as well). - The argument is a string as the function can diddle into the argument - to canonicalize it, which tends to matter on windows platforms. - - Always lower-case drive letters a-z, even those filesystem that - preserve case in filenames do not care about the case of the drive - letters. - - Remove unneeded double slashes. The problem is Windows does not - handle well filenames like c://dir/foo. So canonicalize the names. - The resulting name will always be shorter than the one passed, so no - problem. - - Remove multiple leading slashes to prevent expanding from the root - of a UNIX filesystem tree. */ - -unsigned -kpathsea_normalize_path (kpathsea kpse, string elt) -{ - unsigned ret; - unsigned i; - -#if defined(WIN32) - for (i = 0; elt[i]; i++) { - if (elt[i] == '\\') - elt[i] = '/'; - else if (kpathsea_IS_KANJI(kpse, elt + i)) - i++; - } -#endif - - if (NAME_BEGINS_WITH_DEVICE(elt)) { - if (*elt >= 'A' && *elt <= 'Z') - *elt += 'a' - 'A'; - ret = 2; - - } else if (IS_UNC_NAME(elt)) { - for (ret = 2; elt[ret] && !IS_DIR_SEP_CH(elt[ret]); ret++) - ; - - } else - ret = 0; - - for (i = ret; IS_DIR_SEP_CH(elt[i]); ++i) - ; - if (i > ret + 1) { -#ifdef KPSE_DEBUG - if (KPATHSEA_DEBUG_P (KPSE_DEBUG_STAT)) - DEBUGF2 ("kpse_normalize_path (%s) => %u\n", elt, ret); -#endif /* KPSE_DEBUG */ - - memmove (elt + ret + 1, elt + i, strlen (elt + i) + 1); - } - - return ret; -} - -/* Here is the entry point. Returns directory list for ELT. */ - -str_llist_type * -kpathsea_element_dirs (kpathsea kpse, string elt) -{ - str_llist_type *ret; - unsigned i; - -#ifdef _WIN32 - char *tname = NULL; - wchar_t *wtname = NULL; -#endif /* _WIN32 */ - - /* If given nothing, return nothing. */ - if (!elt || !*elt) - return NULL; - -#ifdef _WIN32 -/* - Change encoding of a variable into kpse->File_system_codepage - to support non-ascii values for the variable. -*/ - if (kpse->File_system_codepage != kpse->Win32_codepage) { - wtname = get_wstring_from_mbstring (kpse->Win32_codepage, - elt, wtname = NULL); - tname = get_mbstring_from_wstring (kpse->File_system_codepage, - wtname, tname = NULL); - elt = tname; - free(wtname); - } -#endif /* _WIN32 */ - - /* Normalize ELT before looking for a cached value. */ - i = kpathsea_normalize_path (kpse, elt); - - /* If we've already cached the answer for ELT, return it. */ - ret = cached (kpse, elt); -#ifdef _WIN32 - if (ret) { - if (tname) free (tname); - return ret; - } -#else - if (ret) - return ret; -#endif /* _WIN32 */ - - /* We're going to have a real directory list to return. */ - ret = XTALLOC1 (str_llist_type); - *ret = NULL; - - /* We handle the hard case in a subroutine. */ - expand_elt (kpse, ret, elt, i); - - /* Remember the directory list we just found, in case future calls are - made with the same ELT. */ - cache (kpse, elt, ret); - -#ifdef KPSE_DEBUG - if (KPATHSEA_DEBUG_P (KPSE_DEBUG_EXPAND)) - { - DEBUGF1 ("path element %s =>", elt); - if (ret) - { - str_llist_elt_type *e; - for (e = *ret; e; e = STR_LLIST_NEXT (*e)) - fprintf (stderr, " %s", STR_LLIST (*e)); - } - putc ('\n', stderr); - fflush (stderr); - } -#endif /* KPSE_DEBUG */ - -#ifdef _WIN32 - if (tname) free (tname); -#endif /* _WIN32 */ - - return ret; -} - -#ifdef TEST - -void -print_element_dirs (const_string elt) -{ - str_llist_type *dirs; - - printf ("Directories of %s:\t", elt ? elt : "(nil)"); - fflush (stdout); - - dirs = kpathsea_element_dirs (kpse_def, elt); - - if (!dirs) - printf ("(nil)"); - else - { - str_llist_elt_type *dir; - for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir)) - { - string d = STR_LLIST (*dir); - printf ("%s ", *d ? d : "`'"); - } - } - - putchar ('\n'); -} - -int -main () -{ - /* DEBUG_SET (DEBUG_STAT); */ - /* All lists end with NULL. */ - print_element_dirs (NULL); /* */ - print_element_dirs (""); /* ./ */ - print_element_dirs ("/k"); /* */ - print_element_dirs (".//"); /* ./ ./archive/ */ - print_element_dirs (".//archive"); /* ./ ./archive/ */ -#ifdef AMIGA - print_element_dirs ("TeXMF:AmiWeb2c/texmf/fonts//"); /* lots */ - print_element_dirs ("TeXMF:AmiWeb2c/share/texmf/fonts//bakoma"); /*just one*/ - print_element_dirs ("TeXMF:AmiWeb2c/texmf/fonts//"); /* lots again [cache] */ - print_element_dirs ("TeXMF:"); /* TeXMF: */ - print_element_dirs ("TeXMF:/"); /* TeXMF: and all subdirs */ -#else /* not AMIGA */ - print_element_dirs ("/tmp/fonts//"); /* no need to stat anything */ - print_element_dirs ("/usr/local/lib/tex/fonts//"); /* lots */ - print_element_dirs ("/usr/local/lib/tex/fonts//times"); /* just one */ - print_element_dirs ("/usr/local/lib/tex/fonts//"); /* lots again [cache] */ - print_element_dirs ("~karl"); /* tilde expansion */ - print_element_dirs ("$karl"); /* variable expansion */ - print_element_dirs ("~${LOGNAME}"); /* both */ -#endif /* not AMIGA */ - return 0; -} - -#endif /* TEST */ - - -/* -Local variables: -standalone-compile-command: "gcc -g -I. -I.. -DTEST elt-dirs.c kpathsea.a" -End: -*/ |