# HG changeset patch # User Markus Mützel # Date 1572166779 -3600 # Node ID 29ccef7e5295dd7871a389ec3a81eecef86e1643 # Parent e78b6e7f743cbce8ffcbe337b8b5ee9ea5a8ce39 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". diff -r e78b6e7f743c -r 29ccef7e5295 doc/interpreter/system.txi --- 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) diff -r e78b6e7f743c -r 29ccef7e5295 libinterp/corefcn/utils.cc --- 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) { diff -r e78b6e7f743c -r 29ccef7e5295 scripts/miscellaneous/dir.m --- 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); diff -r e78b6e7f743c -r 29ccef7e5295 scripts/miscellaneous/run.m --- 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 diff -r e78b6e7f743c -r 29ccef7e5295 scripts/miscellaneous/unpack.m --- 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 diff -r e78b6e7f743c -r 29ccef7e5295 scripts/pkg/private/install.m --- 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); diff -r e78b6e7f743c -r 29ccef7e5295 test/fntests.m --- 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