From d3568852ca0506666fbd1b613439a3916c76ed88 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 2 Dec 2021 10:00:16 +0200 Subject: Add $relative(,) function --- libbuild2/functions-path.cxx | 67 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'libbuild2') 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 + 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() // f["leaf"] += &path::leaf; + // $leaf(, ) + // $leaf(, ) + // + // 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(, ) + // $relative(, ) + // + // 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 (move (n)), d).string (); + } + return ns; + }; + // base // f["base"] += &path::base; -- cgit v1.1