diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2021-12-06 11:16:22 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2021-12-06 11:16:22 +0200 |
commit | 9d860f46631c1567c62336fcb25cf7b8090855a4 (patch) | |
tree | 4df23a20e36671246718fc55af6fa5074d791467 /libbuild2/make-parser.cxx | |
parent | 2006284bfbda3416eb8348078fd98fa518d25c47 (diff) |
Recognize absolute Windows paths in make parser
Diffstat (limited to 'libbuild2/make-parser.cxx')
-rw-r--r-- | libbuild2/make-parser.cxx | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/libbuild2/make-parser.cxx b/libbuild2/make-parser.cxx index cab81d0..c6c077f 100644 --- a/libbuild2/make-parser.cxx +++ b/libbuild2/make-parser.cxx @@ -3,23 +3,21 @@ #include <libbuild2/make-parser.hxx> +#include <cstring> // strchr() + #include <libbuild2/diagnostics.hxx> namespace build2 { auto make_parser:: - next (const string& l, - size_t& p, - const location& ll, - bool strict) -> pair<type, path> + next (const string& l, size_t& p, const location& ll) -> pair<type, path> { assert (state != end); - pair<string, bool> r ( - next (l, p, !strict ? state == prereqs : optional<bool> ())); - type t (state == prereqs ? type::prereq : type::target); + pair<string, bool> r (next (l, p, t)); + // Deal with the end. // if (r.second) @@ -67,8 +65,15 @@ namespace build2 } } + // Note: backslash must be first. + // + // Note also that, at least in GNU make 4.1, `%` seems to be unescapable + // if appears in a target and literal if in a prerequisite. + // + static const char escapable[] = "\\ :#"; + pair<string, bool> make_parser:: - next (const string& l, size_t& p, optional<bool> prereq) + next (const string& l, size_t& p, type) { size_t n (l.size ()); @@ -87,9 +92,36 @@ namespace build2 // // @@ Can't we do better for the (common) case where nothing is escaped? // - for (char c, q (prereq && *prereq ? '\0' : ':'); - p != n && (c = l[p]) != ' ' && c != q; ) +#ifdef _WIN32 + size_t b (p); +#endif + + for (char c; p != n && (c = l[p]) != ' '; r += c) { + if (c == ':') + { +#ifdef _WIN32 + // See if this colon is part of the driver letter component in an + // absolute Windows path. + // + // Note that here we assume we are not dealing with directories (in + // which case c: would be a valid path) and thus an absolute path is + // at least 4 characters long (e.g., c:\x). + // + if (p == b + 1 && // Colon is second character. + alpha (l[b]) && // First is drive letter. + p + 2 < n && // At least two more characters after colon. + ((l[p + 1] == '/') || // Next is directory separator. + (l[p + 1] == '\\' && // But not part of a non-\\ escape sequence. + strchr (escapable + 1, l[p + 2]) == nullptr))) + { + ++p; + continue; + } +#endif + break; + } + // If we have another character, then handle the escapes. // if (++p != n) @@ -99,13 +131,8 @@ namespace build2 // This may or may not be an escape sequence depending on whether // what follows is "escapable". // - switch (c = l[p]) - { - case '\\': - case ' ': - case ':': ++p; break; - default: c = '\\'; // Restore. - } + if (strchr (escapable, l[p]) != nullptr) + c = l[p++]; } else if (c == '$') { @@ -122,8 +149,6 @@ namespace build2 --p; break; } - - r += c; } // Skip trailing spaces. |