From 393d267d191aabdb0acbc53a9645cf6a8f6d2dc7 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 23 Dec 2025 03:32:50 +0000 Subject: [PATCH 1/6] [sys] Fix sys_read_dir unicode on windows --- libs/std/sys.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/libs/std/sys.c b/libs/std/sys.c index a9185150..5bef567d 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -511,7 +511,7 @@ static value sys_read_dir( value path ) { value h = val_null; value cur = NULL, tmp; #ifdef NEKO_WINDOWS - WIN32_FIND_DATA d; + WIN32_FIND_DATAW d; HANDLE handle; buffer b; int len; @@ -524,14 +524,29 @@ static value sys_read_dir( value path ) { else buffer_append(b,"*.*"); path = buffer_to_string(b); - handle = FindFirstFile(val_string(path),&d); + WCHAR wide_path[MAX_PATH]; + int result = MultiByteToWideChar(CP_UTF8, 0, val_string(path), val_strlen(path) + 1, wide_path, MAX_PATH); + if (result == 0) + neko_error(); + handle = FindFirstFileW(wide_path,&d); if( handle == INVALID_HANDLE_VALUE ) neko_error(); while( true ) { // skip magic dirs - if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) ) { + if( d.cFileName[0] != L'.' || (d.cFileName[1] != 0 && (d.cFileName[1] != L'.' || d.cFileName[2] != 0)) ) { tmp = alloc_array(2); - val_array_ptr(tmp)[0] = alloc_string(d.cFileName); + int len = WideCharToMultiByte(CP_UTF8, 0, d.cFileName, -1, NULL, 0, NULL, NULL); + if (len == 0) { + FindClose(handle); + neko_error(); + } + value item = alloc_empty_string(len - 1); + len = WideCharToMultiByte(CP_UTF8, 0, d.cFileName, -1, val_string(item), len, NULL, NULL); + if (len == 0) { + FindClose(handle); + neko_error(); + } + val_array_ptr(tmp)[0] = item; val_array_ptr(tmp)[1] = val_null; if( cur ) val_array_ptr(cur)[1] = tmp; @@ -539,7 +554,7 @@ static value sys_read_dir( value path ) { h = tmp; cur = tmp; } - if( !FindNextFile(handle,&d) ) + if( !FindNextFileW(handle,&d) ) break; } FindClose(handle); From ef4f398c692d4be7a7255333abbd2b736e4e7244 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 23 Dec 2025 14:29:10 +0000 Subject: [PATCH 2/6] [sys] Fix sys_exists with unicode on windows --- libs/std/sys.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libs/std/sys.c b/libs/std/sys.c index 5bef567d..14ab2931 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -295,9 +295,19 @@ static value sys_exit( value ecode ) { Returns true if the file or directory exists. **/ static value sys_exists( value path ) { - struct stat st; val_check(path,string); - return alloc_bool(stat(val_string(path),&st) == 0); + #ifdef NEKO_WINDOWS + WCHAR wide_path[MAX_PATH]; + int out = MultiByteToWideChar(CP_UTF8, 0, val_string(path), val_strlen(path) + 1, wide_path, MAX_PATH); + if (out == 0) + neko_error(); + bool result = GetFileAttributesW(wide_path) != INVALID_FILE_ATTRIBUTES; + #else + struct stat st; + bool result = stat(val_string(path),&st) == 0; + #endif + + return alloc_bool(result); } /** From fbf4a99740600179e0832cf24f27e198139a5d98 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 23 Dec 2025 14:41:46 +0000 Subject: [PATCH 3/6] [sys] Fix sys_file_type with unicode on windows --- libs/std/sys.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/libs/std/sys.c b/libs/std/sys.c index 14ab2931..88f2b520 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -290,6 +290,16 @@ static value sys_exit( value ecode ) { return val_true; } +#ifdef NEKO_WINDOWS +#define CONVERT_TO_WPATH(str, wpath) \ + WCHAR wpath[MAX_PATH]; \ + { \ + int result = MultiByteToWideChar(CP_UTF8, 0, val_string(str), val_strlen(str) + 1, wpath, MAX_PATH); \ + if (result == 0) \ + neko_error(); \ + } +#endif + /** sys_exists : string -> bool Returns true if the file or directory exists. @@ -297,10 +307,7 @@ static value sys_exit( value ecode ) { static value sys_exists( value path ) { val_check(path,string); #ifdef NEKO_WINDOWS - WCHAR wide_path[MAX_PATH]; - int out = MultiByteToWideChar(CP_UTF8, 0, val_string(path), val_strlen(path) + 1, wide_path, MAX_PATH); - if (out == 0) - neko_error(); + CONVERT_TO_WPATH(path, wide_path); bool result = GetFileAttributesW(wide_path) != INVALID_FILE_ATTRIBUTES; #else struct stat st; @@ -398,9 +405,15 @@ static value sys_stat( value path ) { **/ static value sys_file_type( value path ) { - struct stat s; val_check(path,string); +#ifdef NEKO_WINDOWS + struct _stat s; + CONVERT_TO_WPATH(path, wide_path); + if( _wstat(wide_path,&s) != 0 ) +#else + struct stat s; if( stat(val_string(path),&s) != 0 ) +#endif neko_error(); if( s.st_mode & S_IFREG ) return alloc_string("file"); From 7f1577d11550b4db0f04b97e6c81d9b68263d18f Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 23 Dec 2025 15:01:03 +0000 Subject: [PATCH 4/6] [sys] Fix sys_stat with unicode on windows --- libs/std/sys.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/std/sys.c b/libs/std/sys.c index 88f2b520..e90556d8 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -368,10 +368,16 @@ static value sys_rename( value path, value newname ) { Run the [stat] command on the given file or directory. **/ static value sys_stat( value path ) { - struct stat s; value o; val_check(path,string); +#ifdef NEKO_WINDOWS + struct _stat s; + CONVERT_TO_WPATH(path, wide_path); + if( _wstat(wide_path,&s) != 0 ) +#else + struct stat s; if( stat(val_string(path),&s) != 0 ) +#endif neko_error(); o = alloc_object(NULL); STATF(gid); From 184ca9242352f3a08a74c5b635c7248f0555b891 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Tue, 23 Dec 2025 15:12:33 +0000 Subject: [PATCH 5/6] [sys] Use conversion macro in sys_read_dir --- libs/std/sys.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libs/std/sys.c b/libs/std/sys.c index e90556d8..54d5f07f 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -553,10 +553,7 @@ static value sys_read_dir( value path ) { else buffer_append(b,"*.*"); path = buffer_to_string(b); - WCHAR wide_path[MAX_PATH]; - int result = MultiByteToWideChar(CP_UTF8, 0, val_string(path), val_strlen(path) + 1, wide_path, MAX_PATH); - if (result == 0) - neko_error(); + CONVERT_TO_WPATH(path, wide_path); handle = FindFirstFileW(wide_path,&d); if( handle == INVALID_HANDLE_VALUE ) neko_error(); From 569332304a590d5192da458ffd5bdf514c795683 Mon Sep 17 00:00:00 2001 From: Tobiasz Laskowski Date: Wed, 24 Dec 2025 03:45:50 +0000 Subject: [PATCH 6/6] [std] Fix file_open with unicode paths on windows --- libs/std/file.c | 7 +++++++ libs/std/sys.c | 11 +---------- libs/std/win_api_strings.h | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 libs/std/win_api_strings.h diff --git a/libs/std/file.c b/libs/std/file.c index 3e6c31cd..8151620d 100644 --- a/libs/std/file.c +++ b/libs/std/file.c @@ -23,6 +23,7 @@ #include #ifdef NEKO_WINDOWS # include +# include "win_api_strings.h" #endif /** @@ -63,7 +64,13 @@ static value file_open( value name, value r ) { val_check(r,string); f = (fio*)alloc(sizeof(fio)); f->name = alloc_string(val_string(name)); +#ifdef NEKO_WINDOWS + CONVERT_TO_WPATH(name,wide_path); + CONVERT_TO_WSTR(r, wide_r); + f->io = _wfopen(wide_path,wide_r); +#else f->io = fopen(val_string(name),val_string(r)); +#endif if( f->io == NULL ) file_error("file_open",f); return alloc_abstract(k_file,f); diff --git a/libs/std/sys.c b/libs/std/sys.c index 54d5f07f..51e9c605 100644 --- a/libs/std/sys.c +++ b/libs/std/sys.c @@ -32,6 +32,7 @@ # include # include # include +# include "win_api_strings.h" #else # include # include @@ -290,16 +291,6 @@ static value sys_exit( value ecode ) { return val_true; } -#ifdef NEKO_WINDOWS -#define CONVERT_TO_WPATH(str, wpath) \ - WCHAR wpath[MAX_PATH]; \ - { \ - int result = MultiByteToWideChar(CP_UTF8, 0, val_string(str), val_strlen(str) + 1, wpath, MAX_PATH); \ - if (result == 0) \ - neko_error(); \ - } -#endif - /** sys_exists : string -> bool Returns true if the file or directory exists. diff --git a/libs/std/win_api_strings.h b/libs/std/win_api_strings.h new file mode 100644 index 00000000..84989f88 --- /dev/null +++ b/libs/std/win_api_strings.h @@ -0,0 +1,26 @@ +#ifndef WIN_PATHS_H +#define WIN_PATHS_H + +#include + +#define CONVERT_TO_WPATH(str, wpath) \ + WCHAR wpath[MAX_PATH]; \ + { \ + int result = MultiByteToWideChar(CP_UTF8, 0, val_string(str), val_strlen(str) + 1, wpath, MAX_PATH); \ + if (result == 0) \ + neko_error(); \ + } + +#define CONVERT_TO_WSTR(str, wstr) \ + WCHAR* wstr; \ + { \ + int wsize = MultiByteToWideChar(CP_UTF8, 0, val_string(str), val_strlen(str) + 1, NULL, 0); \ + if (wsize == 0) \ + neko_error(); \ + wstr = alloca(sizeof(WCHAR) * wsize); \ + int result = MultiByteToWideChar(CP_UTF8, 0, val_string(str), val_strlen(str) + 1, wstr, wsize); \ + if (result == 0) \ + neko_error(); \ + } + +#endif