changeset 3040:443851377f3f

[project @ 1997-06-06 09:29:28 by jwe]
author jwe
date Fri, 06 Jun 1997 09:34:14 +0000
parents cf74b8097212
children 4b12b66ec09f
files liboctave/ChangeLog liboctave/file-ops.cc liboctave/file-ops.h liboctave/str-vec.cc src/ChangeLog src/defaults.cc src/utils.cc src/utils.h
diffstat 8 files changed, 268 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,11 @@
+Fri Jun  6 04:27:40 1997  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* file-ops.cc (file_ops::tilde_expand): Steal more code from bash
+	to do better job expanding tildes.
+
+	* str-vec.cc (string_vector::string_vector (const char * const *):
+	Use temporary variable to compute length.
+
 Thu Jun  5 01:44:43 1997  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* Makefile.in: Make building of static library optional.
--- a/liboctave/file-ops.cc
+++ b/liboctave/file-ops.cc
@@ -29,6 +29,8 @@
 #include <cstdlib>
 #include <cstring>
 
+#include <iostream.h>
+
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -192,74 +194,250 @@
   return retval;
 }
 
-// If NAME has a leading ~ or ~user, Unix-style, expand it to the
-// user's home directory.  If no ~, or no <pwd.h>, just return NAME.
-
-// Mostly stolen from kpathsea.  Readline also has a more complicated
-// tilde-expand function, but we can probalby get by with something a
-// bit simpler.
+// The following tilde-expansion code was stolen and adapted from
+// readline.
 
 // XXX FIXME XXX
 #define DIR_SEP_CHAR '/'
 
+// The default value of tilde_additional_prefixes.  This is set to
+// whitespace preceding a tilde so that simple programs which do not
+// perform any word separation get desired behaviour.
+static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 };
+
+// The default value of tilde_additional_suffixes.  This is set to
+// whitespace or newline so that simple programs which do not perform
+// any word separation get desired behaviour.
+static const char *default_suffixes[] = { " ", "\n", ":", 0 };
+
+// If non-null, this contains the address of a function that the
+// application wants called before trying the standard tilde
+// expansions.  The function is called with the text sans tilde, and
+// returns a malloc()'ed string which is the expansion, or a NULL
+// pointer if the expansion fails.
+file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0;
+
+// If non-null, this contains the address of a function to call if the
+// standard meaning for expanding a tilde fails.  The function is
+// called with the text (sans tilde, as in "foo"), and returns a
+// malloc()'ed string which is the expansion, or a NULL pointer if
+// there is no expansion.
+file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0;
+
+// When non-null, this is a NULL terminated array of strings which are
+// duplicates for a tilde prefix.  Bash uses this to expand `=~' and
+// `:~'.
+string_vector file_ops::tilde_additional_prefixes = default_prefixes;
+
+// When non-null, this is a NULL terminated array of strings which
+// match the end of a username, instead of just "/".  Bash sets this
+// to `:' and `=~'.
+string_vector file_ops::tilde_additional_suffixes = default_suffixes;
+
+// Find the start of a tilde expansion in S, and return the index
+// of the tilde which starts the expansion.  Place the length of the
+// text which identified this tilde starter in LEN, excluding the
+// tilde itself.
+
+static size_t
+tilde_find_prefix (const string& s, size_t& len)
+{
+  len = 0;
+
+  size_t s_len = s.length ();
+
+  if (s_len == 0 || s[0] == '~')
+    return 0;
+
+  string_vector prefixes = file_ops::tilde_additional_prefixes;
+
+  if (! prefixes.empty ())
+    {
+      for (size_t i = 0; i < s_len; i++)
+	{
+	  for (int j = 0; j < prefixes.length (); j++)
+	    {
+	      size_t pfx_len = prefixes[j].length ();
+
+	      if (prefixes[j].compare (s.substr (i, pfx_len)) == 0)
+		{
+		  len = pfx_len - 1;
+		  return i + len;
+		}
+	    }
+	}
+    }
+
+  return s_len;
+}
+
+// Find the end of a tilde expansion in S, and return the index
+// of the character which ends the tilde definition.
+
+static size_t
+tilde_find_suffix (const string& s)
+{
+  size_t s_len = s.length ();
+
+  string_vector suffixes = file_ops::tilde_additional_suffixes;
+
+  size_t i = 0;
+
+  for ( ; i < s_len; i++)
+    {
+      if (s[i] == DIR_SEP_CHAR)
+	break;
+
+      if (! suffixes.empty ())
+	{
+	  for (int j = 0; j < suffixes.length (); j++)
+	    {
+	      size_t sfx_len = suffixes[j].length ();
+
+	      if (suffixes[j].compare (s.substr (i, sfx_len)) == 0)
+		return i;
+	    }
+	}
+    }
+
+  return i;
+}
+
+// Take FNAME and return the tilde prefix we want expanded.
+
+static string
+isolate_tilde_prefix (const string& fname)
+{
+  size_t f_len = fname.length ();
+
+  size_t len = 1;
+
+  while (len < f_len && fname[len] != DIR_SEP_CHAR)
+    len++;
+
+  return fname.substr (1, len);
+}
+
+// Do the work of tilde expansion on FILENAME.  FILENAME starts with a
+// tilde.
+
+static string
+tilde_expand_word (const string& filename)
+{
+  size_t f_len = filename.length ();
+
+  if (f_len == 0 || filename[0] != '~')
+    return filename;
+
+  // A leading `~/' or a bare `~' is *always* translated to the value
+  // of $HOME or the home directory of the current user, regardless of
+  // any preexpansion hook.
+
+  if (f_len == 1 || filename[1] == DIR_SEP_CHAR)
+    return octave_env::get_home_directory () + filename.substr (1);
+
+  string username = isolate_tilde_prefix (filename);
+
+  size_t user_len = username.length ();
+
+  string dirname;
+
+  if (file_ops::tilde_expansion_preexpansion_hook)
+    {
+      string expansion
+	= file_ops::tilde_expansion_preexpansion_hook (username);
+
+      if (! expansion.empty ())
+	{
+	  dirname = expansion + filename.substr (user_len);
+	  return dirname;
+	}
+    }
+
+  // No preexpansion hook, or the preexpansion hook failed.  Look in the
+  // password database.
+
+  octave_passwd pw = octave_passwd::getpwnam (username);
+
+  if (! pw)
+    {
+      // If the calling program has a special syntax for expanding tildes,
+      // and we couldn't find a standard expansion, then let them try.
+
+      if (file_ops::tilde_expansion_failure_hook)
+	{
+	  string expansion
+	    = file_ops::tilde_expansion_failure_hook (username);
+
+	  if (! expansion.empty ())
+	    dirname = expansion + filename.substr (user_len);
+	}
+
+      // If we don't have a failure hook, or if the failure hook did not
+      // expand the tilde, return a copy of what we were passed.
+
+      if (dirname.length () == 0)
+	dirname = filename;
+    }
+  else
+    dirname = pw.dir () + filename.substr (user_len);
+
+  return dirname;
+}
+
+// If NAME has a leading ~ or ~user, Unix-style, expand it to the
+// user's home directory.  If no ~, or no <pwd.h>, just return NAME.
+
 string
 file_ops::tilde_expand (const string& name)
 {
-  string expansion = name;
+  string result;
 
-  // If no leading tilde, do nothing.
+  size_t name_len = name.length ();
 
-  size_t beg = name.find_first_not_of (" \t");
+  // Scan through S expanding tildes as we come to them.
 
-  if (beg != NPOS && name[beg] == '~')
-    {
-      // If `~' or `~/', use the user's home directory.  If that is
-      // empty, just use ".".
+  size_t pos = 0;
 
-      // If `~user' or `~user/', look up user in the passwd database.
-
-      size_t len = name.length ();
+  while (1)
+    {
+      if (pos > name_len)
+	break;
 
-      if (beg == len-1 || name[beg+1] == DIR_SEP_CHAR)
-	{
-	  string home = octave_env::get_home_directory ();
+      size_t len;
+
+      // Make START point to the tilde which starts the expansion.
 
-	  if (home.empty ())
-	    home = ".";
-        
-	  expansion = name.substr (0, beg) + home;
+      size_t start = tilde_find_prefix (name.substr (pos), len);
+
+      result.append (name.substr (pos, start));
 
-	  if (beg < len)
-	    expansion.append (name.substr (beg+1));
-	}
-      else
-	{
-	  size_t end = name.find (DIR_SEP_CHAR, beg);
+      // Advance STRING to the starting tilde.
+
+      pos += start;
 
-	  size_t len = end;
+      // Make FINI be the index of one after the last character of the
+      // username.
 
-	  if (end != NPOS)
-	    len -= beg + 1;
+      size_t fini = tilde_find_suffix (name.substr (pos));
 
-	  string user = name.substr (beg+1, len);
+      // If both START and FINI are zero, we are all done.
 
-	  octave_passwd pw = octave_passwd::getpwnam (user);
+      if (! (start || fini))
+	break;
 
-	  // If no such user, just return the original string.
+      // Expand the entire tilde word, and copy it into RESULT.
 
-	  if (pw)
-	    {
-	      expansion = string (" ", beg) + pw.dir ();
+      string tilde_word = name.substr (pos, fini);
+
+      pos += fini;
 
-	      if (end != NPOS)
-		expansion.append (name.substr (end));
-	    }
-	  else
-	    expansion = name;
-	}
+      string expansion = tilde_expand_word (tilde_word);
+
+      result.append (expansion);
     }
 
-  return expansion;
+  return result;
 }
 
 // A vector version of the above.
--- a/liboctave/file-ops.h
+++ b/liboctave/file-ops.h
@@ -25,12 +25,12 @@
 
 #include <string>
 
-class string_vector;
-
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
 
+#include "str-vec.h"
+
 struct
 file_ops
 {
@@ -49,6 +49,16 @@
   static string tempnam (const string&, const string&);
   static string tempnam (const string&, const string&, string&);
 
+  typedef string (*tilde_expansion_hook) (const string&);
+
+  static tilde_expansion_hook tilde_expansion_preexpansion_hook;
+
+  static tilde_expansion_hook tilde_expansion_failure_hook;
+
+  static string_vector tilde_additional_prefixes;
+
+  static string_vector tilde_additional_suffixes;
+
   static string tilde_expand (const string&);
   static string_vector tilde_expand (const string_vector&);
 
--- a/liboctave/str-vec.cc
+++ b/liboctave/str-vec.cc
@@ -47,7 +47,9 @@
 {
   int n = 0;
 
-  while (*s++)
+  const char * const *t = s;
+
+  while (*t++)
     n++;
 
   resize (n);
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,13 @@
+Fri Jun  6 04:30:57 1997  John W. Eaton  <jwe@bevo.che.wisc.edu>
+
+	* utils.cc (search_path_for_file): New arg, do_tilde_expansion.
+	If TRUE, perform tilde expansion on path before searching.
+	(file_in_path): Call search_path_for_file with do_tilde_expansion
+	set to false, since we've already performed tilde expansion on the
+	load path.
+
+	* defaults.cc (loadpath): Perform tilde expansion here.
+
 Thu Jun  5 01:42:39 1997  John W. Eaton  <jwe@bevo.che.wisc.edu>
 
 	* Makefile.in: Make building of static library optional.
--- a/src/defaults.cc
+++ b/src/defaults.cc
@@ -42,6 +42,7 @@
 #include <defaults.h>
 #include "defun.h"
 #include "error.h"
+#include "file-ops.h"
 #include "gripes.h"
 #include "help.h"
 #include "ov.h"
@@ -384,7 +385,7 @@
       status = -1;
     }
   else
-    Vload_path = maybe_add_default_load_path (s);
+    Vload_path = file_ops::tilde_expand (maybe_add_default_load_path (s));
 
   return status;
 }
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -57,14 +57,16 @@
 
 #include "SLStack.h"
 
+#include "dir-ops.h"
+#include "file-ops.h"
 #include "file-stat.h"
 #include "oct-cmplx.h"
 #include "oct-env.h"
+#include "pathsearch.h"
 #include "str-vec.h"
 
 #include <defaults.h>
 #include "defun.h"
-#include "dir-ops.h"
 #include "dirfns.h"
 #include "error.h"
 #include "gripes.h"
@@ -72,7 +74,6 @@
 #include "oct-hist.h"
 #include "oct-obj.h"
 #include "pager.h"
-#include "pathsearch.h"
 #include "sysdep.h"
 #include "toplev.h"
 #include "unwind-prot.h"
@@ -227,9 +228,12 @@
 // See if the given file is in the path.
 
 string
-search_path_for_file (const string& path, const string& name)
+search_path_for_file (const string& path, const string& name,
+		      bool do_tilde_expansion)
 {
-  dir_path p (path);
+  string tmp_path = do_tilde_expansion ? file_ops::tilde_expand (path) : path;
+
+  dir_path p (tmp_path);
 
   return octave_env::make_absolute (p.find (name), octave_env::getcwd ());
 }
@@ -269,7 +273,7 @@
   if (! suffix.empty ())
     nm.append (suffix);
 
-  return search_path_for_file (Vload_path, nm);
+  return search_path_for_file (Vload_path, nm, false);
 }
 
 // See if there is an function file in the path.  If so, return the
--- a/src/utils.h
+++ b/src/utils.h
@@ -33,7 +33,7 @@
 class octave_value_list;
 class string_vector;
 
-extern string search_path_for_file (const string&, const string&);
+extern string search_path_for_file (const string&, const string&, bool = true);
 extern string file_in_path (const string&, const string&);
 extern string fcn_file_in_path (const string&);
 extern string oct_file_in_path (const string&);