diff options
-rw-r--r-- | libbuild2/functions-filesystem.cxx | 107 | ||||
-rw-r--r-- | libbuild2/functions-path.cxx | 126 | ||||
-rw-r--r-- | libbuild2/functions-project-name.cxx | 2 | ||||
-rw-r--r-- | tests/function/filesystem/testscript | 79 | ||||
-rw-r--r-- | tests/function/path/testscript | 79 |
5 files changed, 206 insertions, 187 deletions
diff --git a/libbuild2/functions-filesystem.cxx b/libbuild2/functions-filesystem.cxx index 701fa74..1594623 100644 --- a/libbuild2/functions-filesystem.cxx +++ b/libbuild2/functions-filesystem.cxx @@ -3,7 +3,6 @@ // license : MIT; see accompanying LICENSE file #include <libbutl/filesystem.mxx> -#include <libbutl/path-pattern.mxx> #include <libbuild2/function.hxx> #include <libbuild2/variable.hxx> @@ -77,47 +76,6 @@ namespace build2 return r; } - using butl::path_match; - - // Return true if a path for a filesystem entry matches the pattern. See - // path_match() overloads (below) for details. - // - static bool - path_match (const path& entry, - const path& pattern, - const optional<dir_path>& start) - { - // If pattern and entry are both either absolute or relative and - // non-empty, and the first pattern component is not a self-matching - // wildcard, then ignore the start directory. - // - bool rel (pattern.relative () == entry.relative () && - !pattern.empty () && !entry.empty ()); - - if (rel && !path_pattern_self_matching (pattern)) - return path_match (entry, pattern); - - // The start directory must be specified and be absolute. - // - if (!start || start->relative ()) - { - diag_record dr (fail); - - // Print paths "as is". - // - if (!start) - dr << "start directory is not specified"; - else - dr << "start directory path '" << start->representation () - << "' is relative"; - - dr << info << "pattern: '" << pattern.representation () << "'" - << info << "entry: '" << entry.representation () << "'"; - } - - return path_match (entry, pattern, *start); - } - void filesystem_functions (function_map& m) { @@ -149,70 +107,5 @@ namespace build2 return path_search (convert<path> (move (pattern)), convert<dir_path> (move (start))); }; - - // path_match - // - // Match a filesystem entry name against a name pattern (both are strings), - // or a filesystem entry path against a path pattern. For the latter case - // the start directory may also be required (see below). The semantics of - // the pattern and name/entry arguments is determined according to the - // following rules: - // - // - The arguments must be of the string or path types, or be untyped. - // - // - If one of the arguments is typed, then the other one must be of the - // same type or be untyped. In the later case, an untyped argument is - // converted to the type of the other argument. - // - // - If both arguments are untyped and the start directory is specified, - // then the arguments are converted to the path type. - // - // - If both arguments are untyped and the start directory is not - // specified, then, if one of the arguments is syntactically a path (the - // value contains a directory separator), convert them to the path type, - // otherwise to the string type (match as names). - // - // If pattern and entry paths are both either absolute or relative and - // non-empty, and the first pattern component is not a self-matching - // wildcard (doesn't contain ***), then the start directory is not - // required, and is ignored if specified. Otherwise, the start directory - // must be specified and be an absolute path. - // - // Name matching. - // - f["path_match"] = [](string name, string pattern) - { - return path_match (name, pattern); - }; - - // Path matching. - // - f["path_match"] = [](path ent, path pat, optional<dir_path> start) - { - return path_match (ent, pat, start); - }; - - // The semantics depends on the presence of the start directory or the - // first two argument syntactic representation. - // - f["path_match"] = [](names ent, names pat, optional<names> start) - { - auto path_arg = [] (const names& a) -> bool - { - return a.size () == 1 && - (a[0].directory () || - a[0].value.find_first_of (path::traits_type::directory_separators) != - string::npos); - }; - - return start || path_arg (pat) || path_arg (ent) - ? path_match (convert<path> (move (ent)), // Match as paths. - convert<path> (move (pat)), - start - ? convert<dir_path> (move (*start)) - : optional<dir_path> ()) - : path_match (convert<string> (move (ent)), // Match as strings. - convert<string> (move (pat))); - }; } } diff --git a/libbuild2/functions-path.cxx b/libbuild2/functions-path.cxx index 03f9be3..7188b62 100644 --- a/libbuild2/functions-path.cxx +++ b/libbuild2/functions-path.cxx @@ -2,6 +2,8 @@ // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include <libbutl/path-pattern.mxx> + #include <libbuild2/function.hxx> #include <libbuild2/variable.hxx> @@ -95,6 +97,47 @@ namespace build2 } } + using butl::path_match; + + // Return true if a path matches the pattern. See path_match() overloads + // (below) for details. + // + static bool + path_match (const path& entry, + const path& pattern, + const optional<dir_path>& start) + { + // If pattern and entry are both either absolute or relative and + // non-empty, and the first pattern component is not a self-matching + // wildcard, then ignore the start directory. + // + bool rel (pattern.relative () == entry.relative () && + !pattern.empty () && !entry.empty ()); + + if (rel && !path_pattern_self_matching (pattern)) + return path_match (entry, pattern); + + // The start directory must be specified and be absolute. + // + if (!start || start->relative ()) + { + diag_record dr (fail); + + // Print paths "as is". + // + if (!start) + dr << "start directory is not specified"; + else + dr << "start directory path '" << start->representation () + << "' is relative"; + + dr << info << "pattern: '" << pattern.representation () << "'" + << info << "entry: '" << entry.representation () << "'"; + } + + return path_match (entry, pattern, *start); + } + void path_functions (function_map& m) { @@ -341,6 +384,89 @@ namespace build2 return extension (convert<path> (move (ns))); }; + // $path.match(<val>, <pat> [, <start>]) + // + // Match a filesystem entry name against a name pattern (both are strings), + // or a filesystem entry path against a path pattern. For the latter case + // the start directory may also be required (see below). The semantics of + // the pattern and name/entry arguments is determined according to the + // following rules: + // + // - The arguments must be of the string or path types, or be untyped. + // + // - If one of the arguments is typed, then the other one must be of the + // same type or be untyped. In the later case, an untyped argument is + // converted to the type of the other argument. + // + // - If both arguments are untyped and the start directory is specified, + // then the arguments are converted to the path type. + // + // - If both arguments are untyped and the start directory is not + // specified, then, if one of the arguments is syntactically a path (the + // value contains a directory separator), convert them to the path type, + // otherwise to the string type (match as names). + // + // If pattern and entry paths are both either absolute or relative and + // non-empty, and the first pattern component is not a self-matching + // wildcard (doesn't contain ***), then the start directory is not + // required, and is ignored if specified. Otherwise, the start directory + // must be specified and be an absolute path. + // + // Name matching. + // + f[".match"] = [](string name, string pattern) + { + return path_match (name, pattern); + }; + + // Path matching. + // + f["match"] = [](path ent, path pat, optional<dir_path> start) + { + return path_match (ent, pat, start); + }; + + f["match"] = [](path ent, names pat, optional<names> start) + { + return path_match (ent, + convert<path> (move (pat)), + start + ? convert<dir_path> (move (*start)) + : optional<dir_path> ()); + }; + + f["match"] = [](names ent, path pat, optional<names> start) + { + return path_match (convert<path> (move (ent)), + pat, + start + ? convert<dir_path> (move (*start)) + : optional<dir_path> ()); + }; + + // The semantics depends on the presence of the start directory or the + // first two argument syntactic representation. + // + f[".match"] = [](names ent, names pat, optional<names> start) + { + auto path_arg = [] (const names& a) -> bool + { + return a.size () == 1 && + (a[0].directory () || + a[0].value.find_first_of (path::traits_type::directory_separators) != + string::npos); + }; + + return start || path_arg (pat) || path_arg (ent) + ? path_match (convert<path> (move (ent)), // Match as paths. + convert<path> (move (pat)), + start + ? convert<dir_path> (move (*start)) + : optional<dir_path> ()) + : path_match (convert<string> (move (ent)), // Match as strings. + convert<string> (move (pat))); + }; + // Path-specific overloads from builtins. // function_family b (m, "builtin", &path_thunk); diff --git a/libbuild2/functions-project-name.cxx b/libbuild2/functions-project-name.cxx index f70a1e7..6058742 100644 --- a/libbuild2/functions-project-name.cxx +++ b/libbuild2/functions-project-name.cxx @@ -14,7 +14,7 @@ namespace build2 { function_family f (m, "project_name"); - f["string"] = [](project_name p) {return move (p).string ();}; + f["string"] = [](project_name p) {return move (p).string ();}; f["base"] = [](project_name p, optional<string> ext) { diff --git a/tests/function/filesystem/testscript b/tests/function/filesystem/testscript index ecda10e..41d4c59 100644 --- a/tests/function/filesystem/testscript +++ b/tests/function/filesystem/testscript @@ -71,82 +71,3 @@ EOE } } - -: path-match -: -{ - : string - : - : Test overloads for at least one of the first two arguments being of the - : string type. - : - { - : string-string - : - $* <'print $path_match([string] "b", [string] "b*")' >'true' - - : untyped-string - : - $* <'print $path_match("b", [string] "b*")' >'true' - - : string-untyped - : - $* <'print $path_match([string] "b", "b*")' >'true' - - : path-string - : - $* <'print $path_match([path] "b", [string] "b*")' >'true' - } - - : path - : - : Test overloads for at least one of the first two arguments being of the - : path type. - : - { - : path-path - : - $* <'print $path_match([path] "a/b", [path] "b**")' >'true' - - : path-path-untyped - : - $* <'print $path_match([path] "a/b", [path] "b**", "$src_base")' >'true' - - : untyped-path - : - $* <'print $path_match("a/b", [path] "b**")' >'true' - - : untyped-path-dir - : - $* <'print $path_match("a/b", [path] "b**", $src_base)' >'true' - - : path-untyped - : - $* <'print $path_match([path] "a/b", "b**")' >'true' - } - - : untyped - : - : Test overloads for the first two arguments being untyped. - : - { - : converted-to-strings - : - $* <'print $path_match("b", "b**")' >'true' - - : converted-to-paths-due-to - { - : pattern - : - $* <'print $path_match("a/b/", "b**/")' >'true' - - : entry - : - $* <'print $path_match("a/b", "b**")' >'true' - - : start-dir - : - $* <'print $path_match("", "s***/", "$src_base")' >'true' - } - } -} diff --git a/tests/function/path/testscript b/tests/function/path/testscript index fb01e37..8059f05 100644 --- a/tests/function/path/testscript +++ b/tests/function/path/testscript @@ -107,3 +107,82 @@ p = ($cxx.target.class != 'windows' ? /../foo : 'c:/../foo'); $* <"\$path.normalize\('$p')" 2>>"EOE" != 0 error: invalid path: '$p' EOE + +: path-match +: +{ + : string + : + : Test overloads for at least one of the first two arguments being of the + : string type. + : + { + : string-string + : + $* <'print $path.match([string] "b", [string] "b*")' >'true' + + : untyped-string + : + $* <'print $path.match("b", [string] "b*")' >'true' + + : string-untyped + : + $* <'print $path.match([string] "b", "b*")' >'true' + + : path-string + : + $* <'print $match([path] "b", [string] "b*")' >'true' + } + + : path + : + : Test overloads for at least one of the first two arguments being of the + : path type. + : + { + : path-path + : + $* <'print $match([path] "a/b", [path] "b**")' >'true' + + : path-untyped-untyped + : + $* <'print $match([path] "a/b", "b**", "$src_base")' >'true' + + : untyped-path + : + $* <'print $match("a/b", [path] "b**")' >'true' + + : untyped-path-dir + : + $* <'print $match("a/b", [path] "b**", $src_base)' >'true' + + : path-untyped + : + $* <'print $match([path] "a/b", "b**")' >'true' + } + + : untyped + : + : Test overloads for the first two arguments being untyped. + : + { + : converted-to-strings + : + $* <'print $path.match("b", "b**")' >'true' + + : converted-to-paths-due-to + { + : pattern + : + $* <'print $path.match("a/b/", "b**/")' >'true' + + : entry + : + $* <'print $path.match("a/b", "b**")' >'true' + + : start-dir + : + $* <'print $path.match("", "s***/", "$src_base")' >'true' + } + } +} |