メインページ   クラス階層   構成   ファイル一覧   構成メンバ   ファイルメンバ  

kpse.cc

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

Wed Dec 29 11:51:39 2004に生成されました。 doxygen1.2.18
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送