return message;
}
+std::string
+argv_to_string(const char* const* argv, const std::string& prefix)
+{
+ 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 '\\':
+ ++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.
+std::string argv_to_string(const char* const* argv, const std::string& prefix);
+
+// Return the error message corresponding to `error_code`.
std::string error_message(DWORD error_code);
} // namespace Win32Util
return win32execute(argv[0], argv, 1, fd_out.release(), fd_err.release());
}
-// Re-create a win32 command line string based on **argv.
-// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
-char*
-win32argvtos(const char* prefix, const char* const* argv, int* length)
-{
- int i = 0;
- int k = 0;
- const char* arg = prefix ? prefix : argv[i++];
- do {
- int bs = 0;
- for (int j = 0; arg[j]; j++) {
- switch (arg[j]) {
- case '\\':
- bs++;
- break;
- case '"':
- bs = (bs << 1) + 1;
- // Fallthrough.
- default:
- k += bs + 1;
- bs = 0;
- }
- }
- k += (bs << 1) + 3;
- } while ((arg = argv[i++]));
-
- char* ptr = static_cast<char*>(malloc(k + 1));
- char* str = ptr;
- if (!str) {
- *length = 0;
- return NULL;
- }
-
- i = 0;
- arg = prefix ? prefix : argv[i++];
- do {
- int bs = 0;
- *ptr++ = '"';
- for (int j = 0; arg[j]; j++) {
- switch (arg[j]) {
- case '\\':
- bs++;
- break;
- // Fallthrough.
- case '"':
- bs = (bs << 1) + 1;
- // Fallthrough.
- default:
- while (bs && bs--) {
- *ptr++ = '\\';
- }
- *ptr++ = arg[j];
- }
- }
- bs <<= 1;
- while (bs && bs--) {
- *ptr++ = '\\';
- }
- *ptr++ = '"';
- *ptr++ = ' ';
- } while ((arg = argv[i++]));
- ptr[-1] = '\0';
-
- *length = ptr - str - 1;
- return str;
-}
-
std::string
-win32getshell(const char* path)
+win32getshell(const std::string& path)
{
const char* path_env = getenv("PATH");
std::string sh;
}
}
- int length;
- const char* prefix = sh.empty() ? nullptr : sh.c_str();
- char* args = win32argvtos(prefix, argv, &length);
+ std::string args = Win32Util::argv_to_string(argv, sh);
const char* ext = strrchr(path, '.');
char full_path_win_ext[MAX_PATH] = {0};
add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
BOOL ret = FALSE;
- if (length > 8192) {
+ if (args.length() > 8192) {
TemporaryFile tmp_file(path);
- Util::write_fd(*tmp_file.fd, args, length);
+ Util::write_fd(*tmp_file.fd, args.data(), args.length());
std::string atfile = fmt::format("\"@{}\"", tmp_file.path);
ret = CreateProcess(nullptr,
const_cast<char*>(atfile.c_str()),
}
if (!ret) {
ret = CreateProcess(full_path_win_ext,
- args,
+ const_cast<char*>(args.c_str()),
nullptr,
nullptr,
1,
close(fd_stdout);
close(fd_stderr);
}
- free(args);
if (ret == 0) {
DWORD error = GetLastError();
cc_log("failed to execute %s: %s (%lu)",
const std::string& path);
#ifdef _WIN32
-char* win32argvtos(const char* prefix, const char* const* argv, int* length);
-std::string win32getshell(const char* path);
+std::string win32getshell(const std::string& path);
int win32execute(const char* path,
const char* const* argv,
int doreturn,
# include "InodeCache.hpp"
#endif
+#ifdef _WIN32
+# include "Win32Util.hpp"
+#endif
+
#include "third_party/xxhash.h"
// With older GCC (libgcc), __builtin_cpu_supports("avx2) returns true if AVX2
if (path.empty()) {
path = args[0];
}
- std::string sh = win32getshell(path.c_str());
+ std::string sh = win32getshell(path);
if (!sh.empty()) {
path = sh;
}
if (using_cmd_exe) {
win32args = command; // quoted
} else {
- int length;
- const char* prefix = sh.empty() ? nullptr : sh.c_str();
- char* args = win32argvtos(prefix, argv.data(), &length);
- win32args = args;
- free(args);
+ win32args = Win32Util::argv_to_string(argv.data(), sh);
}
BOOL ret = CreateProcess(path.c_str(),
const_cast<char*>(win32args.c_str()),
list(APPEND source_files test_InodeCache.cpp)
endif()
+if(WIN32)
+ list(APPEND source_files test_Win32Util.cpp)
+endif()
+
add_executable(unittest ${source_files})
target_link_libraries(
--- /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"
+
+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")");
+ }
+}
+
+TEST_SUITE_END();