Skip to content

Commit 1340491

Browse files
committed
mex: relative
1 parent ed1dae9 commit 1340491

File tree

5 files changed

+93
-36
lines changed

5 files changed

+93
-36
lines changed

+stdlib/relative_to.m

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@
66
other (1,1) string
77
end
88

9-
r = "";
9+
if strcmp(base, other)
10+
r = ".";
11+
return
12+
end
1013

11-
if stdlib.is_url(base) || stdlib.is_url(other), return, end
14+
if ~stdlib.len(base) || ~stdlib.len(other)
15+
r = "";
16+
return
17+
end
1218

1319
% must remove trailing slashes
14-
b1 = stdlib.drop_slash(base);
15-
o1 = stdlib.drop_slash(other);
16-
17-
b1 = strrep(b1, "/./", "/");
18-
o1 = strrep(o1, "/./", "/");
20+
b1 = stdlib.canonical(base);
21+
o1 = stdlib.canonical(other);
1922

2023
if strcmp(b1, o1)
2124
r = ".";
@@ -25,10 +28,6 @@
2528
b = javaPathObject(b1);
2629
o = javaPathObject(o1);
2730

28-
if ~isempty(strfind(b1, "..")) %#ok<STREMP>
29-
warning("relative_to(%s) is ambiguous base with '..' consider using stdlib.canonical() first", b1)
30-
end
31-
3231
try
3332
r = jPosix(b.relativize(o));
3433
catch e

buildfile.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ function publishTask(context)
9797
srcs = {
9898
["src/is_admin.cpp", "src/admin_fs.cpp"] ...
9999
"src/is_char_device.cpp", ...
100+
"src/relative_to.cpp", ...
100101
["src/is_wsl.cpp", linux], ...
101102
"src/set_permissions.cpp", ...
102103
["src/is_rosetta.cpp", mac], ...

src/read_symlink.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class MexFunction : public matlab::mex::Function {
3636
// actual function algorithm / computation
3737
std::string out = fs_read_symlink(in);
3838

39-
// convert to Matlab output
4039
outputs[0] = factory.createScalar(out);
4140
}
4241
};

src/relative_to.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include "mex.hpp"
2+
#include "mexAdapter.hpp"
3+
4+
#include <string>
5+
6+
#include <vector>
7+
#include <memory>
8+
9+
#include <system_error>
10+
#include <filesystem>
11+
12+
#include "ffilesystem.h"
13+
14+
15+
16+
class MexFunction : public matlab::mex::Function {
17+
public:
18+
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
19+
// boilerplate engine & ArrayFactory setup
20+
std::shared_ptr<matlab::engine::MATLABEngine> matlabEng = getEngine();
21+
22+
matlab::data::ArrayFactory factory;
23+
// wrangle inputs
24+
std::string base, other;
25+
26+
if (inputs.size() != 2) {
27+
matlabEng->feval(u"error", 0,
28+
std::vector<matlab::data::Array>({ factory.createScalar("Mex: Two inputs required") }));
29+
}
30+
31+
if ((inputs[0].getType() == matlab::data::ArrayType::MATLAB_STRING && inputs[0].getNumberOfElements() == 1)){
32+
matlab::data::TypedArray<matlab::data::MATLABString> stringArr = inputs[0];
33+
base = stringArr[0];
34+
} else if (inputs[0].getType() == matlab::data::ArrayType::CHAR){
35+
matlab::data::CharArray charArr = inputs[0];
36+
base.assign(charArr.begin(), charArr.end());
37+
} else {
38+
matlabEng->feval(u"error", 0,
39+
std::vector<matlab::data::Array>({ factory.createScalar("Mex: First input must be a scalar string or char vector") }));
40+
}
41+
42+
if ((inputs[1].getType() == matlab::data::ArrayType::MATLAB_STRING && inputs[1].getNumberOfElements() == 1)){
43+
matlab::data::TypedArray<matlab::data::MATLABString> stringArr = inputs[1];
44+
other = stringArr[0];
45+
} else if (inputs[1].getType() == matlab::data::ArrayType::CHAR){
46+
matlab::data::CharArray charArr = inputs[1];
47+
other.assign(charArr.begin(), charArr.end());
48+
} else {
49+
matlabEng->feval(u"error", 0,
50+
std::vector<matlab::data::Array>({ factory.createScalar("Mex: Second input must be a scalar string or char vector") }));
51+
}
52+
53+
// actual function algorithm / computation
54+
std::error_code ec;
55+
std::string out;
56+
57+
out = std::filesystem::relative(other, base, ec).generic_string();
58+
59+
if(ec)
60+
matlabEng->feval(u"error", 0,
61+
std::vector<matlab::data::Array>({ factory.createScalar(ec.message()) }));
62+
63+
outputs[0] = factory.createScalar(out);
64+
}
65+
};

test/TestRelative.m

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,30 @@ function test_proximate_to(tc, pp)
3535
{"Hello", "Hello/", "."}, ...
3636
{"a/./b", "a/b", "."}, ...
3737
{"a/b", "a/./b", "."}, ...
38-
{"./this/one", "./this/two", "../two"}, ...
39-
{"/path/same", "/path/same/hi/..", "hi/.."}, ...
40-
{"", "/", ""}, ...
41-
{"/", "", ""}, ...
38+
{"./a/b", "./a/c", "../c"}, ...
4239
{"/", "/", "."}, ...
43-
{"/dev/null", "/dev/null", "."}, ...
44-
{"/a/b", "c", ""}, ...
45-
{"c", "/a/b", ""}, ...
46-
{"/a/b", "/a/b", "."}, ...
47-
{"/a/b", "/a", ".."}, ...
48-
{"/a/b/c/d", "/a/b", "../.."}, ...
49-
{"this/one", "this/two", "../two"}};
40+
{"a/b/c/d", "a/b", "../.."}, ...
41+
{"a/b", "a/c", "../c"}, ...
42+
{"a/b", "c", "../../c"}, ...
43+
{"c", "a/b", "../a/b"}, ...
44+
{"a/b", "a/b", "."}, ...
45+
{"a/b", "a", ".."}
46+
};
5047
% NOTE: ".." in relative_to(base) is ambiguous including for python.pathlib, C++ <filesystem>, etc.
5148

5249
if ispc
5350
p = [p, ...
54-
{{"c:\a\b", "c:/", "../.."}, ...
55-
{"c:\", "c:/a/b", "a/b"}, ...
51+
{{"C:/a/b", "C:/", "../.."}, ...
52+
{"C:/", "C:/a/b", "a/b"}, ...
5653
{"c:/a/b", "c:/a/b", "."}, ...
5754
{"c:/a/b", "c:/a", ".."}, ...
5855
{"c:\a/b\c/d", "c:/a\b", "../.."}, ...
59-
{"c:/path", "d:/path", ""}}];
56+
{"C:/path", "D:/path", ""}}];
57+
% note: on Windows the drive letter should be uppercase!
58+
else
59+
p = [p, ...
60+
{{"", "a", "a"}, ...
61+
{"/dev/null", "/dev/null", "."}}];
6062
end
6163

6264
end
@@ -66,18 +68,9 @@ function test_proximate_to(tc, pp)
6668

6769
p = init_rel();
6870

69-
p{8}{3} = "/";
70-
p{12}{3} = "c";
71-
p{13}{3} = "/a/b";
7271

7372
if ispc
74-
p{8}{3} = "/";
75-
p{12}{3} = "c";
76-
p{13}{3} = "/a/b";
77-
78-
p{end}{3} = "d:/path";
73+
p{end}{3} = "D:/path";
7974
end
8075

81-
p{end+1} = {"file:///", "file:///", ""};
82-
8376
end

0 commit comments

Comments
 (0)