Merge pull request #2613 from oneandonlydean/fix/carry-2564
fix(libkernel): return every command-line argument as UTF-8 from getargv on Windows
This commit is contained in:
commit
9d249f365e
|
|
@ -67,7 +67,7 @@ target_include_directories(libkernel PRIVATE ${LIBS_INCLUDE_DIR}/nid/include)
|
|||
target_link_libraries(libkernel PRIVATE ${CMAKE_DL_LIBS})
|
||||
target_link_libraries(libkernel PRIVATE libc)
|
||||
if(WIN32)
|
||||
target_link_libraries(libkernel PRIVATE ws2_32)
|
||||
target_link_libraries(libkernel PRIVATE ws2_32 shell32)
|
||||
target_compile_definitions(libkernel PRIVATE _WIN32_WINNT=0x0602)
|
||||
endif()
|
||||
configure_windows_unwind(libkernel)
|
||||
|
|
@ -125,6 +125,15 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_process_time guest_process_time_counter PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_process_arguments_tests ${LIBS_INCLUDE_DIR}/tests/GuestProcessArguments.cpp)
|
||||
target_include_directories(guest_process_arguments_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_process_arguments_tests PRIVATE libkernel libc)
|
||||
configure_windows_unwind(guest_process_arguments_tests)
|
||||
add_test(NAME guest_process_arguments COMMAND guest_process_arguments_tests plain "two words" "ü日")
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_process_arguments PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_library(guest_module_fixture SHARED ${LIBS_INCLUDE_DIR}/tests/GuestModuleFixture.cpp)
|
||||
target_include_directories(guest_module_fixture PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
add_custom_command(TARGET guest_module_fixture POST_BUILD
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -46,17 +47,30 @@ constexpr unsigned freebsdWaitOptions = 0x8000003Fu;
|
|||
std::atomic<std::uint32_t> gpoBits{0};
|
||||
constexpr std::array<std::uint8_t, 16> openPsId{'A', 'n', 'y', 'P', 'S', '5', 'O', 'p', 'e', 'n', 'P', 's', 'I', 'd', 0, 1};
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string toUtf8(const wchar_t* value) {
|
||||
const int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, value, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (size <= 0)
|
||||
throw std::system_error(GetLastError(), std::system_category(), "Converting a process argument to UTF-8");
|
||||
std::string text(static_cast<std::size_t>(size), '\0');
|
||||
if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, value, -1, text.data(), size, nullptr, nullptr) != size)
|
||||
throw std::system_error(GetLastError(), std::system_category(), "Converting a process argument to UTF-8");
|
||||
text.pop_back();
|
||||
return text;
|
||||
}
|
||||
#endif
|
||||
|
||||
class ProcessArguments {
|
||||
public:
|
||||
ProcessArguments() {
|
||||
#ifdef _WIN32
|
||||
std::array<char, 32768> path{};
|
||||
const auto size = GetModuleFileNameA(nullptr, path.data(), static_cast<DWORD>(path.size()));
|
||||
if (size == 0)
|
||||
throw std::system_error(GetLastError(), std::system_category(), "Reading executable path");
|
||||
if (size >= path.size())
|
||||
throw std::runtime_error("Executable path exceeds the guest argument buffer");
|
||||
arguments.emplace_back(path.data(), size);
|
||||
int count = 0;
|
||||
const std::unique_ptr<LPWSTR, void (*)(LPWSTR*)> values(CommandLineToArgvW(GetCommandLineW(), &count),
|
||||
[](LPWSTR* parsed) { LocalFree(parsed); });
|
||||
if (!values)
|
||||
throw std::system_error(GetLastError(), std::system_category(), "Reading process arguments");
|
||||
for (int index = 0; index < count; ++index)
|
||||
arguments.push_back(toUtf8(values.get()[index]));
|
||||
#else
|
||||
std::ifstream stream("/proc/self/cmdline", std::ios::binary);
|
||||
if (!stream)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" int APS5_VABI getargc_nid_postfix(void);
|
||||
extern "C" const char** APS5_VABI getargv_nid_postfix(void);
|
||||
|
||||
static void Require(bool condition, const char* message) {
|
||||
if (!condition) {
|
||||
std::fprintf(stderr, "%s\n", message);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
const char* const expected[] = {"plain", "two words", "ü日"};
|
||||
constexpr int expectedCount = 1 + static_cast<int>(sizeof(expected) / sizeof(expected[0]));
|
||||
const int count = getargc_nid_postfix();
|
||||
const char** values = getargv_nid_postfix();
|
||||
Require(count == expectedCount, "getargc does not count every command-line argument");
|
||||
Require(values != nullptr && values[0] != nullptr && values[0][0] != '\0', "getargv has no program name");
|
||||
for (int index = 1; index < expectedCount; ++index) {
|
||||
Require(values[index] != nullptr && std::strcmp(values[index], expected[index - 1]) == 0,
|
||||
"getargv does not return a command-line argument as UTF-8");
|
||||
}
|
||||
Require(values[count] == nullptr, "getargv is not terminated by a null pointer");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue