changeset 27569:29ccef7e5295

New function "is_same_file". * utils.cc (Fis_same_file): New function that checks if two paths refer to the same file or folder. * system.txi: Add function to manual. * dir.m, run.m, unpack.m, pkg/private/install.m, fntests.m: Use new function instead of "strcmp".
author Markus Mützel <markus.muetzel@gmx.de>
date Sun, 27 Oct 2019 09:59:39 +0100
parents e78b6e7f743c
children 775412096ae4
files doc/interpreter/system.txi libinterp/corefcn/utils.cc scripts/miscellaneous/dir.m scripts/miscellaneous/run.m scripts/miscellaneous/unpack.m scripts/pkg/private/install.m test/fntests.m
diffstat 7 files changed, 132 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/system.txi	Sat Oct 26 19:00:54 2019 -0700
+++ b/doc/interpreter/system.txi	Sun Oct 27 09:59:39 2019 +0100
@@ -222,6 +222,8 @@
 
 @DOCSTRING(is_absolute_filename)
 
+@DOCSTRING(is_same_file)
+
 @DOCSTRING(is_rooted_relative_filename)
 
 @DOCSTRING(recycle)
--- a/libinterp/corefcn/utils.cc	Sat Oct 26 19:00:54 2019 -0700
+++ b/libinterp/corefcn/utils.cc	Sun Oct 27 09:59:39 2019 +0100
@@ -137,7 +137,117 @@
   {
     return same_file_internal (f, g);
   }
+}
 
+DEFUN (is_same_file, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {@var{same} =} is_same_file (@var{filepath1}, @var{filepath2})
+Return true if @var{filepath1} and @var{filepath2} both refer to the same file.
+
+Depending on the file system and platform, the same file or folder can be
+referred to with different paths.  This function returns true if the paths in
+@var{filepath1} and @var{filepath2} actually refer to the same file or folder,
+and false otherwise.
+
+If either @var{filepath1} or @var{filepath2} is a cell array of strings, then an
+array of the same size is returned, containing the values described above for
+every member of the cell array.  The other argument may also be a cell
+array of strings (of the same size) or character string.
+
+@seealso{canonicalize_file_name, strcmp}
+@end deftypefn */)
+{
+  if (args.length () != 2)
+    print_usage ();
+
+  octave_value retval;
+
+  bool s1_string = args(0).is_string ();
+  bool s1_cell = args(0).iscell ();
+  bool s2_string = args(1).is_string ();
+  bool s2_cell = args(1).iscell ();
+
+  if (s1_string && s2_string)
+    {
+      std::string file1 = args(0).string_value ();
+      std::string file2 = args(1).string_value ();
+
+      retval = octave::same_file (file1, file2);
+    }
+  else if ((s1_string && s2_cell) || (s1_cell && s2_string))
+    {
+      octave_value str_val, cell_val;
+
+      if (s1_string)
+        {
+          str_val = args(0);
+          cell_val = args(1);
+        }
+      else
+        {
+          str_val = args(1);
+          cell_val = args(0);
+        }
+
+      const Cell cell = cell_val.cell_value ();
+      const std::string str = str_val.string_value ();
+
+      boolNDArray output (cell_val.dims (), false);
+
+      if (! cell_val.iscellstr ())
+        error ("is_same_file: cell values must contain strings");
+
+      for (octave_idx_type idx = 0; idx < cell.numel (); idx++)
+        output(idx) = octave::same_file (str, cell(idx).string_value ());
+
+      retval = output;
+    }
+  else if (s1_cell && s2_cell)
+    {
+      if (! args(0).iscellstr () || ! args(1).iscellstr ())
+        error ("is_same_file: cell values must contain strings");
+
+      const Cell cell1 = args(0).cell_value ();
+      const Cell cell2 = args(1).cell_value ();
+
+      const dim_vector size1 = cell1.dims ();
+      const dim_vector size2 = cell2.dims ();
+
+      if (size1 != size2)
+        error ("is_same_file: nonconformant cell arrays");
+
+      boolNDArray output (size1, false);
+
+      for (octave_idx_type idx = 0; idx < cell1.numel (); idx++)
+        output(idx) = octave::same_file (cell1(idx).string_value (),
+                                         cell2(idx).string_value ());
+
+      retval = output;
+    }
+  else
+    error ("is_same_file: input must be cell strings or strings");
+
+  return retval;
+}
+
+/*
+%!testif ; ! ispc ()
+%! assert (is_same_file ("~", tilde_expand ("~")), true);
+%!testif ; ispc ()
+%! assert (is_same_file (tolower (getenv ("OCTAVE_HOME")),
+%!                       toupper (getenv ("OCTAVE_HOME"))), true);
+%!assert (is_same_file ({pwd(), ".", tempdir()}, canonicalize_file_name (".")),
+%!        [true, true, false])
+
+%!error is_same_file ()
+%!error is_same_file ("foo")
+%!error is_same_file ("foo", 1)
+%!error is_same_file ("foo", {1,2,3})
+*/
+
+
+namespace octave
+{
   int almost_match (const std::string& std, const std::string& s,
                     int min_match_len, int case_sens)
   {
--- a/scripts/miscellaneous/dir.m	Sat Oct 26 19:00:54 2019 -0700
+++ b/scripts/miscellaneous/dir.m	Sun Oct 27 09:59:39 2019 +0100
@@ -137,13 +137,13 @@
           endif
         endif
         tmpdir = regexprep (fn, re, '$1');
-        if (strcmp (fn, tmpdir))
+        if (is_same_file (fn, tmpdir))
           ## regexrep failed to match, no directory component.
           tmpdir = ".";
         endif
         fn = regexprep (fn, re, '$2$3');
         info(++cnt).name = fn;
-        if (! strcmp (last_dir, tmpdir))
+        if (! is_same_file (last_dir, tmpdir))
           ## Caching mechanism to speed up function
           last_dir = tmpdir;
           last_absdir = canonicalize_file_name (last_dir);
--- a/scripts/miscellaneous/run.m	Sat Oct 26 19:00:54 2019 -0700
+++ b/scripts/miscellaneous/run.m	Sun Oct 27 09:59:39 2019 +0100
@@ -71,7 +71,7 @@
       evalin ("caller", sprintf ("source ('%s%s');", f, ext),
               "rethrow (lasterror ())");
     unwind_protect_cleanup
-      if (strcmp (scriptdir, pwd ()))
+      if (is_same_file (scriptdir, pwd ()))
         cd (startdir);
       endif
     end_unwind_protect
@@ -125,10 +125,10 @@
 %!   ## Check if temporary directory is on the loadpath.
 %!   ## Function 'dir_in_loadpath' is broken for this use case, so code a test.
 %!   dirs = strsplit (path (), pathsep ());
-%!   tstval1 = any (strcmp (tmp_dir, dirs));
+%!   tstval1 = any (is_same_file (tmp_dir, dirs));
 %!   run (test_function);
 %!   dirs = strsplit (path (), pathsep ());
-%!   tstval2 = any (strcmp (tmp_dir, dirs));
+%!   tstval2 = any (is_same_file (tmp_dir, dirs));
 %!   assert (tstval1, false);
 %!   assert (tstval2, true);
 %! unwind_protect_cleanup
--- a/scripts/miscellaneous/unpack.m	Sat Oct 26 19:00:54 2019 -0700
+++ b/scripts/miscellaneous/unpack.m	Sun Oct 27 09:59:39 2019 +0100
@@ -221,6 +221,17 @@
     file = __w2mpth__ (file);
   endif
 
+  ## Create the output directory if necessary.
+  s = stat (dir);
+  if (isempty (s))
+    [status, msg] = mkdir (dir);
+    if (! status)
+      error ("unpack: mkdir failed to create %s: %s", dir, msg);
+    endif
+  elseif (! S_ISDIR (s.mode))
+    error ("unpack: %s: not a directory", dir);
+  endif
+
   if (isfield (commandlist, tolower (nodotext)))
     [commandv, commandq, parsefcn, move] = deal (commandlist.(nodotext){:});
     origdir = pwd ();
@@ -234,7 +245,7 @@
     if (cenddir(end) == filesep)
       cenddir(end) = [];
     endif
-    needmove = move && ! strcmp (cstartdir, cenddir);
+    needmove = move && ! is_same_file (cstartdir, cenddir);
     if (nargout > 0 || needmove)
       command = commandv;
     else
@@ -246,17 +257,6 @@
     return;
   endif
 
-  ## Create the directory if necessary.
-  s = stat (dir);
-  if (isempty (s))
-    [status, msg] = mkdir (dir);
-    if (! status)
-      error ("unpack: mkdir failed to create %s: %s", dir, msg);
-    endif
-  elseif (! S_ISDIR (s.mode))
-    error ("unpack: %s: not a directory", dir);
-  endif
-
   ## Save and restore the TAR_OPTIONS environment variable used by GNU tar.
   tar_options_env = getenv ("TAR_OPTIONS");
   unwind_protect
--- a/scripts/pkg/private/install.m	Sat Oct 26 19:00:54 2019 -0700
+++ b/scripts/pkg/private/install.m	Sun Oct 27 09:59:39 2019 +0100
@@ -503,8 +503,7 @@
       error ("couldn't copy files to the installation directory");
     endif
     if (isfolder (fullfile (desc.dir, getarch ()))
-        && ! strcmp (canonicalize_file_name (fullfile (desc.dir, getarch ())),
-                     canonicalize_file_name (octfiledir)))
+        && ! is_same_file (fullfile (desc.dir, getarch ()), octfiledir))
       if (! isfolder (octfiledir))
         ## Can be required to create up to three levels of dirs.
         octm1 = fileparts (octfiledir);
--- a/test/fntests.m	Sat Oct 26 19:00:54 2019 -0700
+++ b/test/fntests.m	Sun Oct 27 09:59:39 2019 +0100
@@ -32,7 +32,7 @@
 topsrcdir = canonicalize_file_name (fullfile (xdir, ".."));
 topbuilddir = canonicalize_file_name (fullfile (currdir, ".."));
 
-if (strcmp (currdir, srcdir))
+if (is_same_file (currdir, srcdir))
   testdirs = {srcdir};
 else
   testdirs = {currdir, srcdir};
@@ -45,7 +45,7 @@
 
 fundirs = {liboctave_tree, src_tree, script_tree};
 
-if (! strcmp (currdir, srcdir))
+if (! is_same_file (currdir, srcdir))
   fundirs{end+1} = local_script_tree;
 endif