return message;
}
-std::string
-argv_to_string(const char* const* argv,
- const std::string& prefix,
- bool escape_backslashes)
-{
- std::string result;
- size_t i = 0;
- const char* arg = prefix.empty() ? argv[i++] : prefix.c_str();
-
- do {
- int bs = 0;
- result += '"';
- for (size_t j = 0; arg[j]; ++j) {
- switch (arg[j]) {
- case '\\':
- if (!escape_backslashes) {
- ++bs;
- break;
- }
- [[fallthrough]];
-
- case '"':
- bs = (bs << 1) + 1;
- [[fallthrough]];
-
- default:
- while (bs > 0) {
- result += '\\';
- --bs;
- }
- result += arg[j];
- }
- }
- bs <<= 1;
- while (bs > 0) {
- result += '\\';
- --bs;
- }
- result += "\" ";
- } while ((arg = argv[i++]));
-
- result.resize(result.length() - 1);
- return result;
-}
-
} // namespace Win32Util
namespace Win32Util {
-// Recreate a Windows command line string based on `argv`. If `prefix` is
-// non-empty, add it as the first argument. If `escape_backslashes` is true,
-// emit an additional backslash for each backslash that is not preceding '"' and
-// is not at the end of `argv[i]` either.
-std::string argv_to_string(const char* const* argv,
- const std::string& prefix,
- bool escape_backslashes = false);
-
// Return the error message corresponding to `error_code`.
std::string error_message(DWORD error_code);
}
}
- std::string args = Win32Util::argv_to_string(argv, sh);
+ std::string args = util::format_argv_as_win32_command_string(argv, sh);
std::string full_path = util::add_exe_suffix(path);
fs::path tmp_file_path;
if (args.length() > 8192) {
auto tmp_file = util::value_or_throw<core::Fatal>(
util::TemporaryFile::create(FMT("{}/cmd_args", temp_dir)));
- args = Win32Util::argv_to_string(argv + 1, sh, true);
+ args = util::format_argv_as_win32_command_string(argv + 1, sh, true);
util::write_fd(*tmp_file.fd, args.data(), args.length());
args = FMT(R"("{}" "@{}")", full_path, tmp_file.path);
tmp_file_path = tmp_file.path;
if (using_cmd_exe) {
win32args = adjusted_command; // quoted
} else {
- win32args = Win32Util::argv_to_string(argv.data(), sh);
+ win32args = util::format_argv_as_win32_command_string(argv.data(), sh);
}
BOOL ret = CreateProcess(path.c_str(),
const_cast<char*>(win32args.c_str()),
namespace util {
+std::string
+format_argv_as_win32_command_string(const char* const* argv,
+ const std::string& prefix,
+ bool escape_backslashes)
+{
+ std::string result;
+ size_t i = 0;
+ const char* arg = prefix.empty() ? argv[i++] : prefix.c_str();
+
+ do {
+ int bs = 0;
+ result += '"';
+ for (size_t j = 0; arg[j]; ++j) {
+ switch (arg[j]) {
+ case '\\':
+ if (!escape_backslashes) {
+ ++bs;
+ break;
+ }
+ [[fallthrough]];
+
+ case '"':
+ bs = (bs << 1) + 1;
+ [[fallthrough]];
+
+ default:
+ while (bs > 0) {
+ result += '\\';
+ --bs;
+ }
+ result += arg[j];
+ }
+ }
+ bs <<= 1;
+ while (bs > 0) {
+ result += '\\';
+ --bs;
+ }
+ result += "\" ";
+ } while ((arg = argv[i++]));
+
+ result.resize(result.length() - 1);
+ return result;
+}
+
std::string
format_argv_for_logging(const char* const* argv)
{
// Return true if `suffix` is a suffix of `string`.
bool ends_with(std::string_view string, std::string_view suffix);
+// Recreate a Windows command line string based on `argv`. If `prefix` is
+// non-empty, add it as the first argument. If `escape_backslashes` is true,
+// emit an additional backslash for each backslash that is not preceding '"' and
+// is not at the end of `argv[i]` either.
+std::string
+format_argv_as_win32_command_string(const char* const* argv,
+ const std::string& prefix,
+ bool escape_backslashes = false);
+
// Format `argv` as a simple string for logging purposes. That is, the result is
// not intended to be easily machine parsable. `argv` must be terminated by a
// nullptr.
endif()
if(WIN32)
- list(APPEND source_files test_bsdmkstemp.cpp test_Win32Util.cpp)
+ list(APPEND source_files test_bsdmkstemp.cpp)
endif()
file(GLOB headers *.hpp)
+++ /dev/null
-// Copyright (C) 2020 Joel Rosdahl and other contributors
-//
-// See doc/AUTHORS.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include "../src/Win32Util.hpp"
-#include "TestUtil.hpp"
-
-#include "third_party/doctest.h"
-
-#include <iostream>
-
-TEST_SUITE_BEGIN("Win32Util");
-
-TEST_CASE("Win32Util::argv_to_string")
-{
- {
- const char* const argv[] = {"a", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "") == R"("a")");
- }
- {
- const char* const argv[] = {"a", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "p") == R"("p" "a")");
- }
- {
- const char* const argv[] = {"a", "b c", "\"d\"", "'e'", "\\\"h", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "")
- == R"("a" "b c" "\"d\"" "'e'" "\\\"h")");
- }
- {
- const char* const argv[] = {"a\\b\\c", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "") == R"("a\b\c")");
- }
- {
- const char* const argv[] = {"a\\b\\c", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "", true) == R"("a\\b\\c")");
- }
- {
- const char* const argv[] = {R"(a\b \"c\" \)", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "") == R"("a\b \\\"c\\\" \\")");
- }
- {
- const char* const argv[] = {R"(a\b \"c\" \)", nullptr};
- CHECK(Win32Util::argv_to_string(argv, "", true)
- == R"("a\\b \\\"c\\\" \\")");
- }
-}
-
-TEST_SUITE_END();
TEST_SUITE_BEGIN("util");
+TEST_CASE("util::format_argv_as_win32_command_string")
+{
+ {
+ const char* const argv[] = {"a", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "") == R"("a")");
+ }
+ {
+ const char* const argv[] = {"a", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "p") == R"("p" "a")");
+ }
+ {
+ const char* const argv[] = {"a", "b c", "\"d\"", "'e'", "\\\"h", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "")
+ == R"("a" "b c" "\"d\"" "'e'" "\\\"h")");
+ }
+ {
+ const char* const argv[] = {"a\\b\\c", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "") == R"("a\b\c")");
+ }
+ {
+ const char* const argv[] = {"a\\b\\c", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "", true)
+ == R"("a\\b\\c")");
+ }
+ {
+ const char* const argv[] = {R"(a\b \"c\" \)", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "")
+ == R"("a\b \\\"c\\\" \\")");
+ }
+ {
+ const char* const argv[] = {R"(a\b \"c\" \)", nullptr};
+ CHECK(util::format_argv_as_win32_command_string(argv, "", true)
+ == R"("a\\b \\\"c\\\" \\")");
+ }
+}
+
TEST_CASE("util::format_argv_for_logging")
{
SUBCASE("nullptr")