aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/functions-path.cxx67
-rw-r--r--tests/function/path/testscript6
2 files changed, 72 insertions, 1 deletions
diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx
index c23a8a8..2953067 100644
--- a/libbuild2/functions-path.cxx
+++ b/libbuild2/functions-path.cxx
@@ -99,6 +99,20 @@ namespace build2
}
}
+ template <typename P>
+ static inline P
+ relative (const P& p, const dir_path& d)
+ {
+ try
+ {
+ return p.relative (d); // Note: cannot move due to diagnostics.
+ }
+ catch (const invalid_path&)
+ {
+ fail << "'" << p << "' cannot be made relative to '" << d << "'" << endf;
+ }
+ }
+
using butl::path_match;
// Return true if a path matches the pattern. See path_match() overloads
@@ -332,10 +346,18 @@ namespace build2
return ns;
};
- // leaf
+
+ // $leaf(<path>)
//
f["leaf"] += &path::leaf;
+ // $leaf(<path>, <dir-path>)
+ // $leaf(<paths>, <dir-path>)
+ //
+ // Return the path without the specified directory part. Return empty path
+ // if the paths are the same. Issue diagnostics and fail if the directory
+ // is not a prefix of the path. Note: expects both paths to be normalized.
+ //
f["leaf"] += [](path p, dir_path d)
{
return leaf (p, move (d));
@@ -371,6 +393,49 @@ namespace build2
return ns;
};
+ // $relative(<path>, <dir-path>)
+ // $relative(<paths>, <dir-path>)
+ //
+ // Return a path relative to the specified directory that is equivalent to
+ // the specified path. Issue diagnostics and fail if a relative path
+ // cannot be derived (for example, paths are on different drives on
+ // Windows).
+ //
+ f["relative"] += [](path p, dir_path d)
+ {
+ return relative (p, d);
+ };
+
+ f["relative"] += [](paths v, dir_path d)
+ {
+ for (path& p: v)
+ p = relative (p, d);
+ return v;
+ };
+
+ f["relative"] += [](dir_paths v, dir_path d)
+ {
+ for (dir_path& p: v)
+ p = relative (p, d);
+ return v;
+ };
+
+ f[".relative"] += [](names ns, dir_path d)
+ {
+ // For each path decide based on the presence of a trailing slash
+ // whether it is a directory. Return as untyped list of (potentially
+ // mixed) paths.
+ //
+ for (name& n: ns)
+ {
+ if (n.directory ())
+ n.dir = relative (n.dir, d);
+ else
+ n.value = relative (convert<path> (move (n)), d).string ();
+ }
+ return ns;
+ };
+
// base
//
f["base"] += &path::base;
diff --git a/tests/function/path/testscript b/tests/function/path/testscript
index 55d727f..b0c97c9 100644
--- a/tests/function/path/testscript
+++ b/tests/function/path/testscript
@@ -79,6 +79,12 @@ if! $posix
EOE
}
+: relative
+:
+{
+ $* <'print $relative([path] a/b/c, [dir_path] a/x/y)' >"../../b/c" : basics
+}
+
: extension
:
{