kpse.cc

Go to the documentation of this file.
00001 // This file is not compiled to a separate object file.  It is
00002 // included in pathsearch.cc.
00003 
00004 /* Look up a filename in a path.
00005 
00006 Copyright (C) 1993, 94, 95, 96, 97, 98 Karl Berry.
00007 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry & O. Weber.
00008 Copyright (C) 1992, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Library General Public
00012 License as published by the Free Software Foundation; either
00013 version 2 of the License, or (at your option) any later version.
00014 
00015 This library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Library General Public License for more details.
00019 
00020 You should have received a copy of the GNU Library General Public
00021 License along with this library; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00023 02110-1301, USA.  */
00024 
00025 #if defined (HAVE_CONFIG_H)
00026 #include <config.h>
00027 #endif
00028 
00029 #include <map>
00030 #include <string>
00031 
00032 /* System defines are for non-Unix systems only.  (Testing for all Unix
00033    variations should be done in configure.)  Presently the defines used
00034    are: DOS OS2 WIN32.  I do not use any of these systems
00035    myself; if you do, I'd be grateful for any changes. --kb@mail.tug.org */
00036 
00037 /* If we have either DOS or OS2, we are DOSISH.  */
00038 #if defined (DOS) || defined (OS2) || defined (WIN32) || defined(__MSDOS__)
00039 #define DOSISH
00040 #endif
00041 
00042 #if defined (DOSISH)
00043 #define MONOCASE_FILENAMES      /* case-insensitive filename comparisons */
00044 #endif
00045 
00046 extern "C" {
00047 #if defined(__MINGW32__)
00048 #include <windows.h>
00049 #include <fcntl.h>
00050 #include <dirent.h>
00051 #elif defined(WIN32)
00052 #ifndef _MSC_VER
00053 #define __STDC__ 1
00054 #include "win32lib.h"
00055 #endif
00056 #endif /* not WIN32 */
00057 
00058 #ifdef __DJGPP__
00059 #include <fcntl.h>      /* for long filenames' stuff */
00060 #include <dir.h>        /* for 'getdisk' */
00061 #include <io.h>         /* for 'setmode' */
00062 #endif
00063 }
00064 
00065 /* Some drivers have partially integrated kpathsea changes.  */
00066 #ifndef KPATHSEA
00067 #define KPATHSEA 32
00068 #endif
00069 
00070 /* System dependencies that are figured out by 'configure'.  If we are
00071    compiling standalone, we get our c-auto.h.  Otherwise, the package
00072    containing us must provide this (unless it can somehow generate ours
00073    from c-auto.in).  We use <...> instead of "..." so that the current
00074    cpp directory (i.e., kpathsea/) won't be searched. */
00075 
00076 /* If you want to find subdirectories in a directory with non-Unix
00077    semantics (specifically, if a directory with no subdirectories does
00078    not have exactly two links), define this.  */
00079 #if defined(__DJGPP__) || ! defined (DOSISH)
00080 /* Surprise!  DJGPP returns st_nlink exactly like on Unix.  */
00081 #define ST_NLINK_TRICK
00082 #endif /* either not DOSISH or __DJGPP__ */
00083 
00084 #ifdef OS2
00085 #define access ln_access
00086 #define fopen ln_fopen
00087 #define rename ln_rename
00088 #define stat ln_stat
00089 #endif /* OS2 */
00090 
00091 /* Define the characters which separate components of
00092    filenames and environment variable paths.  */
00093 
00094 /* What separates filename components?  */
00095 #ifndef DIR_SEP
00096 #ifdef DOSISH
00097 /* Either \'s or 's work.  Wayne Sullivan's web2pc prefers /, so we'll
00098    go with that.  */
00099 #define DIR_SEP '/'
00100 #define DIR_SEP_STRING "/"
00101 #define IS_DEVICE_SEP(ch) ((ch) == ':')
00102 #define NAME_BEGINS_WITH_DEVICE(name) ((name.length()>0) && IS_DEVICE_SEP((name)[1]))
00103 /* On DOS, it's good to allow both \ and / between directories.  */
00104 #define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\')
00105 #else
00106 #define DIR_SEP '/'
00107 #define DIR_SEP_STRING "/"
00108 #endif /* not DOSISH */
00109 #endif /* not DIR_SEP */
00110 
00111 #ifndef IS_DIR_SEP
00112 #define IS_DIR_SEP(ch) ((ch) == DIR_SEP)
00113 #endif
00114 #ifndef IS_DEVICE_SEP /* No 'devices' on, e.g., Unix.  */
00115 #define IS_DEVICE_SEP(ch) 0
00116 #endif
00117 #ifndef NAME_BEGINS_WITH_DEVICE
00118 #define NAME_BEGINS_WITH_DEVICE(name) 0
00119 #endif
00120 
00121 #include "lo-error.h"
00122 #include "oct-env.h"
00123 #include "oct-passwd.h"
00124 #include "str-vec.h"
00125 
00126 /* Header files that essentially all of our sources need, and
00127    that all implementations have.  We include these first, to help with
00128    NULL being defined multiple times.  */
00129 #include <cstdio>
00130 #include <cstdarg>
00131 #include <cstdlib>
00132 #include <climits>
00133 #include <cerrno>
00134 #include <cassert>
00135 
00136 #include <sys/types.h>
00137 #include <unistd.h>
00138 
00139 #include "sysdir.h"
00140 #include "statdefs.h"
00141 
00142 /* define NAME_MAX, the maximum length of a single
00143    component in a filename.  No such limit may exist, or may vary
00144    depending on the filesystem.  */
00145 
00146 /* Most likely the system will truncate filenames if it is not POSIX,
00147    and so we can use the BSD value here.  */
00148 #ifndef _POSIX_NAME_MAX
00149 #define _POSIX_NAME_MAX 255
00150 #endif
00151 
00152 #ifndef NAME_MAX
00153 #define NAME_MAX _POSIX_NAME_MAX
00154 #endif
00155 
00156 #include <cctype>
00157 
00158 /* What separates elements in environment variable path lists?  */
00159 #ifndef ENV_SEP
00160 #if defined (SEPCHAR) && defined (SEPCHAR_STR)
00161 #define ENV_SEP SEPCHAR
00162 #define ENV_SEP_STRING SEPCHAR_STR
00163 #elif defined (DOSISH)
00164 #define ENV_SEP ';'
00165 #define ENV_SEP_STRING ";"
00166 #else
00167 #define ENV_SEP ':'
00168 #define ENV_SEP_STRING ":"
00169 #endif /* not DOS */
00170 #endif /* not ENV_SEP */
00171 
00172 #ifndef IS_ENV_SEP
00173 #define IS_ENV_SEP(ch) ((ch) == ENV_SEP)
00174 #endif
00175 
00176 /* define PATH_MAX, the maximum length of a filename.  Since no such
00177    limit may exist, it's preferable to dynamically grow filenames as
00178    needed.  */
00179 
00180 /* Cheat and define this as a manifest constant no matter what, instead
00181    of using pathconf.  I forget why we want to do this.  */
00182 
00183 #ifndef _POSIX_PATH_MAX
00184 #define _POSIX_PATH_MAX 255
00185 #endif
00186 
00187 #ifndef PATH_MAX
00188 #ifdef MAXPATHLEN
00189 #define PATH_MAX MAXPATHLEN
00190 #else
00191 #define PATH_MAX _POSIX_PATH_MAX
00192 #endif
00193 #endif /* not PATH_MAX */
00194 
00195 /* If NO_DEBUG is defined (not recommended), skip all this.  */
00196 #ifndef NO_DEBUG
00197 
00198 /* OK, we'll have tracing support.  */
00199 #define KPSE_DEBUG
00200 
00201 /* Test if a bit is on.  */
00202 #define KPSE_DEBUG_P(bit) (kpathsea_debug & (1 << (bit)))
00203 
00204 #define KPSE_DEBUG_STAT 0               /* stat calls */
00205 #define KPSE_DEBUG_HASH 1               /* hash lookups */
00206 #define KPSE_DEBUG_FOPEN 2              /* fopen/fclose calls */
00207 #define KPSE_DEBUG_PATHS 3              /* search path initializations */
00208 #define KPSE_DEBUG_EXPAND 4             /* path element expansion */
00209 #define KPSE_DEBUG_SEARCH 5             /* searches */
00210 #define KPSE_DEBUG_VARS 6               /* variable values */
00211 #define KPSE_LAST_DEBUG KPSE_DEBUG_VARS
00212 
00213 /* A printf for the debugging.  */
00214 #define DEBUGF_START() do { gnulib::fputs ("kdebug:", stderr)
00215 #define DEBUGF_END()        gnulib::fflush (stderr); } while (0)
00216 
00217 #define DEBUGF(str)                                                     \
00218   DEBUGF_START (); gnulib::fputs (str, stderr); DEBUGF_END ()
00219 #define DEBUGF1(str, e1)                                                \
00220   DEBUGF_START (); gnulib::fprintf (stderr, str, e1); DEBUGF_END ()
00221 #define DEBUGF2(str, e1, e2)                                            \
00222   DEBUGF_START (); gnulib::fprintf (stderr, str, e1, e2); DEBUGF_END ()
00223 #define DEBUGF3(str, e1, e2, e3)                                        \
00224   DEBUGF_START (); gnulib::fprintf (stderr, str, e1, e2, e3); DEBUGF_END ()
00225 #define DEBUGF4(str, e1, e2, e3, e4)                                    \
00226   DEBUGF_START (); gnulib::fprintf (stderr, str, e1, e2, e3, e4); DEBUGF_END ()
00227 
00228 #endif /* not NO_DEBUG */
00229 
00230 #ifdef KPSE_DEBUG
00231 static unsigned int kpathsea_debug = 0;
00232 #endif
00233 
00234 #if defined (WIN32) && !defined (__MINGW32__)
00235 
00236 /* System description file for Windows NT.  */
00237 
00238 /*
00239  *      Define symbols to identify the version of Unix this is.
00240  *      Define all the symbols that apply correctly.
00241  */
00242 
00243 #ifndef DOSISH
00244 #define DOSISH
00245 #endif
00246 
00247 #ifndef MAXPATHLEN
00248 #define MAXPATHLEN      _MAX_PATH
00249 #endif
00250 
00251 /* These have to be defined because our compilers treat __STDC__ as being
00252    defined (most of them anyway). */
00253 
00254 #define access  _access
00255 #define stat    _stat
00256 #define strdup  _strdup
00257 
00258 #define S_IFMT   _S_IFMT
00259 #define S_IFDIR  _S_IFDIR
00260 
00261 /* Define this so that winsock.h definitions don't get included when
00262    windows.h is...  For this to have proper effect, config.h must
00263    always be included before windows.h.  */
00264 #define _WINSOCKAPI_    1
00265 
00266 #include <windows.h>
00267 
00268 /* For proper declaration of environ.  */
00269 #include <io.h>
00270 #include <fcntl.h>
00271 #include <process.h>
00272 
00273 /* ============================================================ */
00274 
00275 #endif /* WIN32 */
00276 
00277 /* Define common sorts of messages.  */
00278 
00279 /* This should be called only after a system call fails.  Don't exit
00280    with status 'errno', because that might be 256, which would mean
00281    success (exit statuses are truncated to eight bits).  */
00282 #define FATAL_PERROR(str) \
00283   do \
00284     { \
00285       gnulib::fputs ("pathsearch: ", stderr); \
00286       perror (str); exit (EXIT_FAILURE); \
00287     } \
00288   while (0)
00289 
00290 #define FATAL(str) \
00291   do \
00292     { \
00293       gnulib::fputs ("pathsearch: fatal: ", stderr); \
00294       gnulib::fputs (str, stderr); \
00295       gnulib::fputs (".\n", stderr); \
00296       exit (1); \
00297     } \
00298   while (0)
00299 
00300 #ifndef WIN32
00301 static void xclosedir (DIR *d);
00302 #endif
00303 
00304 /* It's a little bizarre to be using the same type for the list and the
00305    elements of the list, but no reason not to in this case, I think --
00306    we never need a NULL string in the middle of the list, and an extra
00307    NULL/NULL element always at the end is inconsequential.  */
00308 
00309 struct str_llist_elt
00310 {
00311   str_llist_elt (void) : str (), moved (0), next (0) { }
00312 
00313   ~str_llist_elt (void) { }
00314 
00315   std::string str;
00316   int moved;
00317   struct str_llist_elt *next;
00318 };
00319 
00320 typedef str_llist_elt str_llist_elt_type;
00321 typedef str_llist_elt *str_llist_type;
00322 
00323 #define STR_LLIST(sl) ((sl).str)
00324 #define STR_LLIST_MOVED(sl) ((sl).moved)
00325 #define STR_LLIST_NEXT(sl) ((sl).next)
00326 
00327 static void str_llist_add (str_llist_type *l, const std::string& str);
00328 
00329 static void str_llist_float (str_llist_type *l, str_llist_elt_type *mover);
00330 
00331 static std::string kpse_var_expand (const std::string& src);
00332 
00333 static str_llist_type *kpse_element_dirs (const std::string& elt);
00334 
00335 static std::string kpse_expand (const std::string& s);
00336 
00337 static std::string kpse_expand_default (const std::string& path,
00338                                         const std::string& dflt);
00339 
00340 static string_vector kpse_db_search (const std::string& name,
00341                                      const std::string& path_elt, bool all);
00342 
00343 #include <ctime> /* for 'time' */
00344 
00345 static bool
00346 kpse_is_env_sep (char c)
00347 {
00348   return IS_ENV_SEP (c);
00349 }
00350 
00351 /* These routines just check the return status from standard library
00352    routines and abort if an error happens.  */
00353 
00354 static FILE *
00355 xfopen (const std::string& filename, const char *mode)
00356 {
00357   FILE *f;
00358 
00359   assert (! filename.empty () && mode);
00360 
00361   f = gnulib::fopen (filename.c_str (), mode);
00362 
00363   if (! f)
00364     FATAL_PERROR (filename.c_str ());
00365 
00366   if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN))
00367     DEBUGF3 ("fopen (%s, %s) => 0x%lx\n", filename.c_str (), mode,
00368              reinterpret_cast<unsigned long> (f));
00369 
00370   return f;
00371 }
00372 
00373 /* A single (key,value) pair.  */
00374 
00375 struct hash_element_type
00376 {
00377   std::string key;
00378   std::string value;
00379   struct hash_element_type *next;
00380 };
00381 
00382 /* The usual arrangement of buckets initialized to null.  */
00383 
00384 struct hash_table_type
00385 {
00386   hash_element_type **buckets;
00387   unsigned size;
00388 };
00389 
00390 static unsigned
00391 kpse_hash (hash_table_type table, const std::string& key)
00392 {
00393   unsigned n = 0;
00394 
00395   /* Our keys aren't often anagrams of each other, so no point in
00396      weighting the characters.  */
00397   size_t len = key.length ();
00398   for (size_t i = 0; i < len; i++)
00399     n = (n + n + key[i]) % table.size;
00400 
00401   return n;
00402 }
00403 
00404 /* Look up STR in MAP.  Return a (dynamically-allocated) list of the
00405    corresponding strings or NULL if no match.  */
00406 
00407 static string_vector
00408 hash_lookup (hash_table_type table, const std::string& key)
00409 {
00410   hash_element_type *p;
00411   string_vector ret;
00412   unsigned n = kpse_hash (table, key);
00413 
00414   /* Look at everything in this bucket.  */
00415   for (p = table.buckets[n]; p; p = p->next)
00416     if (key == p->key)
00417       ret.append (p->value);
00418 
00419 #ifdef KPSE_DEBUG
00420   if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
00421     {
00422       DEBUGF1 ("hash_lookup (%s) =>", key.c_str ());
00423       if (ret.empty ())
00424         gnulib::fputs (" (nil)\n", stderr);
00425       else
00426         {
00427           int len = ret.length ();
00428           for (int i = 0; i < len; i++)
00429             {
00430               gnulib::putc (' ', stderr);
00431               gnulib::fputs (ret[i].c_str (), stderr);
00432             }
00433           gnulib::putc ('\n', stderr);
00434         }
00435       gnulib::fflush (stderr);
00436     }
00437 #endif
00438 
00439   return ret;
00440 }
00441 
00442 /* A way to step through a path, extracting one directory name at a
00443    time.  */
00444 
00445 class kpse_path_iterator
00446 {
00447 public:
00448 
00449   kpse_path_iterator (const std::string& p)
00450     : path (p), b (0), e (0), len (path.length ()) { set_end (); }
00451 
00452   kpse_path_iterator (const kpse_path_iterator& pi)
00453     : path (pi.path), b (pi.b), e (pi.e), len (pi.len) { }
00454 
00455   kpse_path_iterator operator ++ (int)
00456     {
00457       kpse_path_iterator retval (*this);
00458       next ();
00459       return retval;
00460     }
00461 
00462   std::string operator * (void) { return path.substr (b, e-b); }
00463 
00464   bool operator != (const size_t sz) { return b != sz; }
00465 
00466 private:
00467 
00468   const std::string& path;
00469   size_t b;
00470   size_t e;
00471   size_t len;
00472 
00473   void set_end (void)
00474     {
00475       e = b + 1;
00476 
00477       if (e == len)
00478         ; /* OK, we have found the last element.  */
00479       else if (e > len)
00480         b = e = std::string::npos;
00481       else
00482         {
00483           /* Find the next colon not enclosed by braces (or the end of
00484              the path).  */
00485 
00486           int brace_level = 0;
00487           while (e < len && ! (brace_level == 0 && kpse_is_env_sep (path[e])))
00488             e++;
00489         }
00490     }
00491 
00492   void next (void)
00493     {
00494       b = e + 1;
00495 
00496       /* Skip any consecutive colons.  */
00497       while (b < len && kpse_is_env_sep (path[b]))
00498         b++;
00499 
00500       if (b >= len)
00501         b = e = std::string::npos;
00502       else
00503         set_end ();
00504     }
00505 
00506   // No assignment.
00507   kpse_path_iterator& operator = (const kpse_path_iterator&);
00508 };
00509 
00510 /* Here's the simple one, when a program just wants a value.  */
00511 
00512 static std::string
00513 kpse_var_value (const std::string& var)
00514 {
00515   std::string ret;
00516 
00517   std::string tmp = octave_env::getenv (var);
00518 
00519   if (! tmp.empty ())
00520     ret = kpse_var_expand (tmp);
00521 
00522 #ifdef KPSE_DEBUG
00523   if (KPSE_DEBUG_P (KPSE_DEBUG_VARS))
00524     DEBUGF2 ("variable: %s = %s\n", var.c_str (),
00525              tmp.empty () ? "(nil)" :  tmp.c_str ());
00526 #endif
00527 
00528   return ret;
00529 }
00530 
00531 /* Truncate any too-long components in NAME, returning the result.  It's
00532    too bad this is necessary.  See comments in readable.c for why.  */
00533 
00534 static std::string
00535 kpse_truncate_filename (const std::string& name)
00536 {
00537   unsigned c_len = 0;        /* Length of current component.  */
00538   unsigned ret_len = 0;      /* Length of constructed result.  */
00539 
00540   std::string ret = name;
00541 
00542   size_t len = name.length ();
00543 
00544   for (size_t i = 0; i < len; i++)
00545     {
00546       if (IS_DIR_SEP (name[i]) || IS_DEVICE_SEP (name[i]))
00547         {
00548           /* At a directory delimiter, reset component length.  */
00549           c_len = 0;
00550         }
00551       else if (c_len > NAME_MAX)
00552         {
00553           /* If past the max for a component, ignore this character.  */
00554           continue;
00555         }
00556 
00557       /* Copy this character.  */
00558       ret[ret_len++] = name[i];
00559       c_len++;
00560     }
00561 
00562   ret.resize (ret_len);
00563 
00564   return ret;
00565 }
00566 
00567 /* If access can read FN, run stat (assigning to stat buffer ST) and
00568    check that fn is not a directory.  Don't check for just being a
00569    regular file, as it is potentially useful to read fifo's or some
00570    kinds of devices.  */
00571 
00572 #ifdef WIN32
00573 static inline bool
00574 READABLE (const std::string& fn, struct stat&)
00575 {
00576   const char *t = fn.c_str ();
00577   return (GetFileAttributes (t) != 0xFFFFFFFF
00578           && ! (GetFileAttributes (t) & FILE_ATTRIBUTE_DIRECTORY));
00579 }
00580 #else
00581 static inline bool
00582 READABLE (const std::string& fn, struct stat& st)
00583 {
00584   const char *t = fn.c_str ();
00585   return (access (t, R_OK) == 0
00586           && stat (t, &(st)) == 0 && ! S_ISDIR (st.st_mode));
00587 }
00588 #endif
00589 
00590 /* POSIX invented the brain-damage of not necessarily truncating
00591    filename components; the system's behavior is defined by the value of
00592    the symbol _POSIX_NO_TRUNC, but you can't change it dynamically!
00593 
00594    Generic const return warning.  See extend-fname.c.  */
00595 
00596 static std::string
00597 kpse_readable_file (const std::string& name)
00598 {
00599   struct stat st;
00600   std::string ret;
00601 
00602   if (READABLE (name, st))
00603     {
00604       ret = name;
00605 
00606 #ifdef ENAMETOOLONG
00607     }
00608   else if (errno == ENAMETOOLONG)
00609     {
00610       ret = kpse_truncate_filename (name);
00611 
00612       /* Perhaps some other error will occur with the truncated name,
00613          so let's call access again.  */
00614 
00615       if (! READABLE (ret, st))
00616         {
00617           /* Failed.  */
00618           ret = std::string ();
00619         }
00620 #endif /* ENAMETOOLONG */
00621 
00622     }
00623   else
00624     {
00625       /* Some other error.  */
00626       if (errno == EACCES)
00627         {
00628           /* Maybe warn them if permissions are bad.  */
00629           perror (name.c_str ());
00630         }
00631 
00632       ret = std::string ();
00633     }
00634 
00635   return ret;
00636 }
00637 
00638 /* Sorry this is such a system-dependent mess, but I can't see any way
00639    to usefully generalize.  */
00640 
00641 static bool
00642 kpse_absolute_p (const std::string& filename, int relative_ok)
00643 {
00644   size_t len = filename.length ();
00645 
00646   int absolute = (len > 0 && IS_DIR_SEP (filename[0]))
00647 #ifdef DOSISH
00648                      /* Novell allows non-alphanumeric drive letters. */
00649     || (len > 0 && IS_DEVICE_SEP (filename[1]))
00650 #endif /* DOSISH */
00651 #ifdef WIN32
00652                      /* UNC names */
00653     || (len > 1 && filename[0] == '\\' && filename[1] == '\\')
00654 #endif
00655     ;
00656 
00657   int explicit_relative
00658     = relative_ok
00659       && (len > 1
00660           && filename[0] == '.'
00661           && (IS_DIR_SEP (filename[1])
00662               || (len > 2 && filename[1] == '.' && IS_DIR_SEP (filename[2]))));
00663 
00664   return absolute || explicit_relative;
00665 }
00666 
00667 /* The very first search is for texmf.cnf, called when someone tries to
00668    initialize the TFM path or whatever.  init_path calls kpse_cnf_get
00669    which calls kpse_all_path_search to find all the texmf.cnf's.  We
00670    need to do various special things in this case, since we obviously
00671    don't yet have the configuration files when we're searching for the
00672    configuration files.  */
00673 static bool first_search = true;
00674 
00675 /* This function is called after every search (except the first, since
00676    we definitely want to allow enabling the logging in texmf.cnf) to
00677    record the filename(s) found in $TEXMFLOG.  */
00678 
00679 static void
00680 log_search (const string_vector& filenames)
00681 {
00682   static FILE *log_file = 0;
00683   static bool first_time = true; /* Need to open the log file?  */
00684 
00685   if (first_time)
00686     {
00687       first_time = false;
00688 
00689       /* Get name from either envvar or config file.  */
00690       std::string log_name = kpse_var_value ("TEXMFLOG");
00691 
00692       if (! log_name.empty ())
00693         {
00694           log_file = xfopen (log_name.c_str (), "a");
00695 
00696           if (! log_file)
00697             perror (log_name.c_str ());
00698         }
00699     }
00700 
00701   if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH) || log_file)
00702     {
00703       /* FILENAMES should never be null, but safety doesn't hurt.  */
00704       for (int e = 0; e < filenames.length () && ! filenames[e].empty (); e++)
00705         {
00706           std::string filename = filenames[e];
00707 
00708           /* Only record absolute filenames, for privacy.  */
00709           if (log_file && kpse_absolute_p (filename.c_str (), false))
00710             gnulib::fprintf (log_file, "%lu %s\n",
00711                      static_cast<unsigned long> (time (0)),
00712                      filename.c_str ());
00713 
00714           /* And show them online, if debugging.  We've already started
00715              the debugging line in 'search', where this is called, so
00716              just print the filename here, don't use DEBUGF.  */
00717           if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00718             gnulib::fputs (filename.c_str (), stderr);
00719         }
00720     }
00721 }
00722 
00723 /* Concatenate each element in DIRS with NAME (assume each ends with a
00724    /, to save time).  If SEARCH_ALL is false, return the first readable
00725    regular file.  Else continue to search for more.  In any case, if
00726    none, return a list containing just NULL.
00727 
00728    We keep a single buffer for the potential filenames and reallocate
00729    only when necessary.  I'm not sure it's noticeably faster, but it
00730    does seem cleaner.  (We do waste a bit of space in the return
00731    value, though, since we don't shrink it to the final size returned.)  */
00732 
00733 static string_vector
00734 dir_list_search (str_llist_type *dirs, const std::string& name,
00735                  bool search_all)
00736 {
00737   str_llist_elt_type *elt;
00738   string_vector ret;
00739 
00740   for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt))
00741     {
00742       const std::string dir = STR_LLIST (*elt);
00743 
00744       std::string potential = dir + name;
00745 
00746       std::string tmp = kpse_readable_file (potential);
00747 
00748       if (! tmp.empty ())
00749         {
00750           ret.append (potential);
00751 
00752           /* Move this element towards the top of the list.  */
00753           str_llist_float (dirs, elt);
00754 
00755           if (! search_all)
00756             return ret;
00757         }
00758     }
00759 
00760   return ret;
00761 }
00762 
00763 /* This is called when NAME is absolute or explicitly relative; if it's
00764    readable, return (a list containing) it; otherwise, return NULL.  */
00765 
00766 static string_vector
00767 absolute_search (const std::string& name)
00768 {
00769   string_vector ret_list;
00770   std::string found = kpse_readable_file (name);
00771 
00772   /* Add 'found' to the return list even if it's null; that tells
00773      the caller we didn't find anything.  */
00774   ret_list.append (found);
00775 
00776   return ret_list;
00777 }
00778 
00779 /* This is the hard case -- look for NAME in PATH.  If ALL is false,
00780    return the first file found.  Otherwise, search all elements of PATH.  */
00781 
00782 static string_vector
00783 path_search (const std::string& path, const std::string& name,
00784              bool /* must_exist */, bool all)
00785 {
00786   string_vector ret_list;
00787   bool done = false;
00788 
00789   for (kpse_path_iterator pi (path); ! done && pi != std::string::npos; pi++)
00790     {
00791       std::string elt = *pi;
00792 
00793       string_vector found;
00794       bool allow_disk_search = true;
00795 
00796       if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
00797         {
00798           /* Those magic leading chars in a path element means don't
00799              search the disk for this elt.  And move past the magic to
00800              get to the name.  */
00801           allow_disk_search = false;
00802           elt = elt.substr (2);
00803         }
00804 
00805       /* Do not touch the device if present */
00806       if (NAME_BEGINS_WITH_DEVICE (elt))
00807         {
00808           while (elt.length () > 3
00809                  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
00810             {
00811               elt[2] = elt[1];
00812               elt[1] = elt[0];
00813               elt = elt.substr (1);
00814             }
00815         }
00816       else
00817         {
00818           /* We never want to search the whole disk.  */
00819           while (elt.length () > 1
00820                  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
00821             elt = elt.substr (1);
00822         }
00823 
00824       /* Try ls-R, unless we're searching for texmf.cnf.  Our caller
00825          (search), also tests first_search, and does the resetting.  */
00826       found = first_search
00827         ? string_vector () : kpse_db_search (name, elt, all);
00828 
00829       /* Search the filesystem if (1) the path spec allows it, and either
00830          (2a) we are searching for texmf.cnf ; or
00831          (2b) no db exists; or
00832          (2c) no db's are relevant to this elt; or
00833          (3) MUST_EXIST && NAME was not in the db.
00834          In (2*), 'found' will be NULL.
00835          In (3),  'found' will be an empty list. */
00836 
00837       if (allow_disk_search && found.empty ())
00838         {
00839           str_llist_type *dirs = kpse_element_dirs (elt);
00840 
00841           if (dirs && *dirs)
00842             found = dir_list_search (dirs, name, all);
00843         }
00844 
00845       /* Did we find anything anywhere?  */
00846       if (! found.empty ())
00847         {
00848           if (all)
00849             ret_list.append (found);
00850           else
00851             {
00852               ret_list.append (found[0]);
00853               done = true;
00854             }
00855         }
00856     }
00857 
00858   return ret_list;
00859 }
00860 
00861 /* Search PATH for ORIGINAL_NAME.  If ALL is false, or ORIGINAL_NAME is
00862    absolute_p, check ORIGINAL_NAME itself.  Otherwise, look at each
00863    element of PATH for the first readable ORIGINAL_NAME.
00864 
00865    Always return a list; if no files are found, the list will
00866    contain just NULL.  If ALL is true, the list will be
00867    terminated with NULL.  */
00868 
00869 static string_vector
00870 search (const std::string& path, const std::string& original_name,
00871         bool must_exist, bool all)
00872 {
00873   string_vector ret_list;
00874   bool absolute_p;
00875 
00876   /* Make a leading ~ count as an absolute filename, and expand $FOO's.  */
00877   std::string name = kpse_expand (original_name);
00878 
00879   /* If the first name is absolute or explicitly relative, no need to
00880      consider PATH at all.  */
00881   absolute_p = kpse_absolute_p (name, true);
00882 
00883   if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00884     DEBUGF4 ("start search (file=%s, must_exist=%d, find_all=%d, path=%s).\n",
00885              name.c_str (), must_exist, all, path.c_str ());
00886 
00887   /* Find the file(s). */
00888   ret_list = absolute_p ? absolute_search (name)
00889                         : path_search (path, name, must_exist, all);
00890 
00891   /* The very first search is for texmf.cnf.  We can't log that, since
00892      we want to allow setting TEXMFLOG in texmf.cnf.  */
00893   if (first_search)
00894     {
00895       first_search = false;
00896     }
00897   else
00898     {
00899       /* Record the filenames we found, if desired.  And wrap them in a
00900          debugging line if we're doing that.  */
00901 
00902       if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00903         DEBUGF1 ("search (%s) =>", original_name.c_str ());
00904 
00905       log_search (ret_list);
00906 
00907       if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00908         gnulib::putc ('\n', stderr);
00909     }
00910 
00911   return ret_list;
00912 }
00913 
00914 /* Search PATH for the first NAME.  */
00915 
00916 /* Call 'kpse_expand' on NAME.  If the result is an absolute or
00917    explicitly relative filename, check whether it is a readable
00918    (regular) file.
00919 
00920    Otherwise, look in each of the directories specified in PATH (also do
00921    tilde and variable expansion on elements in PATH), using a prebuilt
00922    db (see db.h) if it's relevant for a given path element.
00923 
00924    If the prebuilt db doesn't exist, or if MUST_EXIST is true and NAME
00925    isn't found in the prebuilt db, look on the filesystem.  (I.e., if
00926    MUST_EXIST is false, and NAME isn't found in the db, do *not* look on
00927    the filesystem.)
00928 
00929    The caller must expand PATH. This is because it makes more sense to
00930    do this once, in advance, instead of for every search using it.
00931 
00932    In any case, return the complete filename if found, otherwise NULL.  */
00933 
00934 static std::string
00935 kpse_path_search (const std::string& path, const std::string& name,
00936                   bool must_exist)
00937 {
00938   string_vector ret_list = search (path, name, must_exist, false);
00939 
00940   return ret_list.empty () ? std::string () : ret_list[0];
00941 }
00942 
00943 /* Search all elements of PATH for files named NAME.  Not sure if it's
00944    right to assert 'must_exist' here, but it suffices now.  */
00945 
00946 /* Like 'kpse_path_search' with MUST_EXIST true, but return a list of
00947    all the filenames (or NULL if none), instead of taking the first.  */
00948 
00949 static string_vector
00950 kpse_all_path_search (const std::string& path, const std::string& name)
00951 {
00952   return search (path, name, true, true);
00953 }
00954 
00955 /* This is the hard case -- look in each element of PATH for each
00956    element of NAMES.  If ALL is false, return the first file found.
00957    Otherwise, search all elements of PATH.  */
00958 
00959 static string_vector
00960 path_find_first_of (const std::string& path, const string_vector& names,
00961                     bool /* must_exist */, bool all)
00962 {
00963   string_vector ret_list;
00964   bool done = false;
00965 
00966   for (kpse_path_iterator pi (path); ! done && pi != std::string::npos; pi++)
00967     {
00968       std::string elt = *pi;
00969 
00970       str_llist_type *dirs;
00971       str_llist_elt_type *dirs_elt;
00972       string_vector found;
00973       bool allow_disk_search = true;
00974 
00975       if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
00976         {
00977           /* Those magic leading chars in a path element means don't
00978              search the disk for this elt.  And move past the magic to
00979              get to the name.  */
00980 
00981           allow_disk_search = false;
00982           elt = elt.substr (2);
00983         }
00984 
00985       /* Do not touch the device if present */
00986 
00987       if (NAME_BEGINS_WITH_DEVICE (elt))
00988         {
00989           while (elt.length () > 3
00990                  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
00991             {
00992               elt[2] = elt[1];
00993               elt[1] = elt[0];
00994               elt = elt.substr (1);
00995             }
00996         }
00997       else
00998         {
00999           /* We never want to search the whole disk.  */
01000           while (elt.length () > 1
01001                  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
01002             elt = elt.substr (1);
01003         }
01004 
01005       /* We have to search one directory at a time.  */
01006       dirs = kpse_element_dirs (elt);
01007       for (dirs_elt = *dirs; dirs_elt; dirs_elt = STR_LLIST_NEXT (*dirs_elt))
01008         {
01009           const std::string dir = STR_LLIST (*dirs_elt);
01010 
01011           int len = names.length ();
01012           for (int i = 0; i < len && !done; i++)
01013             {
01014               std::string name = names[i];
01015 
01016               /* Try ls-R, unless we're searching for texmf.cnf.  Our caller
01017                  (find_first_of), also tests first_search, and does the
01018                  resetting.  */
01019               found = first_search
01020                 ? string_vector () : kpse_db_search (name, dir.c_str (), all);
01021 
01022               /* Search the filesystem if (1) the path spec allows it,
01023                  and either
01024 
01025                    (2a) we are searching for texmf.cnf ; or
01026                    (2b) no db exists; or
01027                    (2c) no db's are relevant to this elt; or
01028                    (3) MUST_EXIST && NAME was not in the db.
01029 
01030                  In (2*), 'found' will be NULL.
01031                  In (3),  'found' will be an empty list. */
01032 
01033               if (allow_disk_search && found.empty ())
01034                 {
01035                   static str_llist_type *tmp = 0;
01036 
01037                   if (! tmp)
01038                     {
01039                       tmp = new str_llist_type;
01040                       *tmp = 0;
01041                       str_llist_add (tmp, "");
01042                     }
01043 
01044                   STR_LLIST (*(*tmp)) = dir;
01045 
01046                   found = dir_list_search (tmp, name, all);
01047                 }
01048 
01049               /* Did we find anything anywhere?  */
01050               if (! found.empty ())
01051                 {
01052                   if (all)
01053                     ret_list.append (found);
01054                   else
01055                     {
01056                       ret_list.append (found[0]);
01057                       done = true;
01058                     }
01059                 }
01060             }
01061         }
01062     }
01063 
01064   return ret_list;
01065 }
01066 
01067 static string_vector
01068 find_first_of (const std::string& path, const string_vector& names,
01069                bool must_exist, bool all)
01070 {
01071   string_vector ret_list;
01072 
01073   if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01074     {
01075       gnulib::fputs ("start find_first_of ((", stderr);
01076 
01077       int len = names.length ();
01078 
01079       for (int i = 0; i < len; i++)
01080         {
01081           if (i == 0)
01082             gnulib::fputs (names[i].c_str (), stderr);
01083           else
01084             gnulib::fprintf (stderr, ", %s", names[i].c_str ());
01085         }
01086 
01087       gnulib::fprintf (stderr, "), path=%s, must_exist=%d).\n",
01088                        path.c_str (), must_exist);
01089     }
01090 
01091   for (int i = 0; i < names.length (); i++)
01092     {
01093       std::string name = names[i];
01094 
01095       if (kpse_absolute_p (name, true))
01096         {
01097           /* If the name is absolute or explicitly relative, no need
01098              to consider PATH at all.  If we find something, then we
01099              are done.  */
01100 
01101           ret_list = absolute_search (name);
01102 
01103           if (! ret_list.empty ())
01104             return ret_list;
01105         }
01106     }
01107 
01108   /* Find the file. */
01109   ret_list = path_find_first_of (path, names, must_exist, all);
01110 
01111   /* The very first search is for texmf.cnf.  We can't log that, since
01112      we want to allow setting TEXMFLOG in texmf.cnf.  */
01113   if (first_search)
01114     {
01115       first_search = false;
01116     }
01117   else
01118     {
01119       /* Record the filenames we found, if desired.  And wrap them in a
01120          debugging line if we're doing that.  */
01121 
01122       if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01123         {
01124           gnulib::fputs ("find_first_of (", stderr);
01125 
01126           int len = names.length ();
01127 
01128           for (int i = 0; i < len; i++)
01129             {
01130               if (i == 0)
01131                 gnulib::fputs (names[i].c_str (), stderr);
01132               else
01133                 gnulib::fprintf (stderr, ", %s", names[i].c_str ());
01134             }
01135 
01136           gnulib::fputs (") =>", stderr);
01137         }
01138 
01139       log_search (ret_list);
01140 
01141       if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01142         gnulib::putc ('\n', stderr);
01143     }
01144 
01145   return ret_list;
01146 }
01147 
01148 /* Search each element of PATH for each element of NAMES.  Return the
01149    first one found.  */
01150 
01151 /* Search each element of PATH for each element in the list of NAMES.
01152    Return the first one found.  */
01153 
01154 static std::string
01155 kpse_path_find_first_of (const std::string& path, const string_vector& names,
01156                          bool must_exist)
01157 {
01158   string_vector ret_list = find_first_of (path, names, must_exist, false);
01159 
01160   return ret_list.empty () ? std::string () : ret_list[0];
01161 }
01162 
01163 /* Search each element of PATH for each element of NAMES and return a
01164    list containing everything found, in the order found.  */
01165 
01166 /* Like 'kpse_path_find_first_of' with MUST_EXIST true, but return a
01167    list of all the filenames (or NULL if none), instead of taking the
01168    first.  */
01169 
01170 static string_vector
01171 kpse_all_path_find_first_of (const std::string& path,
01172                              const string_vector& names)
01173 {
01174   return find_first_of (path, names, true, true);
01175 }
01176 
01177 /* General expansion.  Some of this file (the brace-expansion
01178    code from bash) is covered by the GPL; this is the only GPL-covered
01179    code in kpathsea.  The part of the file that I wrote (the first
01180    couple of functions) is covered by the LGPL.  */
01181 
01182 /* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
01183    home directory, and return a new malloced string.  If no ~, or no
01184    <pwd.h>, just return NAME.  */
01185 
01186 static std::string
01187 kpse_tilde_expand (const std::string& name)
01188 {
01189   std::string expansion;
01190 
01191   /* If no leading tilde, do nothing.  */
01192   if (name.empty () || name[0] != '~')
01193     {
01194       expansion = name;
01195 
01196       /* If a bare tilde, return the home directory or '.'.  (Very
01197          unlikely that the directory name will do anyone any good, but
01198          ...  */
01199     }
01200   else if (name.length () == 1)
01201     {
01202       expansion = octave_env::getenv ("HOME");
01203 
01204       if (expansion.empty ())
01205         expansion = ".";
01206 
01207       /* If '~/', remove any trailing / or replace leading // in $HOME.
01208          Should really check for doubled intermediate slashes, too.  */
01209     }
01210   else if (IS_DIR_SEP (name[1]))
01211     {
01212       unsigned c = 1;
01213       std::string home = octave_env::getenv ("HOME");
01214 
01215       if (home.empty ())
01216         home = ".";
01217 
01218       size_t home_len = home.length ();
01219 
01220       /* handle leading // */
01221       if (home_len > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
01222         home = home.substr (1);
01223 
01224       /* omit / after ~ */
01225       if (IS_DIR_SEP (home[home_len - 1]))
01226         c++;
01227 
01228       expansion = home + name.substr (c);
01229 
01230       /* If '~user' or '~user/', look up user in the passwd database (but
01231          OS/2 doesn't have this concept.  */
01232     }
01233   else
01234 #ifdef HAVE_PWD_H
01235     {
01236       unsigned c = 2;
01237 
01238       /* find user name */
01239       while (name.length () > c && ! IS_DIR_SEP (name[c]))
01240         c++;
01241 
01242       std::string user = name.substr (1, c-1);
01243 
01244       /* We only need the cast here for (deficient) systems
01245          which do not declare 'getpwnam' in <pwd.h>.  */
01246       octave_passwd p = octave_passwd::getpwnam (user);
01247 
01248       /* If no such user, just use '.'.  */
01249       std::string home = p ? p.dir () : std::string (".");
01250 
01251       if (home.empty ())
01252         home = ".";
01253 
01254       /* handle leading // */
01255       if (home.length () > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
01256         home = home.substr (1);
01257 
01258       /* If HOME ends in /, omit the / after ~user. */
01259       if (name.length () > c && IS_DIR_SEP (home[home.length () - 1]))
01260         c++;
01261 
01262       expansion = name.length () > c ? home : home + name.substr (c);
01263     }
01264 #else /* not HAVE_PWD_H */
01265   expansion = name;
01266 #endif /* not HAVE_PWD_H */
01267 
01268   return expansion;
01269 }
01270 
01271 /* Do variable expansion first so ~${USER} works.  (Besides, it's what the
01272    shells do.)  */
01273 
01274 /* Call kpse_var_expand and kpse_tilde_expand (in that order).  Result
01275    is always in fresh memory, even if no expansions were done.  */
01276 
01277 static std::string
01278 kpse_expand (const std::string& s)
01279 {
01280   std::string var_expansion = kpse_var_expand (s);
01281   return kpse_tilde_expand (var_expansion);
01282 }
01283 
01284 /* Forward declarations of functions from the original expand.c  */
01285 static string_vector brace_expand (const std::string&);
01286 
01287 /* If $KPSE_DOT is defined in the environment, prepend it to any relative
01288    path components. */
01289 
01290 static std::string
01291 kpse_expand_kpse_dot (const std::string& path)
01292 {
01293   std::string ret;
01294   std::string kpse_dot = octave_env::getenv ("KPSE_DOT");
01295 
01296   if (kpse_dot.empty ())
01297     return path;
01298 
01299   for (kpse_path_iterator pi (path); pi != std::string::npos; pi++)
01300     {
01301       std::string elt = *pi;
01302 
01303       /* We assume that the !! magic is only used on absolute components.
01304          Single "." get special treatment, as does "./" or its  equivalent.  */
01305 
01306       size_t elt_len = elt.length ();
01307 
01308       if (kpse_absolute_p (elt, false)
01309           || (elt_len > 1 && elt[0] == '!' && elt[1] == '!'))
01310         ret += elt + ENV_SEP_STRING;
01311       else if (elt_len == 1 && elt[0] == '.')
01312         ret += kpse_dot + ENV_SEP_STRING;
01313       else if (elt_len > 1 && elt[0] == '.' && IS_DIR_SEP (elt[1]))
01314         ret += kpse_dot + elt.substr (1) + ENV_SEP_STRING;
01315       else
01316         ret += kpse_dot + DIR_SEP_STRING + elt + ENV_SEP_STRING;
01317     }
01318 
01319   int len = ret.length ();
01320   if (len > 0)
01321     ret.resize (len-1);
01322 
01323   return ret;
01324 }
01325 
01326 /* Do brace expansion on ELT; then do variable and ~ expansion on each
01327    element of the result; then do brace expansion again, in case a
01328    variable definition contained braces (e.g., $TEXMF).  Return a
01329    string comprising all of the results separated by ENV_SEP_STRING.  */
01330 
01331 static std::string
01332 kpse_brace_expand_element (const std::string& elt)
01333 {
01334   std::string ret;
01335 
01336   string_vector expansions = brace_expand (elt);
01337 
01338   for (int i = 0; i < expansions.length (); i++)
01339     {
01340       /* Do $ and ~ expansion on each element.  */
01341       std::string x = kpse_expand (expansions[i]);
01342 
01343       if (x != expansions[i])
01344         {
01345           /* If we did any expansions, do brace expansion again.  Since
01346              recursive variable definitions are not allowed, this recursion
01347              must terminate.  (In practice, it's unlikely there will ever be
01348              more than one level of recursion.)  */
01349           x = kpse_brace_expand_element (x);
01350         }
01351 
01352       ret += x + ENV_SEP_STRING;
01353     }
01354 
01355   ret.resize (ret.length () - 1);
01356 
01357   return ret;
01358 }
01359 
01360 /* Do brace expansion and call 'kpse_expand' on each element of the
01361    result; return the final expansion (always in fresh memory, even if
01362    no expansions were done).  We don't call 'kpse_expand_default'
01363    because there is a whole sequence of defaults to run through; see
01364    'kpse_init_format'.  */
01365 
01366 static std::string
01367 kpse_brace_expand (const std::string& path)
01368 {
01369   /* Must do variable expansion first because if we have
01370        foo = .:~
01371        TEXINPUTS = $foo
01372      we want to end up with TEXINPUTS = .:/home/karl.
01373      Since kpse_path_element is not reentrant, we must get all
01374      the path elements before we start the loop.  */
01375   std::string tmp = kpse_var_expand (path);
01376 
01377   std::string ret;
01378 
01379   for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
01380     {
01381       std::string elt = *pi;
01382 
01383       /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}.  */
01384       std::string expansion = kpse_brace_expand_element (elt);
01385       ret += expansion + ENV_SEP_STRING;
01386     }
01387 
01388   size_t len = ret.length ();
01389   if (len > 0)
01390     ret.resize (len-1);
01391 
01392   return kpse_expand_kpse_dot (ret);
01393 }
01394 
01395 /* Expand all special constructs in a path, and include only the actually
01396    existing directories in the result. */
01397 
01398 /* Do brace expansion and call 'kpse_expand' on each argument of the
01399    result, then expand any '//' constructs.  The final expansion (always
01400    in fresh memory) is a path of all the existing directories that match
01401    the pattern. */
01402 
01403 static std::string
01404 kpse_path_expand (const std::string& path)
01405 {
01406   std::string ret;
01407   unsigned len;
01408 
01409   len = 0;
01410 
01411   /* Expand variables and braces first.  */
01412   std::string tmp = kpse_brace_expand (path);
01413 
01414   /* Now expand each of the path elements, printing the results */
01415   for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
01416     {
01417       std::string elt = *pi;
01418 
01419       str_llist_type *dirs;
01420 
01421       /* Skip and ignore magic leading chars.  */
01422       if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
01423         elt = elt.substr (2);
01424 
01425       /* Do not touch the device if present */
01426       if (NAME_BEGINS_WITH_DEVICE (elt))
01427         {
01428           while (elt.length () > 3
01429                  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
01430             {
01431               elt[2] = elt[1];
01432               elt[1] = elt[0];
01433               elt = elt.substr (1);
01434             }
01435         }
01436       else
01437         {
01438           /* We never want to search the whole disk.  */
01439           while (elt.length () > 1
01440                  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
01441             elt = elt.substr (1);
01442         }
01443 
01444       /* Search the disk for all dirs in the component specified.
01445          Be faster to check the database, but this is more reliable.  */
01446       dirs = kpse_element_dirs (elt);
01447 
01448       if (dirs && *dirs)
01449         {
01450           str_llist_elt_type *dir;
01451 
01452           for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir))
01453             {
01454               const std::string thedir = STR_LLIST (*dir);
01455               unsigned dirlen = thedir.length ();
01456 
01457               ret += thedir;
01458               len += dirlen;
01459 
01460               /* Retain trailing slash if that's the root directory.  */
01461               if (dirlen == 1
01462                   || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (thedir)
01463                       && IS_DIR_SEP (thedir[2])))
01464                 {
01465                   ret += ENV_SEP_STRING;
01466                   len++;
01467                 }
01468 
01469               ret[len-1] = ENV_SEP;
01470             }
01471         }
01472     }
01473 
01474   if (len > 0)
01475     ret.resize (len-1);
01476 
01477   return ret;
01478 }
01479 
01480 /* braces.c -- code for doing word expansion in curly braces. Taken from
01481    bash 1.14.5.  [Ans subsequently modified for kpatshea.]
01482 
01483    Copyright (C) 1987,1991 Free Software Foundation, Inc.
01484 
01485    This program is free software; you can redistribute it and/or modify it
01486    under the terms of the GNU General Public License as published by
01487    the Free Software Foundation; either version 1, or (at your option)
01488    any later version.
01489 
01490    This program is distributed in the hope that it will be useful, but
01491    WITHOUT ANY WARRANTY; without even the implied warranty of
01492    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
01493    General Public License for more details.
01494 
01495    You should have received a copy of the GNU General Public License
01496    along with this program; see the file COPYING.  If not, write to the
01497    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
01498    MA 02110-1301, USA.  */
01499 
01500 #define brace_whitespace(c) (! (c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
01501 
01502 /* Basic idea:
01503 
01504    Segregate the text into 3 sections: preamble (stuff before an open brace),
01505    postamble (stuff after the matching close brace) and amble (stuff after
01506    preamble, and before postamble).  Expand amble, and then tack on the
01507    expansions to preamble.  Expand postamble, and tack on the expansions to
01508    the result so far.  */
01509 
01510 /* Return a new array of strings which is the result of appending each
01511    string in ARR2 to each string in ARR1.  The resultant array is
01512    len (arr1) * len (arr2) long.  For convenience, ARR1 (and its contents)
01513    are free ()'ed.  ARR1 can be NULL, in that case, a new version of ARR2
01514    is returned. */
01515 
01516 static string_vector
01517 array_concat (const string_vector& arr1, const string_vector& arr2)
01518 {
01519   string_vector result;
01520 
01521   if (arr1.empty ())
01522     result = arr2;
01523   else if (arr2.empty ())
01524     result = arr1;
01525   else
01526     {
01527       int len1 = arr1.length ();
01528       int len2 = arr2.length ();
01529 
01530       result = string_vector (len1 * len2);
01531 
01532       int k = 0;
01533       for (int i = 0; i < len2; i++)
01534         for (int j = 0; j < len1; j++)
01535           result[k++] = arr1[j] + arr2[i];
01536     }
01537 
01538   return result;
01539 }
01540 
01541 static int brace_gobbler (const std::string&, int&, int);
01542 static string_vector expand_amble (const std::string&);
01543 
01544 /* Return an array of strings; the brace expansion of TEXT. */
01545 static string_vector
01546 brace_expand (const std::string& text)
01547 {
01548   /* Find the text of the preamble. */
01549   int i = 0;
01550   int c = brace_gobbler (text, i, '{');
01551 
01552   std::string preamble = text.substr (0, i);
01553 
01554   string_vector result = string_vector (preamble);
01555 
01556   if (c == '{')
01557     {
01558       /* Find the amble.  This is the stuff inside this set of braces. */
01559       int start = ++i;
01560       c = brace_gobbler (text, i, '}');
01561 
01562       /* What if there isn't a matching close brace? */
01563       if (! c)
01564         {
01565           (*current_liboctave_warning_handler)
01566             ("%s: Unmatched {", text.c_str ());
01567 
01568           result = string_vector (text);
01569         }
01570       else
01571         {
01572           std::string amble = text.substr (start, i-start);
01573           result = array_concat (result, expand_amble (amble));
01574 
01575           std::string postamble = text.substr (i+1);
01576           result = array_concat (result, brace_expand (postamble));
01577         }
01578     }
01579 
01580   return result;
01581 }
01582 
01583 /* The character which is used to separate arguments. */
01584 static int brace_arg_separator = ',';
01585 
01586 /* Expand the text found inside of braces.  We simply try to split the
01587    text at BRACE_ARG_SEPARATORs into separate strings.  We then brace
01588    expand each slot which needs it, until there are no more slots which
01589    need it. */
01590 static string_vector
01591 expand_amble (const std::string& text)
01592 {
01593   string_vector result;
01594 
01595   size_t text_len = text.length ();
01596   size_t start;
01597   int i, c;
01598 
01599   for (start = 0, i = 0, c = 1; c && start < text_len; start = ++i)
01600     {
01601       int i0 = i;
01602       int c0 = brace_gobbler (text, i0, brace_arg_separator);
01603       int i1 = i;
01604       int c1 = brace_gobbler (text, i1, ENV_SEP);
01605       c = c0 | c1;
01606       i = (i0 < i1 ? i0 : i1);
01607 
01608       std::string tem = text.substr (start, i-start);
01609 
01610       string_vector partial = brace_expand (tem);
01611 
01612       if (result.empty ())
01613         result = partial;
01614       else
01615         result.append (partial);
01616     }
01617 
01618   return result;
01619 }
01620 
01621 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the
01622    index of the character matching SATISFY.  This understands about
01623    quoting.  Return the character that caused us to stop searching;
01624    this is either the same as SATISFY, or 0. */
01625 static int
01626 brace_gobbler (const std::string& text, int& indx, int satisfy)
01627 {
01628   int c = 0, level = 0, quoted = 0, pass_next = 0;
01629 
01630   size_t text_len = text.length ();
01631 
01632   size_t i = indx;
01633 
01634   for (; i < text_len; i++)
01635     {
01636       c = text[i];
01637 
01638       if (pass_next)
01639         {
01640           pass_next = 0;
01641           continue;
01642         }
01643 
01644       /* A backslash escapes the next character.  This allows backslash to
01645          escape the quote character in a double-quoted string. */
01646       if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
01647         {
01648           pass_next = 1;
01649           continue;
01650         }
01651 
01652       if (quoted)
01653         {
01654           if (c == quoted)
01655             quoted = 0;
01656           continue;
01657         }
01658 
01659       if (c == '"' || c == '\'' || c == '`')
01660         {
01661           quoted = c;
01662           continue;
01663         }
01664 
01665       if (c == satisfy && !level && !quoted)
01666         {
01667           /* We ignore an open brace surrounded by whitespace, and also
01668              an open brace followed immediately by a close brace, that
01669              was preceded with whitespace.  */
01670           if (c == '{' &&
01671               ((i == 0 || brace_whitespace (text[i-1])) &&
01672                (i+1 < text_len &&
01673                 (brace_whitespace (text[i+1]) || text[i+1] == '}'))))
01674             continue;
01675           /* If this is being compiled as part of bash, ignore the '{'
01676              in a '${}' construct */
01677           if ((c != '{') || i == 0 || (text[i-1] != '$'))
01678             break;
01679         }
01680 
01681       if (c == '{')
01682         level++;
01683       else if (c == '}' && level)
01684         level--;
01685     }
01686 
01687   indx = i;
01688   return c;
01689 }
01690 
01691 /* For each file format, we record the following information.  The main
01692    thing that is not part of this structure is the environment variable
01693    lists. They are used directly in tex-file.c. We could incorporate
01694    them here, but it would complicate the code a bit. We could also do
01695    it via variable expansion, but not now, maybe not ever:
01696    ${PKFONTS-${TEXFONTS-/usr/local/lib/texmf/fonts//}}.  */
01697 
01698 struct kpse_format_info_type
01699 {
01700   kpse_format_info_type (void)
01701     : type (), path (), raw_path (), path_source (), override_path (),
01702       client_path (), cnf_path (), default_path (), suffix ()
01703   { }
01704 
01705   ~kpse_format_info_type (void) { }
01706 
01707   std::string type;          /* Human-readable description.  */
01708   std::string path;          /* The search path to use.  */
01709   std::string raw_path;      /* Pre-$~ (but post-default) expansion.  */
01710   std::string path_source;   /* Where the path started from.  */
01711   std::string override_path; /* From client environment variable.  */
01712   std::string client_path;   /* E.g., from dvips's config.ps.  */
01713   std::string cnf_path;      /* From texmf.cnf.  */
01714   std::string default_path;  /* If all else fails.  */
01715   string_vector suffix;      /* For kpse_find_file to check for/append.  */
01716 };
01717 
01718 /* The sole variable of that type, indexed by 'kpse_file_format_type'.
01719    Initialized by calls to 'kpse_find_file' for 'kpse_init_format'.  */
01720 static kpse_format_info_type kpse_format_info;
01721 
01722 /* And EXPAND_DEFAULT calls kpse_expand_default on try_path and the
01723    present info->path.  */
01724 #define EXPAND_DEFAULT(try_path, source_string) \
01725   do \
01726     { \
01727       if (! try_path.empty ()) \
01728         { \
01729           info.raw_path = try_path;     \
01730           info.path = kpse_expand_default (try_path, info.path); \
01731           info.path_source = source_string;     \
01732         } \
01733     } \
01734   while (0)
01735 
01736 static hash_table_type db; /* The hash table for all the ls-R's.  */
01737 
01738 static hash_table_type alias_db;
01739 
01740 static string_vector db_dir_list;
01741 
01742 /* Return true if FILENAME could be in PATH_ELT, i.e., if the directory
01743    part of FILENAME matches PATH_ELT.  Have to consider // wildcards, but
01744    $ and ~ expansion have already been done.  */
01745 
01746 static bool
01747 match (const std::string& filename_arg, const std::string& path_elt_arg)
01748 {
01749   const char *filename = filename_arg.c_str ();
01750   const char *path_elt = path_elt_arg.c_str ();
01751 
01752   const char *original_filename = filename;
01753   bool matched = false;
01754 
01755   for (; *filename && *path_elt; filename++, path_elt++)
01756     {
01757       if (*filename == *path_elt) /* normal character match */
01758         ;
01759 
01760       else if (IS_DIR_SEP (*path_elt)  /* at // */
01761                && original_filename < filename && IS_DIR_SEP (path_elt[-1]))
01762         {
01763           while (IS_DIR_SEP (*path_elt))
01764             path_elt++; /* get past second and any subsequent /'s */
01765 
01766           if (*path_elt == 0)
01767             {
01768               /* Trailing //, matches anything. We could make this
01769                  part of the other case, but it seems pointless to do
01770                  the extra work.  */
01771               matched = true;
01772               break;
01773             }
01774           else
01775             {
01776               /* Intermediate //, have to match rest of PATH_ELT.  */
01777               for (; !matched && *filename; filename++)
01778                 {
01779                   /* Try matching at each possible character.  */
01780                   if (IS_DIR_SEP (filename[-1]) && *filename == *path_elt)
01781                     matched = match (filename, path_elt);
01782                 }
01783 
01784               /* Prevent filename++ when *filename='\0'. */
01785               break;
01786             }
01787         }
01788       else
01789         /* normal character nonmatch, quit */
01790         break;
01791     }
01792 
01793   /* If we've reached the end of PATH_ELT, check that we're at the last
01794      component of FILENAME, we've matched.  */
01795   if (! matched && *path_elt == 0)
01796     {
01797       /* Probably PATH_ELT ended with 'vf' or some such, and FILENAME
01798          ends with 'vf/ptmr.vf'.  In that case, we'll be at a
01799          directory separator.  On the other hand, if PATH_ELT ended
01800          with a / (as in 'vf/'), FILENAME being the same 'vf/ptmr.vf',
01801          we'll be at the 'p'.  Upshot: if we're at a dir separator in
01802          FILENAME, skip it.  But if not, that's ok, as long as there
01803          are no more dir separators.  */
01804 
01805       if (IS_DIR_SEP (*filename))
01806         filename++;
01807 
01808       while (*filename && !IS_DIR_SEP (*filename))
01809         filename++;
01810 
01811       matched = *filename == 0;
01812     }
01813 
01814   return matched;
01815 }
01816 
01817 /* If DB_DIR is a prefix of PATH_ELT, return true; otherwise false.
01818    That is, the question is whether to try the db for a file looked up
01819    in PATH_ELT.  If PATH_ELT == ".", for example, the answer is no. If
01820    PATH_ELT == "/usr/local/lib/texmf/fonts//tfm", the answer is yes.
01821 
01822    In practice, ls-R is only needed for lengthy subdirectory
01823    comparisons, but there's no gain to checking PATH_ELT to see if it is
01824    a subdir match, since the only way to do that is to do a string
01825    search in it, which is all we do anyway.  */
01826 
01827 static bool
01828 elt_in_db (const std::string& db_dir, const std::string& path_elt)
01829 {
01830   bool found = false;
01831 
01832   size_t db_dir_len = db_dir.length ();
01833   size_t path_elt_len = path_elt.length ();
01834 
01835   size_t i = 0;
01836 
01837   while (! found && db_dir[i] == path_elt[i])
01838     {
01839       i++;
01840       /* If we've matched the entire db directory, it's good.  */
01841       if (i == db_dir_len)
01842         found = true;
01843 
01844     /* If we've reached the end of PATH_ELT, but not the end of the db
01845        directory, it's no good.  */
01846       else if (i == path_elt_len)
01847         break;
01848     }
01849 
01850   return found;
01851 }
01852 
01853 /* Avoid doing anything if this PATH_ELT is irrelevant to the databases. */
01854 
01855 /* Return list of matches for NAME in the ls-R file matching PATH_ELT.  If
01856    ALL is set, return (null-terminated list) of all matches, else just
01857    the first.  If no matches, return a pointer to an empty list.  If no
01858    databases can be read, or PATH_ELT is not in any of the databases,
01859    return NULL.  */
01860 
01861 static string_vector
01862 kpse_db_search (const std::string& name_arg,
01863                 const std::string& orig_path_elt, bool all)
01864 {
01865   bool done;
01866   string_vector ret;
01867   string_vector aliases;
01868   bool relevant = false;
01869 
01870   std::string name = name_arg;
01871 
01872   /* If we failed to build the database (or if this is the recursive
01873      call to build the db path), quit.  */
01874   if (! db.buckets)
01875     return ret;
01876 
01877   /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
01878      won't find it unless we change NAME to just 'cmr10.pk' and append
01879      '/dpi600' to PATH_ELT.  We are justified in using a literal '/'
01880      here, since that's what tex-glyph.c unconditionally uses in
01881      DPI_BITMAP_SPEC.  But don't do anything if the / begins NAME; that
01882      should never happen.  */
01883   std::string path_elt;
01884   size_t last_slash = name.rfind ('/');
01885   if (last_slash != std::string::npos && last_slash != 0)
01886     {
01887       std::string dir_part = name.substr (0, last_slash);
01888       name = name.substr (last_slash + 1);
01889     }
01890   else
01891     path_elt = orig_path_elt;
01892 
01893   /* Don't bother doing any lookups if this 'path_elt' isn't covered by
01894      any of database directories.  We do this not so much because the
01895      extra couple of hash lookups matter -- they don't -- but rather
01896      because we want to return NULL in this case, so path_search can
01897      know to do a disk search.  */
01898   for (int e = 0; ! relevant && e < db_dir_list.length (); e++)
01899     relevant = elt_in_db (db_dir_list[e], path_elt);
01900 
01901   if (! relevant)
01902     return ret;
01903 
01904   /* If we have aliases for this name, use them.  */
01905   if (alias_db.buckets)
01906     aliases = hash_lookup (alias_db, name);
01907 
01908   /* Push aliases up by one and insert the original name at the front.  */
01909   int len = aliases.length ();
01910   aliases.resize (len+1);
01911   for (int i = len; i > 0; i--)
01912     aliases[i] = aliases[i - 1];
01913   aliases[0] = name;
01914 
01915   done = false;
01916   len = aliases.length ();
01917   for (int i = 0; i < len && !done; i++)
01918     {
01919       std::string atry = aliases[i];
01920 
01921       /* We have an ls-R db.  Look up 'atry'.  */
01922       string_vector db_dirs = hash_lookup (db, atry);
01923 
01924       /* For each filename found, see if it matches the path element.  For
01925          example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
01926          and the path looks like .../cx, we don't want the ricoh file.  */
01927 
01928       int db_dirs_len = db_dirs.length ();
01929       for (int j = 0; j < db_dirs_len && !done; j++)
01930         {
01931           std::string db_file = db_dirs[j] + atry;
01932           bool matched = match (db_file, path_elt);
01933 
01934 #ifdef KPSE_DEBUG
01935           if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01936             DEBUGF3 ("db:match (%s,%s) = %d\n", db_file.c_str (), path_elt.c_str (), matched);
01937 #endif
01938 
01939           /* We got a hit in the database.  Now see if the file actually
01940              exists, possibly under an alias.  */
01941           if (matched)
01942             {
01943               std::string found;
01944               std::string tmp = kpse_readable_file (db_file);
01945               if (! tmp.empty ())
01946                 found = db_file;
01947               else
01948                 {
01949                   /* The hit in the DB doesn't exist in disk.  Now try
01950                      all its aliases.  For example, suppose we have a
01951                      hierarchy on CD, thus 'mf.bas', but ls-R contains
01952                      'mf.base'.  Find it anyway.  Could probably work
01953                      around this with aliases, but this is pretty easy
01954                      and shouldn't hurt.  The upshot is that if one of
01955                      the aliases actually exists, we use that.  */
01956 
01957                   int aliases_len = aliases.length ();
01958 
01959                   for (int k = 1; k < aliases_len && found.empty (); k++)
01960                     {
01961                       std::string aatry = db_dirs[j] + aliases[k];
01962                       tmp = kpse_readable_file (aatry);
01963                       if (! tmp.empty ())
01964                         found = aatry;
01965                     }
01966                 }
01967 
01968               /* If we have a real file, add it to the list, maybe done.  */
01969               if (! found.empty ())
01970                 {
01971                   ret.append (found);
01972 
01973                   if (! (all || found.empty ()))
01974                     done = true;
01975                 }
01976             }
01977         }
01978     }
01979 
01980   return ret;
01981 }
01982 
01983 /* Expand extra colons.  */
01984 
01985 /* Check for leading colon first, then trailing, then doubled, since
01986    that is fastest.  Usually it will be leading or trailing.  */
01987 
01988 /* Replace a leading or trailing or doubled : in PATH with DFLT.  If
01989    no extra colons, return PATH.  Only one extra colon is replaced.
01990    DFLT may not be NULL.  */
01991 
01992 static std::string
01993 kpse_expand_default (const std::string& path, const std::string& fallback)
01994 {
01995   std::string expansion;
01996 
01997   size_t path_len = path.length ();
01998 
01999   if (path_len == 0)
02000     expansion = fallback;
02001 
02002   /* Solitary or leading :?  */
02003   else if (IS_ENV_SEP (path[0]))
02004     {
02005       expansion = path_len == 1 ? fallback : fallback + path;
02006     }
02007 
02008   /* Sorry about the assignment in the middle of the expression, but
02009      conventions were made to be flouted and all that.  I don't see the
02010      point of calling strlen twice or complicating the logic just to
02011      avoid the assignment (especially now that I've pointed it out at
02012      such great length).  */
02013   else if (IS_ENV_SEP (path[path_len-1]))
02014     expansion = path + fallback;
02015 
02016   /* OK, not leading or trailing.  Check for doubled.  */
02017   else
02018     {
02019       /* What we'll return if we find none.  */
02020       expansion = path;
02021 
02022       for (size_t i = 0; i < path_len; i++)
02023         {
02024           if (i + 1 < path_len
02025               && IS_ENV_SEP (path[i]) && IS_ENV_SEP (path[i+1]))
02026             {
02027               /* We have a doubled colon.  */
02028 
02029               /* Copy stuff up to and including the first colon.  */
02030               /* Copy in FALLBACK, and then the rest of PATH.  */
02031               expansion = path.substr (0, i+1) + fallback + path.substr (i+1);
02032 
02033               break;
02034             }
02035         }
02036     }
02037 
02038   return expansion;
02039 }
02040 
02041 /* Translate a path element to its corresponding director{y,ies}.  */
02042 
02043 /* To avoid giving prototypes for all the routines and then their real
02044    definitions, we give all the subroutines first.  The entry point is
02045    the last routine in the file.  */
02046 
02047 /* Make a copy of DIR (unless it's null) and save it in L.  Ensure that
02048    DIR ends with a DIR_SEP for the benefit of later searches.  */
02049 
02050 static void
02051 dir_list_add (str_llist_type *l, const std::string& dir)
02052 {
02053   char last_char = dir[dir.length () - 1];
02054 
02055   std::string saved_dir = dir;
02056 
02057   if (! (IS_DIR_SEP (last_char) || IS_DEVICE_SEP (last_char)))
02058     saved_dir += DIR_SEP_STRING;
02059 
02060   str_llist_add (l, saved_dir);
02061 }
02062 
02063 /* Return true if FN is a directory or a symlink to a directory,
02064    false if not. */
02065 
02066 static bool
02067 dir_p (const std::string& fn)
02068 {
02069 #ifdef WIN32
02070   unsigned int fa = GetFileAttributes (fn.c_str ());
02071   return (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
02072 #else
02073   struct stat stats;
02074   return stat (fn.c_str (), &stats) == 0 && S_ISDIR (stats.st_mode);
02075 #endif
02076 }
02077 
02078 /* If DIR is a directory, add it to the list L.  */
02079 
02080 static void
02081 checked_dir_list_add (str_llist_type *l, const std::string& dir)
02082 {
02083   if (dir_p (dir))
02084     dir_list_add (l, dir);
02085 }
02086 
02087 /* The cache.  Typically, several paths have the same element; for
02088    example, /usr/local/lib/texmf/fonts//.  We don't want to compute the
02089    expansion of such a thing more than once.  Even though we also cache
02090    the dir_links call, that's not enough -- without this path element
02091    caching as well, the execution time doubles.  */
02092 
02093 struct cache_entry
02094 {
02095   cache_entry (void) : key (), value (0) { }
02096 
02097   ~cache_entry (void) { }
02098 
02099   std::string key;
02100   str_llist_type *value;
02101 };
02102 
02103 static cache_entry *the_cache = 0;
02104 static unsigned cache_length = 0;
02105 
02106 /* Associate KEY with VALUE.  We implement the cache as a simple linear
02107    list, since it's unlikely to ever be more than a dozen or so elements
02108    long.  We don't bother to check here if PATH has already been saved;
02109    we always add it to our list.  We copy KEY but not VALUE; not sure
02110    that's right, but it seems to be all that's needed.  */
02111 
02112 static void
02113 cache (const std::string key, str_llist_type *value)
02114 {
02115   cache_entry *new_cache = new cache_entry [cache_length+1];
02116 
02117   for (unsigned i = 0; i < cache_length; i++)
02118     {
02119       new_cache[i].key = the_cache[i].key;
02120       new_cache[i].value = the_cache[i].value;
02121     }
02122 
02123   delete [] the_cache;
02124 
02125   the_cache = new_cache;
02126 
02127   the_cache[cache_length].key = key;
02128   the_cache[cache_length].value = value;
02129 
02130   cache_length++;
02131 }
02132 
02133 /* To retrieve, just check the list in order.  */
02134 
02135 static str_llist_type *
02136 cached (const std::string& key)
02137 {
02138   unsigned p;
02139 
02140   for (p = 0; p < cache_length; p++)
02141     {
02142       if (key == the_cache[p].key)
02143         return the_cache[p].value;
02144     }
02145 
02146   return 0;
02147 }
02148 
02149 /* Handle the magic path constructs.  */
02150 
02151 /* Declare recursively called routine.  */
02152 static void expand_elt (str_llist_type *, const std::string&, unsigned);
02153 
02154 /* POST is a pointer into the original element (which may no longer be
02155    ELT) to just after the doubled DIR_SEP, perhaps to the null.  Append
02156    subdirectories of ELT (up to ELT_LENGTH, which must be a /) to
02157    STR_LIST_PTR.  */
02158 
02159 #ifdef WIN32
02160 
02161 /* Shared across recursive calls, it acts like a stack. */
02162 static std::string dirname;
02163 
02164 #else /* WIN32 */
02165 
02166 /* Return -1 if FN isn't a directory, else its number of links.
02167    Duplicate the call to stat; no need to incur overhead of a function
02168    call for that little bit of cleanliness. */
02169 
02170 static int
02171 dir_links (const std::string& fn)
02172 {
02173   std::map<std::string, long> link_table;
02174 
02175   long ret;
02176 
02177   if (link_table.find (fn) != link_table.end ())
02178     ret = link_table[fn];
02179   else
02180     {
02181       struct stat stats;
02182 
02183       ret = stat (fn.c_str (), &stats) == 0 && S_ISDIR (stats.st_mode)
02184         ? stats.st_nlink : static_cast<unsigned> (-1);
02185 
02186       link_table[fn] = ret;
02187 
02188 #ifdef KPSE_DEBUG
02189       if (KPSE_DEBUG_P (KPSE_DEBUG_STAT))
02190         DEBUGF2 ("dir_links (%s) => %ld\n", fn.c_str (), ret);
02191 #endif
02192     }
02193 
02194   return ret;
02195 }
02196 
02197 #endif /* WIN32 */
02198 
02199 static void
02200 do_subdir (str_llist_type *str_list_ptr, const std::string& elt,
02201            unsigned elt_length, const std::string& post)
02202 {
02203 #ifdef WIN32
02204   WIN32_FIND_DATA find_file_data;
02205   HANDLE hnd;
02206   int proceed;
02207 #else
02208   DIR *dir;
02209   struct dirent *e;
02210 #endif /* not WIN32 */
02211 
02212   std::string name = elt.substr (0, elt_length);
02213 
02214   assert (IS_DIR_SEP (elt[elt_length - 1])
02215           || IS_DEVICE_SEP (elt[elt_length - 1]));
02216 
02217 #if defined (WIN32)
02218 
02219   dirname = name + "/*.*";         /* "*.*" or "*" -- seems equivalent. */
02220 
02221   hnd = FindFirstFile (dirname.c_str (), &find_file_data);
02222 
02223   if (hnd == INVALID_HANDLE_VALUE)
02224     return;
02225 
02226   /* Include top level before subdirectories, if nothing to match.  */
02227   if (post.empty ())
02228     dir_list_add (str_list_ptr, name);
02229   else
02230     {
02231       /* If we do have something to match, see if it exists.  For
02232          example, POST might be 'pk/ljfour', and they might have a
02233          directory '$TEXMF/fonts/pk/ljfour' that we should find.  */
02234       name += post;
02235       expand_elt (str_list_ptr, name, elt_length);
02236       name.resize (elt_length);
02237     }
02238 
02239   proceed = 1;
02240 
02241   while (proceed)
02242     {
02243       if (find_file_data.cFileName[0] != '.')
02244         {
02245           /* Construct the potential subdirectory name.  */
02246           name += find_file_data.cFileName;
02247 
02248           if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
02249             {
02250               /* It's a directory, so append the separator.  */
02251               name += DIR_SEP_STRING;
02252               unsigned potential_len = name.length ();
02253 
02254               do_subdir (str_list_ptr, name, potential_len, post);
02255             }
02256           name.resize (elt_length);
02257         }
02258 
02259       proceed = FindNextFile (hnd, &find_file_data);
02260     }
02261 
02262   FindClose (hnd);
02263 
02264 #else /* not WIN32 */
02265 
02266   /* If we can't open it, quit.  */
02267   dir = gnulib::opendir (name.c_str ());
02268 
02269   if (! dir)
02270     return;
02271 
02272   /* Include top level before subdirectories, if nothing to match.  */
02273   if (post.empty ())
02274     dir_list_add (str_list_ptr, name);
02275   else
02276     {
02277       /* If we do have something to match, see if it exists.  For
02278          example, POST might be 'pk/ljfour', and they might have a
02279          directory '$TEXMF/fonts/pk/ljfour' that we should find.  */
02280       name += post;
02281       expand_elt (str_list_ptr, name, elt_length);
02282       name.resize (elt_length);
02283     }
02284 
02285   while ((e = gnulib::readdir (dir)))
02286     {
02287       /* If it begins with a '.', never mind.  (This allows "hidden"
02288          directories that the algorithm won't find.)  */
02289 
02290       if (e->d_name[0] != '.')
02291         {
02292           int links;
02293 
02294           /* Construct the potential subdirectory name.  */
02295           name += e->d_name;
02296 
02297           /* If we can't stat it, or if it isn't a directory, continue.  */
02298           links = dir_links (name);
02299 
02300           if (links >= 0)
02301             {
02302               /* It's a directory, so append the separator.  */
02303               name += DIR_SEP_STRING;
02304               unsigned potential_len = name.length ();
02305 
02306               /* Should we recurse?  To see if the subdirectory is a
02307                  leaf, check if it has two links (one for . and one for
02308                  ..).  This means that symbolic links to directories do
02309                  not affect the leaf-ness.  This is arguably wrong, but
02310                  the only alternative I know of is to stat every entry
02311                  in the directory, and that is unacceptably slow.
02312 
02313                  The #ifdef here makes all this configurable at
02314                  compile-time, so that if we're using VMS directories or
02315                  some such, we can still find subdirectories, even if it
02316                  is much slower.  */
02317 #ifdef ST_NLINK_TRICK
02318               if (links != 2)
02319 #endif /* not ST_NLINK_TRICK */
02320                 /* All criteria are met; find subdirectories.  */
02321                 do_subdir (str_list_ptr, name, potential_len, post);
02322 #ifdef ST_NLINK_TRICK
02323               else if (post.empty ())
02324                 /* Nothing to match, no recursive subdirectories to
02325                    look for: we're done with this branch.  Add it.  */
02326                 dir_list_add (str_list_ptr, name);
02327 #endif
02328             }
02329 
02330           /* Remove the directory entry we just checked from 'name'.  */
02331           name.resize (elt_length);
02332         }
02333     }
02334 
02335   xclosedir (dir);
02336 #endif /* not WIN32 */
02337 }
02338 
02339 /* Assume ELT is non-empty and non-NULL.  Return list of corresponding
02340    directories (with no terminating NULL entry) in STR_LIST_PTR.  Start
02341    looking for magic constructs at START.  */
02342 
02343 static void
02344 expand_elt (str_llist_type *str_list_ptr, const std::string& elt,
02345             unsigned /* start */)
02346 {
02347 #if 0
02348   // We don't want magic constructs.
02349 
02350   size_t elt_len = elt.length ();
02351 
02352   size_t dir = start;
02353 
02354 
02355   while (dir < elt_len)
02356     {
02357       if (IS_DIR_SEP (elt[dir]))
02358         {
02359           /* If two or more consecutive /'s, find subdirectories.  */
02360           if (++dir < elt_len && IS_DIR_SEP (elt[dir]))
02361             {
02362               size_t i = dir;
02363               while (i < elt_len && IS_DIR_SEP (elt[i]))
02364                 i++;
02365 
02366               std::string post = elt.substr (i);
02367 
02368               do_subdir (str_list_ptr, elt, dir, post);
02369 
02370               return;
02371             }
02372 
02373           /* No special stuff at this slash.  Keep going.  */
02374         }
02375       else
02376         dir++;
02377     }
02378 #endif
02379 
02380   /* When we reach the end of ELT, it will be a normal filename.  */
02381   checked_dir_list_add (str_list_ptr, elt);
02382 }
02383 
02384 /* Here is the entry point.  Returns directory list for ELT.  */
02385 
02386 /* Given a path element ELT, return a pointer to a NULL-terminated list
02387    of the corresponding (existing) directory or directories, with
02388    trailing slashes, or NULL.  If ELT is the empty string, check the
02389    current working directory.
02390 
02391    It's up to the caller to expand ELT.  This is because this routine is
02392    most likely only useful to be called from 'kpse_path_search', which
02393    has already assumed expansion has been done.  */
02394 
02395 static str_llist_type *
02396 kpse_element_dirs (const std::string& elt)
02397 {
02398   str_llist_type *ret;
02399 
02400   /* If given nothing, return nothing.  */
02401   if (elt.empty ())
02402     return 0;
02403 
02404   /* If we've already cached the answer for ELT, return it.  */
02405   ret = cached (elt);
02406   if (ret)
02407     return ret;
02408 
02409   /* We're going to have a real directory list to return.  */
02410   ret = new str_llist_type;
02411   *ret = 0;
02412 
02413   /* We handle the hard case in a subroutine.  */
02414   expand_elt (ret, elt, 0);
02415 
02416   /* Remember the directory list we just found, in case future calls are
02417      made with the same ELT.  */
02418   cache (elt, ret);
02419 
02420 #ifdef KPSE_DEBUG
02421   if (KPSE_DEBUG_P (KPSE_DEBUG_EXPAND))
02422     {
02423       DEBUGF1 ("path element %s =>", elt.c_str ());
02424       if (ret)
02425         {
02426           str_llist_elt_type *e;
02427           for (e = *ret; e; e = STR_LLIST_NEXT (*e))
02428             gnulib::fprintf (stderr, " %s", (STR_LLIST (*e)).c_str ());
02429         }
02430       gnulib::putc ('\n', stderr);
02431       gnulib::fflush (stderr);
02432     }
02433 #endif /* KPSE_DEBUG */
02434 
02435   return ret;
02436 }
02437 
02438 #ifndef WIN32
02439 void
02440 xclosedir (DIR *d)
02441 {
02442   int ret = gnulib::closedir (d);
02443 
02444   if (ret != 0)
02445     FATAL ("closedir failed");
02446 }
02447 #endif
02448 
02449 /* Implementation of a linked list of strings.  */
02450 
02451 /* Add the new string STR to the end of the list L.  */
02452 
02453 static void
02454 str_llist_add (str_llist_type *l, const std::string& str)
02455 {
02456   str_llist_elt_type *e;
02457   str_llist_elt_type *new_elt = new str_llist_elt_type;
02458 
02459   /* The new element will be at the end of the list.  */
02460   STR_LLIST (*new_elt) = str;
02461   STR_LLIST_MOVED (*new_elt) = 0;
02462   STR_LLIST_NEXT (*new_elt) = 0;
02463 
02464   /* Find the current end of the list.  */
02465   for (e = *l; e && STR_LLIST_NEXT (*e); e = STR_LLIST_NEXT (*e))
02466     ;
02467 
02468   if (! e)
02469     *l = new_elt;
02470   else
02471     STR_LLIST_NEXT (*e) = new_elt;
02472 }
02473 
02474 /* Move an element towards the top. The idea is that when a file is
02475    found in a given directory, later files will likely be in that same
02476    directory, and looking for the file in all the directories in between
02477    is thus a waste.  */
02478 
02479 static void
02480 str_llist_float (str_llist_type *l, str_llist_elt_type *mover)
02481 {
02482   str_llist_elt_type *last_moved, *unmoved;
02483 
02484   /* If we've already moved this element, never mind.  */
02485   if (STR_LLIST_MOVED (*mover))
02486     return;
02487 
02488   /* Find the first unmoved element (to insert before).  We're
02489      guaranteed this will terminate, since MOVER itself is currently
02490      unmoved, and it must be in L (by hypothesis).  */
02491   for (last_moved = 0, unmoved = *l; STR_LLIST_MOVED (*unmoved);
02492        last_moved = unmoved, unmoved = STR_LLIST_NEXT (*unmoved))
02493     ;
02494 
02495   /* If we are the first unmoved element, nothing to relink.  */
02496   if (unmoved != mover)
02497     { /* Remember 'mover's current successor, so we can relink 'mover's
02498          predecessor to it.  */
02499       str_llist_elt_type *before_mover;
02500       str_llist_elt_type *after_mover = STR_LLIST_NEXT (*mover);
02501 
02502       /* Find 'mover's predecessor.  */
02503       for (before_mover = unmoved; STR_LLIST_NEXT (*before_mover) != mover;
02504            before_mover = STR_LLIST_NEXT (*before_mover))
02505         ;
02506 
02507       /* 'before_mover' now links to 'after_mover'.  */
02508       STR_LLIST_NEXT (*before_mover) = after_mover;
02509 
02510       /* Insert 'mover' before 'unmoved' and after 'last_moved' (or at
02511          the head of the list).  */
02512       STR_LLIST_NEXT (*mover) = unmoved;
02513       if (! last_moved)
02514         *l = mover;
02515       else
02516         STR_LLIST_NEXT (*last_moved) = mover;
02517     }
02518 
02519   /* We've moved it.  */
02520   STR_LLIST_MOVED (*mover) = 1;
02521 }
02522 
02523 /* Variable expansion.  */
02524 
02525 /* We have to keep track of variables being expanded, otherwise
02526    constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
02527    (Or indirectly recursive variables, etc.)  Our simple solution is to
02528    add to a list each time an expansion is started, and check the list
02529    before expanding.  */
02530 
02531 static std::map <std::string, bool> expansions;
02532 
02533 static void
02534 expanding (const std::string& var, bool xp)
02535 {
02536   expansions[var] = xp;
02537 }
02538 
02539 /* Return whether VAR is currently being expanding.  */
02540 
02541 static bool
02542 expanding_p (const std::string& var)
02543 {
02544   return (expansions.find (var) != expansions.end ())
02545     ? expansions[var] : false;
02546 }
02547 
02548 /* Append the result of value of 'var' to EXPANSION, where 'var' begins
02549    at START and ends at END.  If 'var' is not set, do not complain.
02550    This is a subroutine for the more complicated expansion function.  */
02551 
02552 static void
02553 expand (std::string &expansion, const std::string& var)
02554 {
02555   if (expanding_p (var))
02556     {
02557       (*current_liboctave_warning_handler)
02558         ("kpathsea: variable '%s' references itself (eventually)",
02559          var.c_str ());
02560     }
02561   else
02562     {
02563       /* Check for an environment variable.  */
02564       std::string value = octave_env::getenv (var);
02565 
02566       if (! value.empty ())
02567         {
02568           expanding (var, true);
02569           std::string tmp = kpse_var_expand (value);
02570           expanding (var, false);
02571           expansion += tmp;
02572         }
02573     }
02574 }
02575 
02576 /* Can't think of when it would be useful to change these (and the
02577    diagnostic messages assume them), but ... */
02578 #ifndef IS_VAR_START /* starts all variable references */
02579 #define IS_VAR_START(c) ((c) == '$')
02580 #endif
02581 #ifndef IS_VAR_CHAR  /* variable name constituent */
02582 #define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_')
02583 #endif
02584 #ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */
02585 #define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
02586 #endif
02587 #ifndef IS_VAR_END_DELIMITER
02588 #define IS_VAR_END_DELIMITER(c) ((c) == '}')
02589 #endif
02590 
02591 /* Maybe we should support some or all of the various shell ${...}
02592    constructs, especially ${var-value}.  */
02593 
02594 static std::string
02595 kpse_var_expand (const std::string& src)
02596 {
02597   std::string expansion;
02598 
02599   size_t src_len = src.length ();
02600 
02601   /* Copy everything but variable constructs.  */
02602   for (size_t i = 0; i < src_len; i++)
02603     {
02604       if (IS_VAR_START (src[i]))
02605         {
02606           i++;
02607 
02608           /* Three cases: '$VAR', '${VAR}', '$<anything-else>'.  */
02609           if (IS_VAR_CHAR (src[i]))
02610             {
02611               /* $V: collect name constituents, then expand.  */
02612               size_t var_end = i;
02613 
02614               do
02615                 {
02616                   var_end++;
02617                 }
02618               while (IS_VAR_CHAR (src[var_end]));
02619 
02620               var_end--; /* had to go one past */
02621               expand (expansion, src.substr (i, var_end - i + 1));
02622               i = var_end;
02623 
02624             }
02625           else if (IS_VAR_BEGIN_DELIMITER (src[i]))
02626             {
02627               /* ${: scan ahead for matching delimiter, then expand.  */
02628               size_t var_end = ++i;
02629 
02630               while (var_end < src_len && !IS_VAR_END_DELIMITER (src[var_end]))
02631                 var_end++;
02632 
02633               if (var_end == src_len)
02634                 {
02635                   (*current_liboctave_warning_handler)
02636                     ("%s: No matching } for ${", src.c_str ());
02637                   i = var_end - 1; /* will incr to eos at top of loop */
02638                 }
02639               else
02640                 {
02641                   expand (expansion, src.substr (i, var_end - i));
02642                   i = var_end; /* will incr past } at top of loop*/
02643                 }
02644             }
02645           else
02646             {
02647               /* $<something-else>: error.  */
02648               (*current_liboctave_warning_handler)
02649                 ("%s: Unrecognized variable construct '$%c'",
02650                  src.c_str (), src[i]);
02651 
02652               /* Just ignore those chars and keep going.  */
02653             }
02654         }
02655       else
02656         expansion += src[i];
02657     }
02658 
02659   return expansion;
02660 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines