diff options
author | jacobly0 <jacobly0@users.noreply.github.com> | 2022-05-11 14:45:40 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-11 20:45:40 +0200 |
commit | 1892e4d3e8ece73a922ac8fe883b4391227d2700 (patch) | |
tree | 3eb5a08119295a9409ec4a092c0b207427a47251 | |
parent | e15af963082f39a0595a7d623da2316b2fe3b282 (diff) | |
download | ccache-1892e4d3e8ece73a922ac8fe883b4391227d2700.tar.gz |
fix: Fix parsing of MSVC response files (#1071)
-rw-r--r-- | src/Args.cpp | 25 | ||||
-rw-r--r-- | src/Args.hpp | 10 | ||||
-rw-r--r-- | src/argprocessing.cpp | 5 | ||||
-rw-r--r-- | unittest/test_Args.cpp | 19 |
4 files changed, 49 insertions, 10 deletions
diff --git a/src/Args.cpp b/src/Args.cpp index 572911ec..6b4ec218 100644 --- a/src/Args.cpp +++ b/src/Args.cpp @@ -50,7 +50,7 @@ Args::from_string(const std::string& command) } optional<Args> -Args::from_atfile(const std::string& filename, bool ignore_backslash) +Args::from_atfile(const std::string& filename, AtFileFormat format) { std::string argtext; try { @@ -72,17 +72,28 @@ Args::from_atfile(const std::string& filename, bool ignore_backslash) while (true) { switch (*pos) { case '\\': - if (ignore_backslash) { - break; - } pos++; - if (*pos == '\0') { - continue; + switch (format) { + case AtFileFormat::QuoteAny_EscapeAny: + if (*pos == '\0') { + continue; + } + break; + case AtFileFormat::QuoteDouble_EscapeQuoteEscape: + if (*pos != '"' && *pos != '\\') { + pos--; + } + break; } break; - case '"': case '\'': + if (format == AtFileFormat::QuoteDouble_EscapeQuoteEscape) { + break; + } + // Fall through. + + case '"': if (quoting != '\0') { if (quoting == *pos) { quoting = '\0'; diff --git a/src/Args.hpp b/src/Args.hpp index 1a07ddc7..75aa331f 100644 --- a/src/Args.hpp +++ b/src/Args.hpp @@ -36,8 +36,14 @@ public: static Args from_argv(int argc, const char* const* argv); static Args from_string(const std::string& command); - static nonstd::optional<Args> from_atfile(const std::string& filename, - bool ignore_backslash = false); + + enum class AtFileFormat { + QuoteAny_EscapeAny, // '\'' and '"' quote, '\\' escapes any character + QuoteDouble_EscapeQuoteEscape, // '"' quotes, '\\' escapes only '"' and '\\' + }; + static nonstd::optional<Args> + from_atfile(const std::string& filename, + AtFileFormat format = AtFileFormat::QuoteAny_EscapeAny); Args& operator=(const Args& other) = default; Args& operator=(Args&& other) noexcept; diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index a0888b2b..679ee101 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -307,7 +307,10 @@ process_arg(const Context& ctx, ++argpath; } auto file_args = - Args::from_atfile(argpath, ctx.config.is_compiler_group_msvc()); + Args::from_atfile(argpath, + config.is_compiler_group_msvc() + ? Args::AtFileFormat::QuoteDouble_EscapeQuoteEscape + : Args::AtFileFormat::QuoteAny_EscapeAny); if (!file_args) { LOG("Couldn't read arg file {}", argpath); return Statistic::bad_compiler_arguments; diff --git a/unittest/test_Args.cpp b/unittest/test_Args.cpp index 391b71bd..ee9f8083 100644 --- a/unittest/test_Args.cpp +++ b/unittest/test_Args.cpp @@ -136,6 +136,25 @@ TEST_CASE("Args::from_atfile") CHECK(args[5] == "si'x\" th"); CHECK(args[6] == "seve\nth"); } + + SUBCASE("Only escape double quote and backslash in alternate format") + { + Util::write_file("at_file", "\"\\\"\\a\\ \\\\\\ \\b\\\"\"\\"); + args = *Args::from_atfile( + "at_file", Args::AtFileFormat::QuoteDouble_EscapeQuoteEscape); + CHECK(args.size() == 1); + CHECK(args[0] == "\"\\a\\ \\\\ \\b\"\\"); + } + + SUBCASE("Ignore single quote in alternate format") + { + Util::write_file("at_file", "'a b'"); + args = *Args::from_atfile( + "at_file", Args::AtFileFormat::QuoteDouble_EscapeQuoteEscape); + CHECK(args.size() == 2); + CHECK(args[0] == "'a"); + CHECK(args[1] == "b'"); + } } TEST_CASE("Args copy assignment operator") |