changeset 30979:302faf5bc425 stable

__wglob__: Correctly handle "." and ".." in patterns on Windows (bug #62414). * liboctave/util/oct-glob.cc (find_files): Retain "." and ".." literally in result. * libinterp/corefcn/dirfns.cc (F__wglob__): Add tests. Move test for "Fglob" immediately below function definition.
author Markus Mützel <markus.muetzel@gmx.de>
date Thu, 05 May 2022 19:23:06 +0200
parents 791bc376f979
children e33444cd822f 1ce1c4552d5b
files libinterp/corefcn/dirfns.cc liboctave/util/oct-glob.cc
diffstat 2 files changed, 75 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/dirfns.cc	Sun May 01 11:38:16 2022 +0200
+++ b/libinterp/corefcn/dirfns.cc	Thu May 05 19:23:06 2022 +0200
@@ -534,6 +534,37 @@
   return ovl (Cell (pattern.glob ()));
 }
 
+/*
+%!test
+%! tmpdir = tempname ();
+%! filename = {"file1", "file2", "file3", "myfile1", "myfile1b"};
+%! if (mkdir (tmpdir))
+%!   cwd = pwd ();
+%!   cd (tmpdir);
+%!   if (strcmp (canonicalize_file_name (pwd), canonicalize_file_name (tmpdir)))
+%!     a = 0;
+%!     for n = 1:5
+%!       save (filename{n}, "a");
+%!     endfor
+%!   else
+%!     sts = rmdir (tmpdir);
+%!     error ("Couldn't change to temporary directory");
+%!   endif
+%! else
+%!   error ("Couldn't create temporary directory");
+%! endif
+%! result1 = glob ("*file1");
+%! result2 = glob ("myfile?");
+%! result3 = glob ("file[12]");
+%! for n = 1:5
+%!   delete (filename{n});
+%! endfor
+%! cd (cwd);
+%! sts = rmdir (tmpdir);
+%! assert (result1, {"file1"; "myfile1"});
+%! assert (result2, {"myfile1"});
+%! assert (result3, {"file1"; "file2"});
+*/
 
 DEFUN (__wglob__, args, ,
        doc: /* -*- texinfo -*-
@@ -602,35 +633,32 @@
 }
 
 /*
-%!test
-%! tmpdir = tempname ();
-%! filename = {"file1", "file2", "file3", "myfile1", "myfile1b"};
-%! if (mkdir (tmpdir))
-%!   cwd = pwd ();
-%!   cd (tmpdir);
-%!   if (strcmp (canonicalize_file_name (pwd), canonicalize_file_name (tmpdir)))
-%!     a = 0;
-%!     for n = 1:5
-%!       save (filename{n}, "a");
-%!     endfor
-%!   else
-%!     sts = rmdir (tmpdir);
-%!     error ("Couldn't change to temporary directory");
-%!   endif
-%! else
-%!   error ("Couldn't create temporary directory");
+%!test <*62414>
+%! ## get name of current directory and one file in it
+%! [~, curr_dir, ext] = fileparts (pwd ());
+%! curr_dir = [curr_dir, ext];
+%! files = dir ();
+%! if (numel (files) < 3)
+%!   return;
 %! endif
-%! result1 = glob ("*file1");
-%! result2 = glob ("myfile?");
-%! result3 = glob ("file[12]");
-%! for n = 1:5
-%!   delete (filename{n});
-%! endfor
-%! cd (cwd);
-%! sts = rmdir (tmpdir);
-%! assert (result1, {"file1"; "myfile1"});
-%! assert (result2, {"myfile1"});
-%! assert (result3, {"file1"; "file2"});
+%! ## check some patterns including "." and ".."
+%! file_in_pwd = files(3).name;
+%! assert (__wglob__ (file_in_pwd), {file_in_pwd});
+%! glob_pattern = fullfile (".", file_in_pwd);
+%! assert (__wglob__ (glob_pattern), {glob_pattern});
+%! glob_pattern = fullfile ("..", curr_dir, file_in_pwd);
+%! assert (__wglob__ (glob_pattern), {glob_pattern});
+%! glob_pattern = fullfile ("..", curr_dir, "..", ".", curr_dir, ".", file_in_pwd);
+%! assert (__wglob__ (glob_pattern), {glob_pattern});
+
+%!test <*62414>
+%! old_dir = cd (fileparts (which ("plot.m")));
+%! unwind_protect
+%!   assert (__wglob__ (fullfile (".", "*.m")), ...
+%!           fullfile (".", __wglob__ ("*.m")));
+%! unwind_protect_cleanup
+%!   cd (old_dir);
+%! end_unwind_protect
 */
 
 DEFUN (__fnmatch__, args, ,
--- a/liboctave/util/oct-glob.cc	Sun May 01 11:38:16 2022 +0200
+++ b/liboctave/util/oct-glob.cc	Thu May 05 19:23:06 2022 +0200
@@ -157,6 +157,24 @@
     find_files (std::list<std::string>& dirlist, const std::string& dir,
                 const std::string& pat, std::string& file)
     {
+      if (! pat.compare (".") || ! pat.compare (".."))
+        {
+          // shortcut for trivial patterns that would expand to a folder name
+
+          // get next component of path (or file name)
+          std::size_t sep_pos
+            = file.find_first_of (sys::file_ops::dir_sep_chars ());
+          std::string pat_str = file.substr (0, sep_pos);
+          std::string file_str = (sep_pos != std::string::npos
+                                  && file.length () > sep_pos+1)
+                                 ? file.substr (sep_pos+1) : "";
+
+          // call this function recursively with next path component in PAT
+          find_files (dirlist, sys::file_ops::concat (dir, pat),
+                      pat_str, file_str);
+          return;
+        }
+
       // remove leading file separators
       while (file.length () > 1 && sys::file_ops::is_dir_sep (file[0]))
         file = file.substr (1, std::string::npos);
@@ -178,6 +196,7 @@
 
           if (file.empty ())
             {
+              // Don't include "." and ".." in matches.
               if (found_dir.compare (".") && found_dir.compare (".."))
                 dirlist.push_back (sys::file_ops::concat (dir, found_dir));
             }