summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjacobly0 <jacobly0@users.noreply.github.com>2022-05-11 14:45:40 -0400
committerGitHub <noreply@github.com>2022-05-11 20:45:40 +0200
commit1892e4d3e8ece73a922ac8fe883b4391227d2700 (patch)
tree3eb5a08119295a9409ec4a092c0b207427a47251
parente15af963082f39a0595a7d623da2316b2fe3b282 (diff)
downloadccache-1892e4d3e8ece73a922ac8fe883b4391227d2700.tar.gz
fix: Fix parsing of MSVC response files (#1071)
-rw-r--r--src/Args.cpp25
-rw-r--r--src/Args.hpp10
-rw-r--r--src/argprocessing.cpp5
-rw-r--r--unittest/test_Args.cpp19
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")