Better unicode support: use UTF-16 for console input, while piped input still uses UTF-8.

This commit is contained in:
Pavel Punegov
2020-05-22 21:17:03 +03:00
committed by Pavel Punegov
parent 33ebd40964
commit 1b3504119d
+40 -28
View File
@@ -34,6 +34,7 @@
#include "Common.h"
#include "Porting.h"
#include "KAssert.h"
#if KONAN_WASM || KONAN_ZEPHYR
extern "C" RUNTIME_NORETURN void Konan_abort(const char*);
@@ -53,6 +54,8 @@ void consoleInit() {
// how we perform console IO, if it turns out, that UTF-16 is better output format.
::SetConsoleCP(CP_UTF8);
::SetConsoleOutputCP(CP_UTF8);
// FIXME: should set original CP back during the deinit of the program.
// Otherwise, this codepage remains in the console.
#endif
}
@@ -60,11 +63,6 @@ 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
@@ -74,40 +72,54 @@ 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
}
#if KONAN_WINDOWS
int getLastErrorMessage(char* message, uint32_t size) {
auto errCode = ::GetLastError();
if (errCode) {
auto flags = FORMAT_MESSAGE_FROM_SYSTEM;
auto errMsgBufSize = size / 4;
wchar_t errMsgBuffer[errMsgBufSize];
::FormatMessageW(flags, NULL, errCode, 0, errMsgBuffer, errMsgBufSize, NULL);
auto errMsgLength = ::WideCharToMultiByte(CP_UTF8, 0, errMsgBuffer, -1, message, size, NULL, NULL);
}
return errCode;
}
#endif
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);
auto length = 0;
void *stdInHandle = ::GetStdHandle(STD_INPUT_HANDLE);
if (::GetFileType(stdInHandle) == FILE_TYPE_CHAR) {
unsigned long bufferRead;
// In UTF-16 there are surrogate pairs that a 2 * 16-bit long (4 bytes).
auto bufferLength = maxSizeBytes / 4 - 1;
wchar_t buffer[bufferLength];
if (::ReadConsoleW(stdInHandle, buffer, bufferLength, &bufferRead, NULL)) {
length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8,
maxSizeBytes - 1, NULL, NULL);
if (!length && KonanNeedDebugInfo) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
char buffer[1024];
consoleErrorf("UTF-16 to UTF-8 conversion error %d: %s", errCode, msg);
}
((char*) utf8)[length] = 0;
} else if (KonanNeedDebugInfo) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("Console read failure: %d %s", errCode, msg);
}
} else {
length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
}
((char*) utf8)[length] = 0;
#else
auto length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
#endif