aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-09-19 17:43:02 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-09-27 18:29:19 +0300
commitc595aac0142436f64ada4f5412b821bfcc6db008 (patch)
treef0b20b290a52cba6f01cb07df7b9734941fad050
parent28d1791e2dc66cc610468deb29ea030e28d0793c (diff)
Adapt to bracket expressions in wildcard patterns
-rw-r--r--libbuild2/cc/link-rule.cxx2
-rw-r--r--libbuild2/functions-filesystem.cxx5
-rw-r--r--libbuild2/parser.cxx82
-rw-r--r--libbuild2/test/script/runner.cxx5
-rw-r--r--tests/name/cross.testscript2
5 files changed, 54 insertions, 42 deletions
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index 2eeebda..14e5b94 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -8,7 +8,7 @@
#include <cstdlib> // exit()
#include <cstring> // strlen()
-#include <libbutl/filesystem.mxx> // file_exists()
+#include <libbutl/filesystem.mxx> // file_exists(), path_search()
#include <libbuild2/depdb.hxx>
#include <libbuild2/scope.hxx>
diff --git a/libbuild2/functions-filesystem.cxx b/libbuild2/functions-filesystem.cxx
index 2fcd305..d0861ba 100644
--- a/libbuild2/functions-filesystem.cxx
+++ b/libbuild2/functions-filesystem.cxx
@@ -93,10 +93,7 @@ namespace build2
bool rel (pattern.relative () == entry.relative () &&
!pattern.empty () && !entry.empty ());
- bool self (!pattern.empty () &&
- (*pattern.begin ()).find ("***") != string::npos);
-
- if (rel && !self)
+ if (rel && !path_pattern_self_matching (pattern))
return path_match (pattern, entry);
// The start directory must be specified and be absolute.
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index a7e65dd..ffe64fb 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -7,7 +7,7 @@
#include <sstream>
#include <iostream> // cout
-#include <libbutl/filesystem.mxx> // path_search(), path_match()
+#include <libbutl/filesystem.mxx> // path_{search,match,pattern}()
#include <libbuild2/dump.hxx>
#include <libbuild2/file.hxx>
@@ -21,6 +21,7 @@
#include <libbuild2/prerequisite.hxx>
using namespace std;
+using namespace butl;
namespace build2
{
@@ -275,14 +276,6 @@ namespace build2
return make_pair (move (lhs), move (t));
}
- // Test if a string is a wildcard pattern.
- //
- static inline bool
- pattern (const string& s)
- {
- return s.find_first_of ("*?") != string::npos;
- };
-
bool parser::
parse_clause (token& t, type& tt, bool one)
{
@@ -553,7 +546,7 @@ namespace build2
// Figure out if this is a target or a target type/pattern (yeah,
// it can be a mixture).
//
- if (pattern (n.value))
+ if (path_pattern (n.value))
{
if (n.pair)
fail (nloc) << "out-qualified target type/pattern";
@@ -772,7 +765,7 @@ namespace build2
// Make sure not a pattern (see also the target case above and scope
// below).
//
- if (pattern (d.string ()))
+ if (path_pattern (d))
fail (nloc) << "pattern in directory " << d.representation ();
if (tt != type::lsbrace)
@@ -820,7 +813,7 @@ namespace build2
// Make sure not a pattern (see also the target and directory cases
// above).
//
- if (pattern (d.string ()))
+ if (path_pattern (d))
fail (nloc) << "pattern in directory " << d.representation ();
next (t, tt); // Newline.
@@ -1004,7 +997,7 @@ namespace build2
// Make sure none of our targets are patterns (maybe we will allow
// quoting later).
//
- if (pattern (n.value))
+ if (path_pattern (n.value))
fail (tloc) << "pattern in target " << n;
enter_target tg (*this,
@@ -3350,7 +3343,7 @@ namespace build2
auto match = [&dir, sp] (const path& pattern, const name& n) -> bool
{
const path& p (dir ? path_cast<path> (n.dir) : path (n.value));
- return butl::path_match (pattern, p, *sp);
+ return path_match (pattern, p, *sp);
};
// Append name/extension to result according to dir. Store an indication
@@ -3386,6 +3379,8 @@ namespace build2
append (move (m), move (e), a);
};
+ // May throw invalid_path.
+ //
auto include_pattern =
[&r, &append, &include_match, sp, &l, this] (string&& p,
optional<string>&& e,
@@ -3396,12 +3391,7 @@ namespace build2
// can skip checking for duplicated. This should help quite a bit in the
// common cases where we have a pattern plus maybe a few exclusions.
//
- bool unique (false);
- if (r.empty ())
- {
- size_t i (p.find ("**"));
- unique = (i == string::npos || p.find ("**", i + 2) == string::npos);
- }
+ bool unique (r.empty () && path_pattern_recursive (path (p)) <= 1);
function<void (string&&, optional<string>&&)> appf;
if (unique)
@@ -3443,7 +3433,7 @@ namespace build2
try
{
- butl::path_search (path (move (p)), process, *sp);
+ path_search (path (move (p)), process, *sp);
}
catch (const system_error& e)
{
@@ -3465,13 +3455,11 @@ namespace build2
r.erase (i);
};
- auto exclude_pattern = [&r, &match] (string&& p)
+ auto exclude_pattern = [&r, &match] (const path& p)
{
- path pattern (move (p));
-
for (auto i (r.begin ()); i != r.end (); )
{
- if (match (pattern, *i))
+ if (match (p, *i))
i = r.erase (i);
else
++i;
@@ -3576,10 +3564,12 @@ namespace build2
include_pattern (move (v), move (e), a);
else
{
- if (v.find_first_of ("*?") != string::npos)
- exclude_pattern (move (v));
+ path p (move (v));
+
+ if (path_pattern (p))
+ exclude_pattern (p);
else
- exclude_match (move (v));
+ exclude_match (move (p).representation ()); // Reuse the buffer.
}
}
catch (const invalid_path& e)
@@ -4195,6 +4185,7 @@ namespace build2
continue;
string val (move (t.value));
+ const location loc (get_location (t));
bool quoted (t.qtype != quote_type::unquoted);
// Should we accumulate? If the buffer is not empty, then we continue
@@ -4266,11 +4257,11 @@ namespace build2
if (quoted) // See above.
break;
- fail (t) << "invalid project name '" << proj << "': " << e;
+ fail (loc) << "invalid project name '" << proj << "': " << e;
}
if (pp)
- fail (t) << "nested project name " << *p1;
+ fail (loc) << "nested project name " << *p1;
pp1 = &p1;
@@ -4311,7 +4302,7 @@ namespace build2
}
if (p != n && tp != nullptr && !pinc)
- fail (t) << "nested type name " << val;
+ fail (loc) << "nested type name " << val;
dir_path d1;
const dir_path* dp1 (dp);
@@ -4347,7 +4338,7 @@ namespace build2
}
catch (const invalid_path& e)
{
- fail (t) << "invalid path '" << e.path << "'";
+ fail (loc) << "invalid path '" << e.path << "'";
}
count = parse_names_trailer (
@@ -4374,12 +4365,35 @@ namespace build2
// It should either contain a wildcard character or, in a curly
// context, start with unquoted '+'.
//
+ // Note that in the general case we need to convert it to a path prior
+ // to testing for being a pattern (think of b[a/r] that is not a
+ // pattern). If the conversion fails then this is not a path pattern.
+ //
+ auto pattern = [&val, &loc, this] ()
+ {
+ // Let's optimize it a bit for the common cases.
+ //
+ if (val.find_first_of ("*?[") == string::npos)
+ return false;
+
+ if (path::traits_type::find_separator (val) == string::npos)
+ return path_pattern (val);
+
+ try
+ {
+ return path_pattern (path (val));
+ }
+ catch (const invalid_path& e)
+ {
+ fail (loc) << "invalid path '" << e.path << "'" << endf;
+ }
+ };
+
if (pmode != pattern_mode::ignore &&
!*pp1 && // Cannot be project-qualified.
!quoted && // Cannot be quoted.
((dp != nullptr && dp->absolute ()) || pbase_ != nullptr) &&
- ((val.find_first_of ("*?") != string::npos) ||
- (curly && val[0] == '+')))
+ (pattern () || (curly && val[0] == '+')))
{
// Resolve the target if there is one. If we fail, then this is not
// a pattern.
diff --git a/libbuild2/test/script/runner.cxx b/libbuild2/test/script/runner.cxx
index 554edd0..56e29b1 100644
--- a/libbuild2/test/script/runner.cxx
+++ b/libbuild2/test/script/runner.cxx
@@ -8,7 +8,8 @@
#include <libbutl/regex.mxx>
#include <libbutl/builtin.mxx>
-#include <libbutl/fdstream.mxx> // fdopen_mode, fdnull(), fddup()
+#include <libbutl/fdstream.mxx> // fdopen_mode, fdnull(), fddup()
+#include <libbutl/filesystem.mxx> // path_search(), path_pattern()
#include <libbuild2/variable.hxx>
#include <libbuild2/filesystem.hxx>
@@ -800,7 +801,7 @@ namespace build2
// Remove files or directories using wildcard.
//
- if (p.string ().find_first_of ("?*") != string::npos)
+ if (path_pattern (p))
{
bool removed (false);
diff --git a/tests/name/cross.testscript b/tests/name/cross.testscript
index 263a1d1..198f890 100644
--- a/tests/name/cross.testscript
+++ b/tests/name/cross.testscript
@@ -87,7 +87,7 @@ EOI
EOE
$* <'print {dir/foo}{fox{bar}}' 2>>EOE != 0
- <stdin>:1:20: error: nested type name fox
+ <stdin>:1:17: error: nested type name fox
EOE
}