From 33ebd40964fb62ec46031acf97833c9199a8e8b4 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Thu, 21 May 2020 11:56:25 +0300 Subject: [PATCH] Unicode support in Windows console: reading in UTF-16 and converting to UTF-8. --- common/src/files/cpp/Files.cpp | 2 +- runtime/src/main/cpp/Porting.cpp | 33 ++++++++++++++++++- .../kotlin/konan/target/ClangArgs.kt | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/common/src/files/cpp/Files.cpp b/common/src/files/cpp/Files.cpp index fab901711ed..9f6aef7662b 100644 --- a/common/src/files/cpp/Files.cpp +++ b/common/src/files/cpp/Files.cpp @@ -17,7 +17,7 @@ bool renameAtomic(const char* from, const char* to, bool replaceExisting) { #include bool renameAtomic(const char* from, const char* to, bool replaceExisting) { - return MoveFileEx(from, to, replaceExisting ? MOVEFILE_REPLACE_EXISTING : 0) != 0; + return MoveFileExA(from, to, replaceExisting ? MOVEFILE_REPLACE_EXISTING : 0) != 0; } #else diff --git a/runtime/src/main/cpp/Porting.cpp b/runtime/src/main/cpp/Porting.cpp index 25b626c48e2..311271e1784 100644 --- a/runtime/src/main/cpp/Porting.cpp +++ b/runtime/src/main/cpp/Porting.cpp @@ -60,6 +60,11 @@ void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes) { #ifdef KONAN_ANDROID // TODO: use sizeBytes! __android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8); +//#elif KONAN_WINDOWS +// // UTF-16 write +// void *con = GetStdHandle(STD_OUTPUT_HANDLE); +// unsigned long num; +// ::WriteConsole(con, utf8, sizeBytes, &num, NULL); #else ::write(STDOUT_FILENO, utf8, sizeBytes); #endif @@ -69,6 +74,11 @@ void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes) { #ifdef KONAN_ANDROID // TODO: use sizeBytes! __android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8); +//#elif KONAN_WINDOWS +// // UTF-16 write +// void *con = GetStdHandle(STD_ERROR_HANDLE); +// unsigned long num; +// ::WriteConsole(con, utf8, sizeBytes, &num, NULL); #else ::write(STDERR_FILENO, utf8, sizeBytes); #endif @@ -77,8 +87,30 @@ void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes) { int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) { #ifdef KONAN_ZEPHYR return 0; +#elif KONAN_WINDOWS + void *con = ::GetStdHandle(STD_INPUT_HANDLE); + unsigned long bufferRead; + auto bufferLength = maxSizeBytes / 4; + wchar_t buffer[bufferLength]; + ::ReadConsoleW(con, buffer, bufferLength, &bufferRead, NULL); + auto length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8, maxSizeBytes, NULL, NULL); + if (!length) { + auto errCode = ::GetLastError(); + if (errCode) { + auto flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER; + wchar_t *errMsgBuffer; + auto errMsgLength = ::FormatMessageW(flags, NULL, errCode, 0, errMsgBuffer, 1024, NULL); + char errMsgUtf8[4096]; + ::WideCharToMultiByte(CP_UTF8, 0, errMsgBuffer, errMsgLength, errMsgUtf8, + sizeof(errMsgUtf8), NULL, NULL); + consoleErrorf("UTF-16 to UTF-8 convertion error %d: %s\n", errCode, errMsgUtf8); + ::LocalFree(errMsgBuffer); + } + } + ((char*) utf8)[length] = 0; #else auto length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1); +#endif if (length <= 0) return -1; char* start = reinterpret_cast(utf8); char* current = start + length - 1; @@ -96,7 +128,6 @@ int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) { current--; } return length; -#endif } #if KONAN_INTERNAL_SNPRINTF diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt index 05b529123b3..2f62ad6a4eb 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt @@ -205,6 +205,7 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con listOf("-DUSE_GCC_UNWIND=1", "-DUSE_PE_COFF_SYMBOLS=1", "-DKONAN_WINDOWS=1", + "-DUNICODE", if (target == KonanTarget.MINGW_X64) "-DKONAN_X64=1" else "-DKONAN_X86=1", "-DKONAN_NO_MEMMEM=1", "-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1")