# HG changeset patch # User Lachlan Andrew # Date 1468641814 -36000 # Node ID 289409b2992d05feeee9498d59275be0cea02b19 # Parent ff54e7882863ab891c4a947b257c2c80e44bdb9f 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. diff -r ff54e7882863 -r 289409b2992d libinterp/corefcn/dirfns.cc --- 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; diff -r ff54e7882863 -r 289409b2992d liboctave/util/oct-glob.cc --- 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 (); + } } } diff -r ff54e7882863 -r 289409b2992d liboctave/util/oct-glob.h --- 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&); } } diff -r ff54e7882863 -r 289409b2992d scripts/miscellaneous/dir.m --- 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