From bd976eebe875bd6f4b7f3e97d7727eb91ea18b5b Mon Sep 17 00:00:00 2001 From: "U-teleon\\arr" Date: Mon, 18 May 2026 11:46:01 +0200 Subject: [PATCH 1/6] added missing include for SetConsoleOutput in nob.c --- nob.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nob.c b/nob.c index 58c0500..20a258e 100644 --- a/nob.c +++ b/nob.c @@ -172,6 +172,10 @@ extern "C" { } #endif +#ifdef _WIN32 +#include "ConsoleApi2.h" +#endif // _WIN32 + int main(int argc, char **argv) { #ifdef _WIN32 From 25155ae098134813bac90c98151277ded68d523a Mon Sep 17 00:00:00 2001 From: "U-teleon\\arr" Date: Mon, 18 May 2026 11:49:54 +0200 Subject: [PATCH 2/6] added utf8 <-> utf16 conversion functions and changed win32 directory api to use utf16 strings --- nob.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/nob.h b/nob.h index 2735a93..aeaa473 100644 --- a/nob.h +++ b/nob.h @@ -308,12 +308,12 @@ NOBDEF bool nob_walk_dir_opt(const char *root, Nob_Walk_Func func, Nob_Walk_Dir_ #define nob_walk_dir(root, func, ...) nob_walk_dir_opt((root), (func), NOB_CLIT(Nob_Walk_Dir_Opt){__VA_ARGS__}) typedef struct { - char *name; + const char *name; bool error; struct { #ifdef _WIN32 - WIN32_FIND_DATA win32_data; + WIN32_FIND_DATAW win32_data; HANDLE win32_hFind; bool win32_init; #else @@ -951,6 +951,7 @@ NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count); #ifdef _WIN32 NOBDEF char *nob_win32_error_message(DWORD err); +NOBDEF LPCWSTR nob_win32_temp_utf8_to_utf16(const char* str); #endif // _WIN32 @@ -1014,6 +1015,50 @@ NOBDEF char *nob_win32_error_message(DWORD err) { return win32ErrMsg; } +// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar +NOBDEF LPCWSTR nob_win32_temp_utf8_to_utf16(const char* str){ + + // n is the output strings size in charachters and includes size for null terminator due to -1 + int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(n == 0){ + nob_log(NOB_ERROR, "Could not determine charachter count for utf8 to utf16 conversion: %s", nob_win32_error_message(GetLastError())); + return NULL; + } + + LPWSTR wstr; + wstr = nob_temp_alloc(n*sizeof(*wstr)); + + n = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, n); + if(n == 0){ + nob_log(NOB_ERROR, "Could not convert utf8 to utf16: %s", nob_win32_error_message(GetLastError())); + return NULL; + } + + return wstr; +} + +// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte +NOBDEF const char* nob_win32_temp_utf16_to_utf8(LPCWSTR wstr){ + + // n is the output strings size in bytes and includes size for null terminator due to -1 + int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + if(n == 0){ + nob_log(NOB_ERROR, "Could not determine byte count for utf16 to utf8 conversion: %s", nob_win32_error_message(GetLastError())); + return NULL; + } + + char* str; + str = nob_temp_alloc(n*sizeof(*str)); + + n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, n, NULL, NULL); + if(n == 0){ + nob_log(NOB_ERROR, "Could not convert utf16 to utf8: %s", nob_win32_error_message(GetLastError())); + return NULL; + } + + return str; +} + #endif // _WIN32 // The implementation idea is stolen from https://github.com/zhiayang/nabs @@ -1218,6 +1263,7 @@ static void nob__win32_cmd_quote(Nob_Cmd cmd, Nob_String_Builder *quoted) } } } + #endif NOBDEF int nob_nprocs(void) @@ -1959,8 +2005,8 @@ NOBDEF bool nob_dir_entry_open(const char *dir_path, Nob_Dir_Entry *dir) memset(dir, 0, sizeof(*dir)); #ifdef _WIN32 size_t temp_mark = nob_temp_save(); - char *buffer = nob_temp_sprintf("%s\\*", dir_path); - dir->nob__private.win32_hFind = FindFirstFile(buffer, &dir->nob__private.win32_data); + LPCWSTR buffer = nob_win32_temp_utf8_to_utf16(nob_temp_sprintf("%s\\*", dir_path)); + dir->nob__private.win32_hFind = FindFirstFileW(buffer, &dir->nob__private.win32_data); nob_temp_rewind(temp_mark); if (dir->nob__private.win32_hFind == INVALID_HANDLE_VALUE) { @@ -1984,17 +2030,17 @@ NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) #ifdef _WIN32 if (!dir->nob__private.win32_init) { dir->nob__private.win32_init = true; - dir->name = dir->nob__private.win32_data.cFileName; + dir->name = nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); return true; } - if (!FindNextFile(dir->nob__private.win32_hFind, &dir->nob__private.win32_data)) { + if (!FindNextFileW(dir->nob__private.win32_hFind, &dir->nob__private.win32_data)) { if (GetLastError() == ERROR_NO_MORE_FILES) return false; nob_log(NOB_ERROR, "Could not read next directory entry: %s", nob_win32_error_message(GetLastError())); dir->error = true; return false; } - dir->name = dir->nob__private.win32_data.cFileName; + dir->name = nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); #else errno = 0; dir->nob__private.posix_ent = readdir(dir->nob__private.posix_dir); From ffe93d5574efe23c255cfeff9f7f1b629be68f84 Mon Sep 17 00:00:00 2001 From: "U-teleon\\arr" Date: Mon, 18 May 2026 12:01:43 +0200 Subject: [PATCH 3/6] added explicit casts --- nob.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nob.h b/nob.h index aeaa473..15c613c 100644 --- a/nob.h +++ b/nob.h @@ -1026,7 +1026,7 @@ NOBDEF LPCWSTR nob_win32_temp_utf8_to_utf16(const char* str){ } LPWSTR wstr; - wstr = nob_temp_alloc(n*sizeof(*wstr)); + wstr = (LPWSTR)nob_temp_alloc(n*sizeof(*wstr)); n = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, n); if(n == 0){ @@ -1048,7 +1048,7 @@ NOBDEF const char* nob_win32_temp_utf16_to_utf8(LPCWSTR wstr){ } char* str; - str = nob_temp_alloc(n*sizeof(*str)); + str = (char*)nob_temp_alloc(n*sizeof(*str)); n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, n, NULL, NULL); if(n == 0){ From ada570fa1dd8a7babed12c1b9719a10fedf7070b Mon Sep 17 00:00:00 2001 From: "U-teleon\\arr" Date: Mon, 18 May 2026 12:18:26 +0200 Subject: [PATCH 4/6] reverted const change for name in Nob_Dir_Entry --- nob.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nob.h b/nob.h index 15c613c..938dd86 100644 --- a/nob.h +++ b/nob.h @@ -308,7 +308,7 @@ NOBDEF bool nob_walk_dir_opt(const char *root, Nob_Walk_Func func, Nob_Walk_Dir_ #define nob_walk_dir(root, func, ...) nob_walk_dir_opt((root), (func), NOB_CLIT(Nob_Walk_Dir_Opt){__VA_ARGS__}) typedef struct { - const char *name; + char *name; bool error; struct { @@ -2030,7 +2030,7 @@ NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) #ifdef _WIN32 if (!dir->nob__private.win32_init) { dir->nob__private.win32_init = true; - dir->name = nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); + dir->name = (char*)nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); return true; } @@ -2040,7 +2040,7 @@ NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) dir->error = true; return false; } - dir->name = nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); + dir->name = (char*)nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); #else errno = 0; dir->nob__private.posix_ent = readdir(dir->nob__private.posix_dir); From 67d8d618ec79ec6e43c3f2c77abb661b3c5a9625 Mon Sep 17 00:00:00 2001 From: "U-teleon\\arr" Date: Mon, 18 May 2026 14:24:48 +0200 Subject: [PATCH 5/6] replace dir_entry temp allocators with statically sized buffer --- nob.h | 101 +++++++++++++++++++++++++++------------------------------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/nob.h b/nob.h index 938dd86..cb877c3 100644 --- a/nob.h +++ b/nob.h @@ -316,6 +316,7 @@ typedef struct { WIN32_FIND_DATAW win32_data; HANDLE win32_hFind; bool win32_init; + char utf8_name[MAX_PATH]; #else DIR *posix_dir; struct dirent *posix_ent; @@ -951,7 +952,6 @@ NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count); #ifdef _WIN32 NOBDEF char *nob_win32_error_message(DWORD err); -NOBDEF LPCWSTR nob_win32_temp_utf8_to_utf16(const char* str); #endif // _WIN32 @@ -1014,51 +1014,6 @@ NOBDEF char *nob_win32_error_message(DWORD err) { return win32ErrMsg; } - -// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar -NOBDEF LPCWSTR nob_win32_temp_utf8_to_utf16(const char* str){ - - // n is the output strings size in charachters and includes size for null terminator due to -1 - int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if(n == 0){ - nob_log(NOB_ERROR, "Could not determine charachter count for utf8 to utf16 conversion: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - LPWSTR wstr; - wstr = (LPWSTR)nob_temp_alloc(n*sizeof(*wstr)); - - n = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, n); - if(n == 0){ - nob_log(NOB_ERROR, "Could not convert utf8 to utf16: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - return wstr; -} - -// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte -NOBDEF const char* nob_win32_temp_utf16_to_utf8(LPCWSTR wstr){ - - // n is the output strings size in bytes and includes size for null terminator due to -1 - int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); - if(n == 0){ - nob_log(NOB_ERROR, "Could not determine byte count for utf16 to utf8 conversion: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - char* str; - str = (char*)nob_temp_alloc(n*sizeof(*str)); - - n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, n, NULL, NULL); - if(n == 0){ - nob_log(NOB_ERROR, "Could not convert utf16 to utf8: %s", nob_win32_error_message(GetLastError())); - return NULL; - } - - return str; -} - #endif // _WIN32 // The implementation idea is stolen from https://github.com/zhiayang/nabs @@ -1263,7 +1218,6 @@ static void nob__win32_cmd_quote(Nob_Cmd cmd, Nob_String_Builder *quoted) } } } - #endif NOBDEF int nob_nprocs(void) @@ -2005,8 +1959,16 @@ NOBDEF bool nob_dir_entry_open(const char *dir_path, Nob_Dir_Entry *dir) memset(dir, 0, sizeof(*dir)); #ifdef _WIN32 size_t temp_mark = nob_temp_save(); - LPCWSTR buffer = nob_win32_temp_utf8_to_utf16(nob_temp_sprintf("%s\\*", dir_path)); - dir->nob__private.win32_hFind = FindFirstFileW(buffer, &dir->nob__private.win32_data); + char *buffer = nob_temp_sprintf("%s\\*", dir_path); + + WCHAR utf16_buffer[MAX_PATH]; + int n = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, utf16_buffer, sizeof(utf16_buffer)); + if(n == 0){ + nob_log(NOB_ERROR, "Could not convert dir_path name from utf8 to utf16: %s", nob_win32_error_message(GetLastError())); + return false; + } + + dir->nob__private.win32_hFind = FindFirstFileW(utf16_buffer, &dir->nob__private.win32_data); nob_temp_rewind(temp_mark); if (dir->nob__private.win32_hFind == INVALID_HANDLE_VALUE) { @@ -2030,7 +1992,13 @@ NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) #ifdef _WIN32 if (!dir->nob__private.win32_init) { dir->nob__private.win32_init = true; - dir->name = (char*)nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); + + int n = WideCharToMultiByte(CP_UTF8, 0, dir->nob__private.win32_data.cFileName, -1, dir->nob__private.utf8_name, sizeof(dir->nob__private.utf8_name), NULL, NULL); + if(n == 0){ + nob_log(NOB_ERROR, "Could not convert path name from utf16 to utf8: %s", nob_win32_error_message(GetLastError())); + return false; + } + dir->name = dir->nob__private.utf8_name; return true; } @@ -2040,7 +2008,13 @@ NOBDEF bool nob_dir_entry_next(Nob_Dir_Entry *dir) dir->error = true; return false; } - dir->name = (char*)nob_win32_temp_utf16_to_utf8(dir->nob__private.win32_data.cFileName); + + int n = WideCharToMultiByte(CP_UTF8, 0, dir->nob__private.win32_data.cFileName, -1, dir->nob__private.utf8_name, sizeof(dir->nob__private.utf8_name), NULL, NULL); + if(n == 0){ + nob_log(NOB_ERROR, "Could not convert path name from utf16 to utf8: %s", nob_win32_error_message(GetLastError())); + return false; + } + dir->name = dir->nob__private.utf8_name; #else errno = 0; dir->nob__private.posix_ent = readdir(dir->nob__private.posix_dir); @@ -2760,18 +2734,37 @@ NOBDEF int nob_file_exists(const char *file_path) NOBDEF const char *nob_get_current_dir_temp(void) { #ifdef _WIN32 - DWORD nBufferLength = GetCurrentDirectory(0, NULL); + DWORD nBufferLength = GetCurrentDirectoryW(0, NULL); if (nBufferLength == 0) { nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError())); return NULL; } - char *buffer = (char*) nob_temp_alloc(nBufferLength); - if (GetCurrentDirectory(nBufferLength, buffer) == 0) { + LPWSTR utf16_buffer; + utf16_buffer = (LPWSTR) nob_temp_alloc(nBufferLength*sizeof(*utf16_buffer)); + + if (GetCurrentDirectoryW(nBufferLength, utf16_buffer) == 0) { nob_log(NOB_ERROR, "could not get current directory: %s", nob_win32_error_message(GetLastError())); return NULL; } + + int nUtf8BufferLength = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, nBufferLength, NULL, 0, NULL, NULL); + if(nUtf8BufferLength == 0){ + nob_log(NOB_ERROR, "Could not determine utf8 path size: %s", nob_win32_error_message(GetLastError())); + return false; + } + + char* buffer; + buffer = (char*) nob_temp_alloc(nUtf8BufferLength*sizeof(*buffer)); + + nUtf8BufferLength = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, nBufferLength, buffer, nUtf8BufferLength, NULL, NULL); + if(nBufferLength == 0){ + nob_log(NOB_ERROR, "Could not convert utf16 path to utf8: %s", nob_win32_error_message(GetLastError())); + return false; + } + + return buffer; #else char *buffer = (char*) nob_temp_alloc(PATH_MAX); From 0ca947f4b82668ebd4a76fc3ad125e18f5f61077 Mon Sep 17 00:00:00 2001 From: Alaric de Ruiter Date: Mon, 18 May 2026 19:03:40 +0200 Subject: [PATCH 6/6] fixed get_current_dir returns --- nob.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nob.h b/nob.h index cb877c3..8248d00 100644 --- a/nob.h +++ b/nob.h @@ -2752,7 +2752,7 @@ NOBDEF const char *nob_get_current_dir_temp(void) int nUtf8BufferLength = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, nBufferLength, NULL, 0, NULL, NULL); if(nUtf8BufferLength == 0){ nob_log(NOB_ERROR, "Could not determine utf8 path size: %s", nob_win32_error_message(GetLastError())); - return false; + return NULL; } char* buffer; @@ -2761,7 +2761,7 @@ NOBDEF const char *nob_get_current_dir_temp(void) nUtf8BufferLength = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, nBufferLength, buffer, nUtf8BufferLength, NULL, NULL); if(nBufferLength == 0){ nob_log(NOB_ERROR, "Could not convert utf16 path to utf8: %s", nob_win32_error_message(GetLastError())); - return false; + return NULL; }