changeset 22155:289409b2992d

Allow dir to accept [ and ] in arguments. (bug #47950) * liboctave/util/oct-glob.{cc,h} (windows_glob): New function * libinterp/corefcn/dirfns.cc (__wglob__): New wrapper for the above * dir.m: Call __wglob__ instead of glob.
author Lachlan Andrew <lachlanbis@gmail.com>
date Sat, 16 Jul 2016 14:03:34 +1000
parents ff54e7882863
children 187b6727c75e
files libinterp/corefcn/dirfns.cc liboctave/util/oct-glob.cc liboctave/util/oct-glob.h scripts/miscellaneous/dir.m
diffstat 4 files changed, 177 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/dirfns.cc	Thu Jul 21 07:49:44 2016 -0400
+++ b/libinterp/corefcn/dirfns.cc	Sat Jul 16 14:03:34 2016 +1000
@@ -37,6 +37,7 @@
 #include "file-stat.h"
 #include "glob-match.h"
 #include "oct-env.h"
+#include "oct-glob.h"
 #include "pathsearch.h"
 #include "str-vec.h"
 
@@ -486,6 +487,73 @@
   return ovl (Cell (pattern.glob ()));
 }
 
+
+DEFUN (__wglob__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} __wglob__ (@var{pattern})
+Windows-like glob for dir.
+
+Given an array of pattern strings (as a char array or a cell array) in
+@var{pattern}, return a cell array of filenames that match any of
+them, or an empty cell array if no patterns match.
+
+The pattern strings are interpreted as filename globbing patterns
+(roughly as they are used by Windows dir).
+
+Within a pattern
+
+@table @code
+@item *
+matches any string, including the null string,
+
+@item ?
+matches any single character, and
+
+@item *.*
+matches any string, even if no . is present.
+@end table
+
+Tilde expansion is performed on each of the patterns before looking for
+matching filenames.  For example:
+
+@example
+ls
+   @result{}
+      file1  file2  file3  myfile1 myfile1b
+glob ("*file1")
+   @result{}
+      @{
+        [1,1] = file1
+        [2,1] = myfile1
+      @}
+glob ("myfile?")
+   @result{}
+      @{
+        [1,1] = myfile1
+      @}
+glob ("*.*")
+   @result{}
+      @{
+        [1,1] = file1
+        [2,1] = file2
+        [3,1] = file3
+        [4,1] = myfile1
+        [5,1] = myfile1b
+      @}
+@end example
+@seealso{glob, dir}
+@end deftypefn */)
+{
+  if (args.length () == 0)
+    return ovl ();
+
+  string_vector pat = args(0).string_vector_value ();
+
+  string_vector pattern (octave::sys::file_ops::tilde_expand (pat));
+
+  return ovl (Cell (octave::sys::windows_glob (pattern)));
+}
+
 /*
 %!test
 %! tmpdir = tempname;
--- a/liboctave/util/oct-glob.cc	Thu Jul 21 07:49:44 2016 -0400
+++ b/liboctave/util/oct-glob.cc	Sat Jul 16 14:03:34 2016 +1000
@@ -139,5 +139,110 @@
 
       return retval.sort ();
     }
+
+    // Glob like Windows "dir".  Treat only * and ? as wildcards,
+    // and "*.*" matches filenames even if they do not contain ".".
+    string_vector
+    windows_glob (const string_vector& pat)
+    {
+      string_vector retval;
+
+      int npat = pat.numel ();
+
+      int k = 0;
+
+      octave::unwind_protect frame;
+
+      void *glob_info = octave_create_glob_info_struct ();
+
+      frame.add_fcn (octave_destroy_glob_info_struct, glob_info);
+
+      for (int i = 0; i < npat; i++)
+        {
+          std::string xpat = pat(i);
+
+          if (! xpat.empty ())
+            {
+              std::string escaped;
+              escaped.reserve (xpat.length ());
+
+              for (size_t j = 0; j < xpat.length (); j++)
+                {
+#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
+     && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
+                  if (xpat[j] == '\\')
+                      escaped += '/';
+                  else
+#endif
+                  {
+                    if (xpat[j] == ']' || xpat[j] == '[')
+                      escaped += '\\';
+
+                    escaped += xpat[j];
+                  }
+                }
+
+              // Replace trailing "*.*" by "*".
+              int len = escaped.length ();
+              if (len >= 3 && escaped.substr (len - 3) == "*.*")
+                escaped = escaped.substr (0, len - 2);
+
+              int err = octave_glob_wrapper (escaped.c_str (),
+                                             octave_glob_nosort_wrapper (),
+                                             glob_info);
+
+              if (! err)
+                {
+                  int n = octave_glob_num_matches (glob_info);
+
+                  const char * const *matches
+                    = octave_glob_match_list (glob_info);
+
+                  // FIXME: we shouldn't have to check to see if
+                  // a single match exists, but it seems that glob() won't
+                  // check for us unless the pattern contains globbing
+                  // characters.  Hmm.
+
+                  if (n > 1
+                      || (n == 1
+                          && single_match_exists (std::string (matches[0]))))
+                    {
+                      retval.resize (k + n);
+
+                      for (int j = 0; j < n; j++)
+                        {
+                          std::string tmp = matches[j];
+
+                          std::string unescaped;
+                          unescaped.reserve (tmp.length ());
+
+                          for (size_t m = 0; m < tmp.length (); m++)
+                            {
+#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
+     && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
+                              if (tmp[m] == '/')
+                                  unescaped += '\\';
+                              else
+#endif
+                              {
+                                if (tmp[m] == '\\'
+                                    && ++m == tmp.length ())
+                                  break;
+
+                                unescaped += tmp[m];
+                              }
+                            }
+
+                          retval[k++] = unescaped;
+                        }
+                    }
+
+                  octave_globfree_wrapper (glob_info);
+                }
+            }
+        }
+
+      return retval.sort ();
+    }
   }
 }
--- a/liboctave/util/oct-glob.h	Thu Jul 21 07:49:44 2016 -0400
+++ b/liboctave/util/oct-glob.h	Sat Jul 16 14:03:34 2016 +1000
@@ -37,6 +37,9 @@
 
     extern string_vector
     glob (const string_vector&);
+
+    extern string_vector
+    windows_glob (const string_vector&);
   }
 }
 
--- a/scripts/miscellaneous/dir.m	Thu Jul 21 07:49:44 2016 -0400
+++ b/scripts/miscellaneous/dir.m	Sat Jul 16 14:03:34 2016 +1000
@@ -91,7 +91,7 @@
     flst = {"."};
     nf = 1;
   else
-    flst = glob (directory);
+    flst = __wglob__ (directory);
     nf = numel (flst);
   endif