1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-15 10:35:19 -05:00

libdeno: fix libdeno.print() unicode output on Windows

Note that emoji are still not supported, due limitations of the
Windows console.
This commit is contained in:
Bert Belder 2019-03-03 19:07:25 -08:00
parent 2e9d43391f
commit 4cb157b85b
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461

View file

@ -2,9 +2,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <algorithm>
#include <iostream> #include <iostream>
#include <string> #include <string>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h>
#include <windows.h>
#endif // _WIN32
#include "third_party/v8/include/v8.h" #include "third_party/v8/include/v8.h"
#include "third_party/v8/src/base/logging.h" #include "third_party/v8/src/base/logging.h"
@ -93,10 +102,52 @@ void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
DenoIsolate* d = DenoIsolate::FromIsolate(isolate); DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
auto context = d->context_.Get(d->isolate_); auto context = d->context_.Get(d->isolate_);
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
v8::String::Utf8Value str(isolate, args[0]);
bool is_err = bool is_err =
args.Length() >= 2 ? args[1]->BooleanValue(context).ToChecked() : false; args.Length() >= 2 ? args[1]->BooleanValue(context).ToChecked() : false;
FILE* file = is_err ? stderr : stdout; FILE* file = is_err ? stderr : stdout;
#ifdef _WIN32
int fd = _fileno(file);
if (fd < 0) return;
HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
if (h == INVALID_HANDLE_VALUE) return;
DWORD mode;
if (GetConsoleMode(h, &mode)) {
// Print to Windows console. Since the Windows API generally doesn't support
// UTF-8 encoded text, we have to use `WriteConsoleW()` which uses UTF-16.
v8::String::Value str(isolate, args[0]);
auto str_len = static_cast<size_t>(str.length());
auto str_wchars = reinterpret_cast<WCHAR*>(*str);
// WriteConsoleW has some limit to how many characters can be written at
// once, which is unspecified but low enough to be encountered in practice.
// Therefore we break up the write into chunks of 8kb if necessary.
size_t chunk_start = 0;
while (chunk_start < str_len) {
size_t chunk_end = std::min(chunk_start + 8192, str_len);
// Do not break in the middle of a surrogate pair. Note that `chunk_end`
// points to the start of the next chunk, so we check whether it contains
// the second half of a surrogate pair (a.k.a. "low surrogate").
if (chunk_end < str_len && str_wchars[chunk_end] >= 0xdc00 &&
str_wchars[chunk_end] <= 0xdfff) {
--chunk_end;
}
// Write to the console.
DWORD chunk_len = static_cast<DWORD>(chunk_end - chunk_start);
DWORD _;
WriteConsoleW(h, &str_wchars[chunk_start], chunk_len, &_, nullptr);
chunk_start = chunk_end;
}
return;
}
#endif // _WIN32
v8::String::Utf8Value str(isolate, args[0]);
fwrite(*str, sizeof(**str), str.length(), file); fwrite(*str, sizeof(**str), str.length(), file);
fflush(file); fflush(file);
} }