windows: remove deprecated codecvt via UTF-8 narrow APIs

Drop wstring_convert/codecvt and the
related wide process calls (_wsystem, _wexecvp, CreateProcessW)
in favor of ::system, _execvp, and CreateProcess.
This commit is contained in:
kevkevinpal
2026-07-11 10:22:19 -04:00
parent b388674acf
commit 6b6d77cc84
5 changed files with 32 additions and 46 deletions

View File

@@ -471,7 +471,6 @@ if(MSVC)
try_append_cxx_flags("/wd4805" TARGET warn_interface SKIP_LINK)
target_compile_definitions(warn_interface INTERFACE
_CRT_SECURE_NO_WARNINGS
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
)
else()
try_append_cxx_flags("-Wall" TARGET warn_interface SKIP_LINK)

View File

@@ -24,8 +24,7 @@ endif()
# Even though ::system is part of the standard library, we still check
# for it, to support building targets that don't have it, such as iOS.
check_cxx_symbol_exists(std::system "cstdlib" HAVE_STD_SYSTEM)
check_cxx_symbol_exists(::_wsystem "stdlib.h" HAVE__WSYSTEM)
if(HAVE_STD_SYSTEM OR HAVE__WSYSTEM)
if(HAVE_STD_SYSTEM)
set(HAVE_SYSTEM 1)
endif()

View File

@@ -14,7 +14,6 @@
#ifdef WIN32
#include <compat/compat.h>
#include <util/check.h>
#include <codecvt>
#include <windows.h>
#else
#include <sys/stat.h>
@@ -49,11 +48,7 @@ std::string ShellEscape(const std::string& arg)
void runCommand(const std::string& strCommand)
{
if (strCommand.empty()) return;
#ifndef WIN32
int nErr = ::system(strCommand.c_str());
#else
int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
#endif
if (nErr) {
LogWarning("runCommand error: system(%s) returned %d", strCommand, nErr);
}

View File

@@ -14,8 +14,6 @@
#include <system_error>
#ifdef WIN32
#include <codecvt>
#include <locale>
#include <process.h>
#include <windows.h>
#else
@@ -28,17 +26,16 @@ int ExecVp(const char* file, char* const argv[])
#ifndef WIN32
return execvp(file, argv);
#else
std::vector<std::wstring> escaped_args;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::vector<std::string> escaped_args;
for (char* const* arg_ptr{argv}; *arg_ptr; ++arg_ptr) {
subprocess::util::quote_argument(converter.from_bytes(*arg_ptr), escaped_args.emplace_back(), false);
subprocess::util::quote_argument(std::string{*arg_ptr}, escaped_args.emplace_back(), /*force=*/false);
}
std::vector<const wchar_t*> new_argv;
std::vector<const char*> new_argv;
new_argv.reserve(escaped_args.size() + 1);
for (const auto& s : escaped_args) new_argv.push_back(s.c_str());
new_argv.push_back(nullptr);
return _wexecvp(converter.from_bytes(file).c_str(), new_argv.data());
return _execvp(file, new_argv.data());
#endif
}

View File

@@ -48,22 +48,16 @@ Documentation for C++ subprocessing library.
#include <future>
#include <initializer_list>
#include <iostream>
#include <locale>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#ifdef WIN32
#include <codecvt>
#endif
extern "C" {
#ifdef WIN32
#include <windows.h>
#include <io.h>
#include <cwchar>
#else
#include <sys/wait.h>
#include <unistd.h>
@@ -168,9 +162,12 @@ public:
namespace util
{
#ifdef WIN32
inline void quote_argument(const std::wstring &argument, std::wstring &command_line,
inline void quote_argument(const std::string &argument, std::string &command_line,
bool force)
{
constexpr char quote = '"';
constexpr char backslash = '\\';
//
// Unless we're told otherwise, don't quote unless we actually
// need to do so --- hopefully avoid problems if programs won't
@@ -178,16 +175,16 @@ namespace util
//
if (force == false && argument.empty() == false &&
argument.find_first_of(L" \t\n\v") == argument.npos) {
argument.find_first_of(" \t\n\v") == argument.npos) {
command_line.append(argument);
}
else {
command_line.push_back(L'"');
command_line.push_back(quote);
for (auto it = argument.begin();; ++it) {
unsigned number_backslashes = 0;
while (it != argument.end() && *it == L'\\') {
while (it != argument.end() && *it == backslash) {
++it;
++number_backslashes;
}
@@ -200,17 +197,17 @@ namespace util
// as a metacharacter.
//
command_line.append(number_backslashes * 2, L'\\');
command_line.append(number_backslashes * 2, backslash);
break;
}
else if (*it == L'"') {
else if (*it == quote) {
//
// Escape all backslashes and the following
// double quotation mark.
//
command_line.append(number_backslashes * 2 + 1, L'\\');
command_line.append(number_backslashes * 2 + 1, backslash);
command_line.push_back(*it);
}
else {
@@ -219,12 +216,12 @@ namespace util
// Backslashes aren't special here.
//
command_line.append(number_backslashes, L'\\');
command_line.append(number_backslashes, backslash);
command_line.push_back(*it);
}
}
command_line.push_back(L'"');
command_line.push_back(quote);
}
}
@@ -1085,37 +1082,36 @@ inline void Popen::execute_process() noexcept(false)
}
this->exe_name_ = vargs_[0];
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring argument;
std::wstring command_line;
std::string argument;
std::string command_line;
bool first_arg = true;
for (auto arg : this->vargs_) {
if (!first_arg) {
command_line += L" ";
command_line += " ";
} else {
first_arg = false;
}
argument = converter.from_bytes(arg);
util::quote_argument(argument, command_line, false);
argument = arg;
util::quote_argument(argument, command_line, /*force=*/false);
}
// CreateProcessW can modify szCmdLine so we allocate needed memory
wchar_t *szCmdline = new wchar_t[command_line.size() + 1];
wcscpy_s(szCmdline, command_line.size() + 1, command_line.c_str());
// CreateProcessA can modify szCmdLine so we allocate needed memory
char *szCmdline = new char[command_line.size() + 1];
strcpy_s(szCmdline, command_line.size() + 1, command_line.c_str());
PROCESS_INFORMATION piProcInfo;
STARTUPINFOW siStartInfo;
STARTUPINFOA siStartInfo;
BOOL bSuccess = FALSE;
DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW;
DWORD creation_flags = CREATE_NO_WINDOW;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFOW structure.
// Set up members of the STARTUPINFOA structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFOW));
siStartInfo.cb = sizeof(STARTUPINFOW);
ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA));
siStartInfo.cb = sizeof(STARTUPINFOA);
siStartInfo.hStdError = this->stream_.g_hChildStd_ERR_Wr;
siStartInfo.hStdOutput = this->stream_.g_hChildStd_OUT_Wr;
@@ -1124,7 +1120,7 @@ inline void Popen::execute_process() noexcept(false)
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcessW(NULL,
bSuccess = CreateProcessA(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
@@ -1132,7 +1128,7 @@ inline void Popen::execute_process() noexcept(false)
creation_flags, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFOW pointer
&siStartInfo, // STARTUPINFOA pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.