diff liboctave/kpse.cc @ 4399:286a3345aa8e

[project @ 2003-05-01 03:00:28 by jwe]
author jwe
date Thu, 01 May 2003 03:00:29 +0000
parents cd8bf2c6797a
children 16e8acbd19d5
line wrap: on
line diff
--- a/liboctave/kpse.cc	Tue Apr 29 04:21:01 2003 +0000
+++ b/liboctave/kpse.cc	Thu May 01 03:00:29 2003 +0000
@@ -1,8 +1,11 @@
-/* pathsearch.c: look up a filename in a path.
+// This file is not compiled to a separate object file.  It is
+// included in pathsearch.cc.
+
+/* Look up a filename in a path.
 
 Copyright (C) 1993, 94, 95, 96, 97, 98 Karl Berry.
 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry & O. Weber.
-Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+Copyright (C) 1992, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public
@@ -25,16 +28,70 @@
 #include <map>
 #include <string>
 
-#include "kpse-config.h"
+/* System defines are for non-Unix systems only.  (Testing for all Unix
+   variations should be done in configure.)  Presently the defines used
+   are: DOS OS2 WIN32.  I do not use any of these systems
+   myself; if you do, I'd be grateful for any changes. --kb@mail.tug.org */
+
+/* If we have either DOS or OS2, we are DOSISH.  */
+#if defined (DOS) || defined (OS2) || defined (WIN32) || defined(__MSDOS__)
+#define DOSISH
+#endif
+
+#if defined (DOSISH)
+#define MONOCASE_FILENAMES	/* case-insensitive filename comparisons */
+#endif
+
+extern "C" {
+#if defined(__MINGW32__)
+#include <windows.h>
+#include <fcntl.h>
+#include <dirent.h>
+#elif defined(WIN32)
+#define __STDC__ 1
+#include "win32lib.h"
+#endif /* not WIN32 */
+
+#ifdef __DJGPP__
+#include <fcntl.h>	/* for long filenames' stuff */
+#include <dir.h>	/* for `getdisk' */
+#include <io.h>		/* for `setmode' */
+#endif
+}
+
+/* Some drivers have partially integrated kpathsea changes.  */
+#ifndef KPATHSEA
+#define KPATHSEA 32
+#endif
+ 
+/* System dependencies that are figured out by `configure'.  If we are
+   compiling standalone, we get our c-auto.h.  Otherwise, the package
+   containing us must provide this (unless it can somehow generate ours
+   from c-auto.in).  We use <...> instead of "..." so that the current
+   cpp directory (i.e., kpathsea/) won't be searched. */
+
+/* If you want to find subdirectories in a directory with non-Unix
+   semantics (specifically, if a directory with no subdirectories does
+   not have exactly two links), define this.  */
+#if !defined (DOSISH) || defined(__DJGPP__)
+/* Surprise!  DJGPP returns st_nlink exactly like on Unix.  */
+#define ST_NLINK_TRICK
+#endif /* either not DOSISH or __DJGPP__ */
+
+#ifdef OS2
+#define access ln_access
+#define fopen ln_fopen
+#define rename ln_rename
+#define stat ln_stat
+#endif /* OS2 */
+
 #include "kpse-xfns.h"
-#include "kpse.h"
 
 #include "lo-error.h"
 #include "lo-sstream.h"
 #include "oct-env.h"
 #include "oct-passwd.h"
-
-/* c-std.h: the first header files.  */
+#include "str-vec.h"
 
 /* Header files that essentially all of our sources need, and
    that all implementations have.  We include these first, to help with
@@ -42,7 +99,6 @@
 #include <cstdio>
 #include <cstdarg>
 #include <cstdlib>
-#include <cstring>
 #include <climits>
 #include <cerrno>
 #include <cassert>
@@ -71,8 +127,6 @@
 #define NAME_MAX _POSIX_NAME_MAX
 #endif
 
-/* c-ctype.h: ASCII-safe versions of the <ctype.h> macros.  */
-
 #include <cctype>
 
 /* What separates elements in environment variable path lists?  */
@@ -90,9 +144,9 @@
 #define IS_ENV_SEP(ch) ((ch) == ENV_SEP)
 #endif
 
-/* c-pathmx.h: define PATH_MAX, the maximum length of a filename.
-   Since no such limit may exist, it's preferable to dynamically grow
-   filenames as needed.  */
+/* define PATH_MAX, the maximum length of a filename.  Since no such
+   limit may exist, it's preferable to dynamically grow filenames as
+   needed.  */
 
 /* Cheat and define this as a manifest constant no matter what, instead
    of using pathconf.  I forget why we want to do this.  */
@@ -109,8 +163,6 @@
 #endif
 #endif /* not PATH_MAX */
 
-/* debug.h: Runtime tracing.  */
-
 /* If NO_DEBUG is defined (not recommended), skip all this.  */
 #ifndef NO_DEBUG
 
@@ -146,13 +198,17 @@
 
 #undef fopen
 #define fopen kpse_fopen_trace
-extern FILE *fopen (const char *filename, const char *mode);
+static FILE *fopen (const char *filename, const char *mode);
 #undef fclose
 #define fclose kpse_fclose_trace
-extern int fclose (FILE *);
+static int fclose (FILE *);
 
 #endif /* not NO_DEBUG */
 
+#ifdef KPSE_DEBUG
+static unsigned int kpathsea_debug = 0;
+#endif
+
 #if defined (WIN32) && !defined (__MINGW32__)
 
 /* System description file for Windows NT.  */
@@ -175,9 +231,7 @@
 
 #define access  _access
 #define stat    _stat
-#define strcasecmp _stricmp
 #define strdup  _strdup
-#define strncasecmp _strnicmp
 
 #define S_IFMT   _S_IFMT
 #define S_IFDIR  _S_IFDIR
@@ -198,8 +252,6 @@
 
 #endif /* WIN32 */
 
-/* lib.h: other stuff.  */
-
 /* Define common sorts of messages.  */
 
 /* This should be called only after a system call fails.  Don't exit
@@ -223,82 +275,53 @@
     } \
   while (0)
 
-extern "C" char *xbasename (const char *name);
-
 #ifndef WIN32
 static void xclosedir (DIR *d);
 #endif
 
+/* It's a little bizarre to be using the same type for the list and the
+   elements of the list, but no reason not to in this case, I think --
+   we never need a NULL string in the middle of the list, and an extra
+   NULL/NULL element always at the end is inconsequential.  */
+
+struct str_llist_elt
+{
+  std::string str;
+  int moved;
+  struct str_llist_elt *next;
+};
+
+typedef str_llist_elt str_llist_elt_type;
+typedef str_llist_elt *str_llist_type;
+
+#define STR_LLIST(sl) ((sl).str)
+#define STR_LLIST_MOVED(sl) ((sl).moved)
+#define STR_LLIST_NEXT(sl) ((sl).next)
+
 static void str_llist_add (str_llist_type *l, const std::string& str);
 
 static void str_llist_float (str_llist_type *l, str_llist_elt_type *mover);
 
 static std::string kpse_var_expand (const std::string& src);
 
+static str_llist_type *kpse_element_dirs (const std::string& elt);
+
+static std::string kpse_expand (const std::string& s);
+
+static std::string kpse_expand_default (const std::string& path,
+					const std::string& dflt);
+
+static string_vector kpse_db_search (const std::string& name,
+				     const std::string& path_elt, bool all);
+
 #include <ctime> /* for `time' */
 
-bool
+static bool
 kpse_is_env_sep (char c)
 {
   return IS_ENV_SEP (c);
 }
 
-/* xmalloc.c: malloc with error checking.  */
-
-static void *
-xmalloc (unsigned size)
-{
-  void *new_mem = (void *) malloc (size);
-
-  if (! new_mem)
-    {
-      fprintf (stderr, "fatal: memory exhausted (xmalloc of %u bytes).\n",
-               size);
-      /* 1 means success on VMS, so pick a random number (ASCII `K').  */
-      exit (75);
-    }
-
-  return new_mem;
-}
-
-/* xrealloc.c: realloc with error checking.  */
-
-static void *
-xrealloc (void *old_ptr, unsigned size)
-{
-  void *new_mem;
-
-  if (! old_ptr)
-    new_mem = xmalloc (size);
-  else
-    {
-      new_mem = (void *) realloc (old_ptr, size);
-
-      if (! new_mem)
-        {
-          /* We used to print OLD_PTR here using %x, and casting its
-             value to unsigned, but that lost on the Alpha, where
-             pointers and unsigned had different sizes.  Since the info
-             is of little or no value anyway, just don't print it.  */
-          fprintf (stderr, "fatal: memory exhausted (realloc of %u bytes).\n",
-                   size);
-          /* 1 means success on VMS, so pick a random number (ASCII `B').  */
-          exit (66);
-        }
-    }
-
-  return new_mem;
-}
-
-/* Return a copy of S in new storage.  */
-
-static char *
-xstrdup (const char *s)
-{
-  char *new_string = (char *) xmalloc (strlen (s) + 1);
-  return strcpy (new_string, s);
-}
-
 /* These routines just check the return status from standard library
    routines and abort if an error happens.  */
 
@@ -487,6 +510,65 @@
 	   total_buckets ? total_elements / (double) total_buckets : 0.0);
 }
 
+/* A way to step through a path, extracting one directory name at a
+   time.  */
+
+class kpse_path_iterator
+{
+public:
+
+  kpse_path_iterator (const std::string& p)
+    : path (p), b (0), e (0), len (path.length ()) { set_end (); }
+
+  kpse_path_iterator (const kpse_path_iterator& pi)
+    : path (pi.path), b (pi.b), e (pi.e), len (pi.len) { }
+
+  kpse_path_iterator operator ++ (int)
+    {
+      kpse_path_iterator retval (*this);
+      next ();
+      return retval;
+    }
+
+  std::string operator * (void) { return path.substr (b, e-b); }
+
+  bool operator != (const size_t sz) { return b != sz; }
+
+private:
+
+  const std::string& path;
+  size_t b;
+  size_t e;
+  size_t len;
+
+  void set_end (void)
+    {
+      e = b + 1;
+
+      if (e >= len)
+	b = e = NPOS;
+      else
+	{
+	  /* Find the next colon not enclosed by braces (or the end of
+	     the path).  */
+
+	  int brace_level = 0;
+	  while (e < len && ! (brace_level == 0 && kpse_is_env_sep (path[e])))
+	    e++;
+	}
+    }
+
+  void next (void)
+    {
+      b = e + 1;
+
+      if (b >= len)
+	b = e = NPOS;
+      else
+	set_end ();
+    }
+};
+
 /* Here's the simple one, when a program just wants a value.  */
 
 static std::string
@@ -891,7 +973,25 @@
 
 /* Search PATH for the first NAME.  */
 
-std::string
+/* Call `kpse_expand' on NAME.  If the result is an absolute or
+   explicitly relative filename, check whether it is a readable
+   (regular) file.
+   
+   Otherwise, look in each of the directories specified in PATH (also do
+   tilde and variable expansion on elements in PATH), using a prebuilt
+   db (see db.h) if it's relevant for a given path element.
+   
+   If the prebuilt db doesn't exist, or if MUST_EXIST is true and NAME
+   isn't found in the prebuilt db, look on the filesystem.  (I.e., if
+   MUST_EXIST is false, and NAME isn't found in the db, do *not* look on
+   the filesystem.)
+   
+   The caller must expand PATH. This is because it makes more sense to
+   do this once, in advance, instead of for every search using it.
+   
+   In any case, return the complete filename if found, otherwise NULL.  */
+
+static std::string
 kpse_path_search (const std::string& path, const std::string& name,
 		  bool must_exist)
 {
@@ -903,7 +1003,10 @@
 /* Search all elements of PATH for files named NAME.  Not sure if it's
    right to assert `must_exist' here, but it suffices now.  */
 
-string_vector
+/* Like `kpse_path_search' with MUST_EXIST true, but return a list of
+   all the filenames (or NULL if none), instead of taking the first.  */
+
+static string_vector
 kpse_all_path_search (const std::string& path, const std::string& name)
 {
   return search (path, name, true, true);
@@ -1087,7 +1190,10 @@
 /* Search each element of PATH for each element of NAMES.  Return the
    first one found.  */
 
-std::string
+/* Search each element of PATH for each element in the list of NAMES.
+   Return the first one found.  */
+
+static std::string
 kpse_path_find_first_of (const std::string& path, const string_vector& names,
 			 bool must_exist)
 {
@@ -1099,14 +1205,18 @@
 /* Search each element of PATH for each element of NAMES and return a
    list containing everything found, in the order found.  */
 
-string_vector
+/* Like `kpse_path_find_first_of' with MUST_EXIST true, but return a
+   list of all the filenames (or NULL if none), instead of taking the
+   first.  */
+
+static string_vector
 kpse_all_path_find_first_of (const std::string& path,
 			     const string_vector& names)
 {
   return find_first_of (path, names, true, true);
 }
 
-/* expand.c: general expansion.  Some of this file (the brace-expansion
+/* General expansion.  Some of this file (the brace-expansion
    code from bash) is covered by the GPL; this is the only GPL-covered
    code in kpathsea.  The part of the file that I wrote (the first
    couple of functions) is covered by the LGPL.  */
@@ -1205,7 +1315,10 @@
 /* Do variable expansion first so ~${USER} works.  (Besides, it's what the
    shells do.)  */
 
-std::string
+/* Call kpse_var_expand and kpse_tilde_expand (in that order).  Result
+   is always in fresh memory, even if no expansions were done.  */
+
+static std::string
 kpse_expand (const std::string& s)
 {
   std::string var_expansion = kpse_var_expand (s);
@@ -1288,9 +1401,13 @@
   return ret;
 }
 
-/* Be careful to not waste all the memory we allocate for each element.  */
-
-std::string
+/* Do brace expansion and call `kpse_expand' on each element of the
+   result; return the final expansion (always in fresh memory, even if
+   no expansions were done).  We don't call `kpse_expand_default'
+   because there is a whole sequence of defaults to run through; see
+   `kpse_init_format'.  */
+
+static std::string
 kpse_brace_expand (const std::string& path)
 {
   /* Must do variable expansion first because if we have
@@ -1321,7 +1438,13 @@
 
 /* Expand all special constructs in a path, and include only the actually
    existing directories in the result. */
-std::string
+
+/* Do brace expansion and call `kpse_expand' on each argument of the
+   result, then expand any `//' constructs.  The final expansion (always
+   in fresh memory) is a path of all the existing directories that match
+   the pattern. */
+
+static std::string
 kpse_path_expand (const std::string& path)
 {
   std::string ret;
@@ -1609,7 +1732,7 @@
   return c;
 }
 
-/* db.c: an external database to avoid filesystem lookups.  */
+/* An external database to avoid filesystem lookups.  */
 
 #ifndef DEFAULT_TEXMFDBS
 #define DEFAULT_TEXMFDBS "/usr/local/share/texmf:/var/tmp/texfonts"
@@ -1622,7 +1745,7 @@
    it via variable expansion, but not now, maybe not ever:
    ${PKFONTS-${TEXFONTS-/usr/local/lib/texmf/fonts//}}.  */
 
-typedef struct
+struct kpse_format_info_type
 {
   std::string type;	     /* Human-readable description.  */
   std::string path;	     /* The search path to use.  */
@@ -1633,7 +1756,7 @@
   std::string cnf_path;	     /* From texmf.cnf.  */
   std::string default_path;  /* If all else fails.  */
   string_vector suffix;	     /* For kpse_find_file to check for/append.  */
-} kpse_format_info_type;
+};
 
 /* The sole variable of that type, indexed by `kpse_file_format_type'.
    Initialized by calls to `kpse_find_file' for `kpse_init_format'.  */
@@ -1837,16 +1960,17 @@
    directories -- ones that don't get searched.  */
 
 static bool
-ignore_dir_p (const std::string& dirname_arg)
+ignore_dir_p (const std::string& dirname)
 {
-  const char *dirname = dirname_arg.c_str ();
-
-  const char *dot_pos = dirname;
-
-  while ((dot_pos = strchr (dot_pos + 1, '.')))
+  size_t dot_pos = 0;
+  size_t len = dirname.length ();
+
+  while ((dot_pos = dirname.find ('.', dot_pos + 1)) != NPOS)
     {
-      /* If / before and no / after, skip it. */
-      if (IS_DIR_SEP (dot_pos[-1]) && dot_pos[1] && !IS_DIR_SEP (dot_pos[1]))
+      /* If / before and no / after, skip it.  But don't skip xxx/../yyy.  */
+      if (IS_DIR_SEP (dirname[dot_pos-1])
+	  && dot_pos + 1 < len
+	  && ! (IS_DIR_SEP (dirname[dot_pos+1]) || dirname[dot_pos+1] == '.'))
 	return true;
     }
 
@@ -2002,20 +2126,20 @@
    during a run.  We wouldn't want to reread all of ls-R, even if it got
    rebuilt.  */
 
-void
+static void
 kpse_db_insert (const std::string& passed_fname)
 {
   /* We might not have found ls-R, or even had occasion to look for it
      yet, so do nothing if we have no hash table.  */
   if (db.buckets)
     {
-      const char *dir_part;
-      char *fname = xstrdup (passed_fname.c_str ());
-      char *baseptr = xbasename (fname);
-      const char *file_part = xstrdup (baseptr);
-
-      *baseptr = '\0';  /* Chop off the filename.  */
-      dir_part = fname; /* That leaves the dir, with the trailing /.  */
+      const char *fname = passed_fname.c_str ();
+      const char *baseptr = octave_basename (fname);
+
+      size_t len = baseptr - fname;
+
+      std::string file_part = passed_fname.substr (len);
+      std::string dir_part = passed_fname.substr (0, len);
 
       hash_insert (&db, file_part, dir_part);
     }
@@ -2206,9 +2330,10 @@
 }
 
 /* Initialize the path for ls-R files, and read them all into the hash
-   table `db'.  If no usable ls-R's are found, set db.buckets to NULL.  */
-
-void
+   table `db'.  If no usable ls-R's are found, set db.buckets to NULL.
+   Until this is called, no ls-R matches will be found.  */
+
+static void
 kpse_init_db (void)
 {
   bool ok = false;
@@ -2264,7 +2389,13 @@
 
 /* Avoid doing anything if this PATH_ELT is irrelevant to the databases. */
 
-string_vector
+/* Return list of matches for NAME in the ls-R file matching PATH_ELT.  If
+   ALL is set, return (null-terminated list) of all matches, else just
+   the first.  If no matches, return a pointer to an empty list.  If no
+   databases can be read, or PATH_ELT is not in any of the databases,
+   return NULL.  */
+
+static string_vector
 kpse_db_search (const std::string& name_arg,
 		const std::string& orig_path_elt, bool all)
 {
@@ -2386,12 +2517,16 @@
   return ret;
 }
 
-/* kdefault.c: Expand extra colons.  */
+/* Expand extra colons.  */
 
 /* Check for leading colon first, then trailing, then doubled, since
    that is fastest.  Usually it will be leading or trailing.  */
 
-std::string
+/* Replace a leading or trailing or doubled : in PATH with DFLT.  If
+   no extra colons, return PATH.  Only one extra colon is replaced.
+   DFLT may not be NULL.  */
+
+static std::string
 kpse_expand_default (const std::string& path, const std::string& fallback)
 {
   std::string expansion;
@@ -2440,8 +2575,7 @@
   return expansion;
 }
 
-/* elt-dirs.c: Translate a path element to its corresponding
-   director{y,ies}.  */
+/* Translate a path element to its corresponding director{y,ies}.  */
 
 /* To avoid giving prototypes for all the routines and then their real
    definitions, we give all the subroutines first.  The entry point is
@@ -2511,7 +2645,7 @@
 {
   cache_entry *new_cache = new cache_entry [cache_length+1];
 
-  for (int i = 0; i < cache_length; i++)
+  for (unsigned i = 0; i < cache_length; i++)
     {
       new_cache[i].key = the_cache[i].key;
       new_cache[i].value = the_cache[i].value;
@@ -2776,7 +2910,16 @@
 
 /* Here is the entry point.  Returns directory list for ELT.  */
 
-str_llist_type *
+/* Given a path element ELT, return a pointer to a NULL-terminated list
+   of the corresponding (existing) directory or directories, with
+   trailing slashes, or NULL.  If ELT is the empty string, check the
+   current working directory.
+   
+   It's up to the caller to expand ELT.  This is because this routine is
+   most likely only useful to be called from `kpse_path_search', which
+   has already assumed expansion has been done.  */
+
+static str_llist_type *
 kpse_element_dirs (const std::string& elt)
 {
   str_llist_type *ret;
@@ -2834,16 +2977,14 @@
 }
 #endif
 
-/* debug.c: Help the user discover what's going on.  */
+/* Help the user discover what's going on.  */
 
 #ifdef KPSE_DEBUG
 
-unsigned int kpathsea_debug = 0;
-
 /* If the real definitions of fopen or fclose are macros, we lose -- the
    #undef won't restore them. */
 
-FILE *
+static FILE *
 fopen (const char *filename, const char *mode)
 {
 #undef fopen
@@ -2855,7 +2996,7 @@
   return ret;
 }
 
-int
+static int
 fclose (FILE *f)
 {
 #undef fclose
@@ -2869,7 +3010,7 @@
 
 #endif
 
-/* str-llist.c: Implementation of a linked list of strings.  */
+/* Implementation of a linked list of strings.  */
 
 /* Add the new string STR to the end of the list L.  */
 
@@ -2943,7 +3084,7 @@
   STR_LLIST_MOVED (*mover) = 1;
 }
 
-/* variable.c: variable expansion.  */
+/* Variable expansion.  */
 
 /* We have to keep track of variables being expanded, otherwise
    constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
@@ -3081,3 +3222,9 @@
 
   return expansion;
 }
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/