Skip to content

Commit 1544ff5

Browse files
[windows] fix utf console output (#1307)
1 parent abfd20d commit 1544ff5

2 files changed

Lines changed: 130 additions & 25 deletions

File tree

src/hx/StdLibs.cpp

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -255,29 +255,15 @@ void __hxcpp_stdlibs_boot()
255255
#endif
256256

257257
#if defined(_MSC_VER) && !defined(HX_WINRT)
258-
HMODULE kernel32 = LoadLibraryA("kernel32");
259-
if (kernel32)
260-
{
261-
typedef BOOL (WINAPI *AttachConsoleFunc)(DWORD);
262-
typedef HWND (WINAPI *GetConsoleWindowFunc)(void);
263-
AttachConsoleFunc attach = (AttachConsoleFunc)GetProcAddress(kernel32,"AttachConsole");
264-
GetConsoleWindowFunc getConsole = (GetConsoleWindowFunc)GetProcAddress(kernel32,"GetConsoleWindow");
265-
if (attach && getConsole)
266-
{
267-
if (!attach( /*ATTACH_PARENT_PROCESS*/ (DWORD)-1 ))
268-
{
269-
//printf("Could not attach to parent console : %d\n",GetLastError());
270-
}
271-
else if (getConsole())
272-
{
273-
if (_fileno(stdout) < 0 || _get_osfhandle(fileno(stdout)) < 0)
274-
freopen("CONOUT$", "w", stdout);
275-
if (_fileno(stderr) < 0 || _get_osfhandle(fileno(stderr)) < 0)
276-
freopen("CONOUT$", "w", stderr);
277-
if (_fileno(stdin) < 0 || _get_osfhandle(fileno(stdin)) < 0)
278-
freopen("CONIN$", "r", stdin);
279-
}
280-
}
258+
if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
259+
260+
} else if (GetConsoleWindow()) {
261+
if (_fileno(stdout) < 0 || _get_osfhandle(fileno(stdout)) < 0)
262+
freopen("CONOUT$", "w", stdout);
263+
if (_fileno(stderr) < 0 || _get_osfhandle(fileno(stderr)) < 0)
264+
freopen("CONOUT$", "w", stderr);
265+
if (_fileno(stdin) < 0 || _get_osfhandle(fileno(stdin)) < 0)
266+
freopen("CONIN$", "r", stdin);
281267
}
282268
//_setmode(_fileno(stdout), 0x00040000); // _O_U8TEXT
283269
//_setmode(_fileno(stderr), 0x00040000); // _O_U8TEXT
@@ -294,12 +280,72 @@ void __hxcpp_stdlibs_boot()
294280
setbuf(stderr, 0);
295281
}
296282

283+
#ifdef HX_WINDOWS
284+
void WriteConsoleAllW(HANDLE h, const wchar_t *str, DWORD length) {
285+
DWORD total_written = 0;
286+
DWORD remaining = length;
287+
while (total_written < length) {
288+
DWORD written;
289+
if (!WriteConsoleW(h, str + total_written, remaining, &written, NULL))
290+
{
291+
return;
292+
}
293+
if (written == remaining) {
294+
return;
295+
}
296+
total_written += written;
297+
remaining -= written;
298+
}
299+
}
300+
301+
void WriteConsoleAllA(HANDLE h, const char *str, DWORD length) {
302+
DWORD total_written = 0;
303+
DWORD remaining = length;
304+
while (total_written < length) {
305+
DWORD written;
306+
if (!WriteConsoleA(h, str + total_written, remaining, &written, NULL))
307+
{
308+
return;
309+
}
310+
if (written == remaining) {
311+
return;
312+
}
313+
total_written += written;
314+
remaining -= written;
315+
}
316+
}
317+
#endif
318+
297319
void __trace(Dynamic inObj, Dynamic info)
298320
{
299321
String text;
300322
if (inObj != null())
301323
text = inObj->toString();
302324

325+
#ifdef HX_WINDOWS
326+
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
327+
DWORD mode;
328+
if (GetConsoleMode(handle, &mode))
329+
{
330+
fflush(stdout);
331+
String s;
332+
if (info == null()) {
333+
s = String("?? ") + text + String("\n");
334+
} else {
335+
String filename = Dynamic((info)->__Field(HX_CSTRING("fileName"), HX_PROP_DYNAMIC))->toString();
336+
int line = Dynamic((info)->__Field(HX_CSTRING("lineNumber"), HX_PROP_DYNAMIC))->__ToInt();
337+
s = filename + String(":") + line + String(": ") + text + String("\n");
338+
}
339+
if (s.isUTF16Encoded())
340+
{
341+
WriteConsoleAllW(handle, s.__WCStr(), s.length);
342+
} else {
343+
// ascii
344+
WriteConsoleAllA(handle, s.__CStr(), s.length);
345+
}
346+
return;
347+
}
348+
#endif
303349

304350
hx::strbuf convertBuf;
305351
if (info==null())
@@ -606,12 +652,34 @@ Array<String> __get_args()
606652

607653
void __hxcpp_print_string(const String &inV)
608654
{
655+
#ifdef HX_WINDOWS
656+
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
657+
DWORD mode;
658+
if (GetConsoleMode(handle, &mode) && inV.isUTF16Encoded())
659+
{
660+
fflush(stdout);
661+
WriteConsoleAllW(handle, inV.__WCStr(), inV.length);
662+
return;
663+
}
664+
#endif
609665
hx::strbuf convertBuf;
610666
PRINTF("%s", inV.out_str(&convertBuf) );
611667
}
612668

613669
void __hxcpp_println_string(const String &inV)
614670
{
671+
#ifdef HX_WINDOWS
672+
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
673+
DWORD mode;
674+
if (GetConsoleMode(handle, &mode) && inV.isUTF16Encoded())
675+
{
676+
fflush(stdout);
677+
WriteConsoleAllW(handle, inV.__WCStr(), inV.length);
678+
fwrite("\n", 1, 1, stdout);
679+
fflush(stdout);
680+
return;
681+
}
682+
#endif
615683
hx::strbuf convertBuf;
616684
PRINTF("%s\n", inV.out_str(&convertBuf));
617685
fflush(stdout);

src/hx/libs/std/File.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#ifdef NEKO_WINDOWS
99
# include <windows.h>
10+
# include <io.h>
1011
#endif
1112

1213
/**
@@ -146,7 +147,44 @@ int _hx_std_file_write( Dynamic handle, Array<unsigned char> s, int p, int n )
146147
if( p < 0 || len < 0 || p > buflen || p + len > buflen )
147148
return 0;
148149

149-
hx::EnterGCFreeZone();
150+
hx::AutoGCFreeZone zone;
151+
#ifdef HX_WINDOWS
152+
if (_isatty(_fileno(f->io))) {
153+
fflush(f->io);
154+
HANDLE win_handle = (HANDLE)_get_osfhandle(_fileno(f->io));
155+
static const int MAX_BUFFER_SIZE = 8192;
156+
wchar_t buf[MAX_BUFFER_SIZE / 2];
157+
int result = MultiByteToWideChar(CP_UTF8, 0, (char *)&s[p], len, buf, MAX_BUFFER_SIZE / 2);
158+
DWORD written = 0;
159+
if(!WriteConsoleW(win_handle, buf, result, &written, NULL)) {
160+
file_error("file_write", f->name);
161+
}
162+
if (written == result) {
163+
return len;
164+
} else {
165+
auto first_code_unit_remaining = buf[written];
166+
if (first_code_unit_remaining > 0xDCEE && first_code_unit_remaining <= 0xDFF) {
167+
DWORD tmp;
168+
WriteConsoleW(win_handle, &buf[written], 1, &tmp, NULL);
169+
written += 1;
170+
}
171+
int count = 0;
172+
for (int i = 0; i < written; i++) {
173+
wchar_t ch = buf[i];
174+
if (ch >= 0 && ch <= 0x7F) {
175+
count += 1;
176+
} else if (ch >= 0x0080 && ch <= 0x07FF) {
177+
count += 2;
178+
} else if (ch >= 0xDCEE && ch <= 0xDFF) {
179+
count += 1;
180+
} else {
181+
count += 3;
182+
}
183+
}
184+
return count;
185+
}
186+
}
187+
#endif
150188
while( len > 0 )
151189
{
152190
POSIX_LABEL(file_write_again);
@@ -159,7 +197,6 @@ int _hx_std_file_write( Dynamic handle, Array<unsigned char> s, int p, int n )
159197
p += d;
160198
len -= d;
161199
}
162-
hx::ExitGCFreeZone();
163200
return n;
164201
}
165202

0 commit comments

Comments
 (0)