From 580f4a3a19dc014b3c2bf5d4ac9e1e96857bbc12 Mon Sep 17 00:00:00 2001 From: vylsaz Date: Tue, 7 Jan 2025 03:00:59 +0000 Subject: [PATCH 1/7] Windows: utf-16 util --- src/windows/utf16.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/windows/utf16.c diff --git a/src/windows/utf16.c b/src/windows/utf16.c new file mode 100644 index 00000000..99cbc642 --- /dev/null +++ b/src/windows/utf16.c @@ -0,0 +1,76 @@ +#include "../utils/talloc.h" +#include + +static u64 utf16lenB(B x) { // doesn't consume + assert(isArr(x)); + SGetU(x) + usz ia = IA(x); + u64 res = 0; + for (usz i = 0; i < ia; ++i) { + u32 c = o2c(GetU(x,i)); + res+= 1+(c > 0xFFFF); + } + return res; +} + +FORCE_INLINE void utf16_w(WCHAR** buf_i, u32 c) +{ + WCHAR* buf = *buf_i; + if (c<=0xFFFF) { + *buf++ = c; + } else { + assert(c <= 0x10FFFF); + *buf++ = ((c-0x10000) >> 10)+0xD800; + *buf++ = ((c-0x10000)&0x3FF)+0xDC00; + } + *buf_i = buf; +} + +void toUTF16(B x, WCHAR* p) { + SGetU(x) + usz ia = IA(x); + for (u64 i = 0; i < ia; ++i) utf16_w(&p, o2cG(GetU(x,i))); +} + +B utf16Decode(const WCHAR* s, i64 len) { +#define UTF16_MASK 0xFC00 +#define UTF16_IS_HI(WC) ((UTF16_MASK&(WC))==0xD800) /* 0xD800..0xDBFF */ +#define UTF16_IS_LO(WC) ((UTF16_MASK&(WC))==0xDC00) /* 0xDC00..0xDFFF */ +#define UTF16_SURROGATE(HI, LO) (0x10000+(((HI)-0xD800) << 10)+((LO)-0xDC00)) + u64 sz = 0; + for (i64 j = 0; ; ++j) { + if (j>=len) { + if (j!=len) assert(0); + break; + } + if (UTF16_IS_HI(s[j]) && j+1 Date: Tue, 7 Jan 2025 03:02:16 +0000 Subject: [PATCH 2/7] Windows: sh using utf16; simply argument quoting --- src/builtins/sysfn.c | 52 ++++++++++++++++++----------- src/windows/sh.c | 79 +++++++++----------------------------------- 2 files changed, 47 insertions(+), 84 deletions(-) diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 10f758d9..b6e59639 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -1154,31 +1154,43 @@ static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_er #elif defined(_WIN32) || defined(_WIN64) #define HAS_SH 1 #include "../windows/winError.c" +#include "../windows/utf16.c" #include "../windows/sh.c" static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_errp) { // allocate args - u64 arglen = 0; + TSALLOC(WCHAR, arg, 8); SGetU(x) for (u64 i = 0; i < xia; i++) { B c = GetU(x, i); if (isAtm(c) || RNK(c)!=1) thrM("•SH: 𝕩 must be a list of strings"); - u64 len = utf8lenB(c); - arglen += 1+2+2*len; - // space or 0, quotes, worst-case scenario (every character needs escaping) - } - TALLOC(char, arg, arglen); - char* pos = arg; - for (u64 i = 0; i < xia; i++) { - B c = GetU(x, i); - u64 len = utf8lenB(c); - TALLOC(char, cstr, len+1); - toUTF8(c, cstr); - cstr[len] = 0; - pos = winQuoteCmdArg(len, cstr, pos); - *(pos++) = (xia==i+1)? '\0' : ' '; - TFREE(cstr) - assert(pos <= arg+arglen); + u64 len = utf16lenB(c); + TALLOC(WCHAR, wstr, len); + toUTF16(c, wstr); + + // https://learn.microsoft.com/en-gb/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way + u64 backslashes = 0; + bool quote = len==0 || NULL!=wcspbrk(wstr, L" \t\n\v\""); + if (quote) { TSADD(arg, L'\"'); } + for (u64 j = 0; j < len; ++j) { + WCHAR x = wstr[j]; + if (x==L'\\') { + backslashes += 1; + } else { + if (x==L'\"') { + for (u64 k = 0; k < 1+backslashes; ++k) { TSADD(arg, L'\\'); } + } + backslashes = 0; + } + TSADD(arg, x); + } + if (quote) { + for (u64 k = 0; k < backslashes; ++k) { TSADD(arg, L'\\'); } + TSADD(arg, L'\"'); + } + + TSADD(arg, (xia==i+1)? L'\0' : L' '); + TFREE(wstr); } // allocate stdin @@ -1200,7 +1212,7 @@ static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_er u64 eLen = 0; char* eBuf; DWORD dwResult = winCmd(arg, iLen, iBuf, &code, &oLen, &oBuf, &eLen, &eBuf); if (iLen>0) { if (raw) free_chars(iBufRaw); else TFREE(iBuf); } // FREE_INPUT - TFREE(arg) + TSFREE(arg); if (dwResult != ERROR_SUCCESS) { thrF("•SH: Failed to run command: %S", winErrorEx(dwResult)); } @@ -1208,8 +1220,8 @@ static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_er // prepare output u8* op; *s_outp = m_c8arrv(&op, oLen); u8* ep; *s_errp = m_c8arrv(&ep, eLen); - if (oLen > 0 && oBuf != NULL) memcpy(op, oBuf, oLen*sizeof(char)); free(oBuf); - if (eLen > 0 && eBuf != NULL) memcpy(ep, eBuf, eLen*sizeof(char)); free(eBuf); + if (oBuf!=NULL) { memcpy(op, oBuf, oLen*sizeof(char)); TFREE(oBuf); } + if (eBuf!=NULL) { memcpy(ep, eBuf, eLen*sizeof(char)); TFREE(eBuf); } return (i32)code; } #else diff --git a/src/windows/sh.c b/src/windows/sh.c index 56654a53..66fbe6a2 100644 --- a/src/windows/sh.c +++ b/src/windows/sh.c @@ -1,48 +1,5 @@ #include - -// https://github.com/libuv/libuv/blob/v1.23.0/src/win/process.c#L454-L524 - -static char* winQuoteCmdArg(u64 len, char* source, char* target) { - if (len == 0) { - // Need double quotation for empty argument - *(target++) = '"'; - *(target++) = '"'; - return target; - } - if (NULL == strpbrk(source, " \t\"")) { - // No quotation needed - memcpy(target, source, len * sizeof(char)); target += len; - return target; - } - if (NULL == strpbrk(source, "\"\\")) { - // No embedded double quotes or backlashes, so I can just wrap - // quote marks around the whole thing. - *(target++) = '"'; - memcpy(target, source, len * sizeof(char)); target += len; - *(target++) = '"'; - return target; - } - - *(target++) = '"'; - char *start = target; - int quote_hit = 1; - - for (u64 i = 0; i < len; ++i) { - *(target++) = source[len - 1 - i]; - - if (quote_hit && source[len - 1 - i] == '\\') { - *(target++) = '\\'; - } else if (source[len - 1 - i] == '"') { - quote_hit = 1; - *(target++) = '\\'; - } else { - quote_hit = 0; - } - } - target[0] = '\0'; _strrev(start); - *(target++) = '"'; - return target; -} +#include "../utils/talloc.h" typedef struct { HANDLE hndl; @@ -74,8 +31,8 @@ static DWORD WINAPI winThreadRead(LPVOID arg0) { HANDLE hndl = arg->hndl; u8 buf[1024] = {0}; const usz bufSize = sizeof(buf)/sizeof(u8); - DWORD dwRead = 0, dwHasRead = 0; - char* rBuf = NULL; + DWORD dwRead = 0; + TSALLOC(char, rBuf, 8); for (;;) { ZeroMemory(buf, bufSize); @@ -85,26 +42,20 @@ static DWORD WINAPI winThreadRead(LPVOID arg0) { if (dwErr == ERROR_BROKEN_PIPE) { break; } else { dwResult = dwErr; break; } } - char* newBuf = (rBuf==NULL)? - calloc(dwHasRead+dwRead, sizeof(char)) : - realloc(rBuf, (dwHasRead+dwRead)*sizeof(char)); - if (newBuf == NULL) { dwResult = GetLastError(); break; } - rBuf = newBuf; - memcpy(&rBuf[dwHasRead], buf, dwRead); - dwHasRead += dwRead; + TSADDA(rBuf, buf, dwRead); } - if (dwResult != ERROR_SUCCESS) { - if (dwHasRead > 0 && rBuf != NULL) { free(rBuf); } - } else { - arg->buf = rBuf; - arg->len = dwHasRead; + if (dwResult == ERROR_SUCCESS) { + arg->len = TSSIZE(rBuf); + arg->buf = TALLOCP(char, arg->len); + memcpy(arg->buf, rBuf, arg->len); } + TSFREE(rBuf); CloseHandle(hndl); return dwResult; } -static DWORD winCmd(char* arg, +static DWORD winCmd(WCHAR* arg, u64 iLen, char* iBuf, DWORD* code, u64* oLen, char** oBuf, @@ -117,7 +68,7 @@ static DWORD winCmd(char* arg, // Create pipes SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; @@ -130,9 +81,9 @@ static DWORD winCmd(char* arg, SetHandleInformation(hErrR, HANDLE_FLAG_INHERIT, 0); // Set up - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); + STARTUPINFOW si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); si.hStdInput = hInpR; si.hStdOutput = hOutW; si.hStdError = hErrW; @@ -142,7 +93,7 @@ static DWORD winCmd(char* arg, ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); // Create the child process - BOOL bSuccess = CreateProcessA(NULL, arg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); + BOOL bSuccess = CreateProcessW(NULL, arg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (!bSuccess) { return GetLastError(); } // Close the unneeded handles From 40609b2f5fd6de9af465d001de11cfd4be2a287a Mon Sep 17 00:00:00 2001 From: vylsaz Date: Sat, 11 Jan 2025 05:45:35 +0000 Subject: [PATCH 3/7] Windows: sh: revert to using calloc() in reading threads --- src/builtins/sysfn.c | 4 ++-- src/windows/sh.c | 32 ++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index b6e59639..e3851fba 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -1220,8 +1220,8 @@ static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_er // prepare output u8* op; *s_outp = m_c8arrv(&op, oLen); u8* ep; *s_errp = m_c8arrv(&ep, eLen); - if (oBuf!=NULL) { memcpy(op, oBuf, oLen*sizeof(char)); TFREE(oBuf); } - if (eBuf!=NULL) { memcpy(ep, eBuf, eLen*sizeof(char)); TFREE(eBuf); } + if (oBuf!=NULL) { memcpy(op, oBuf, oLen*sizeof(char)); free(oBuf); } + if (eBuf!=NULL) { memcpy(ep, eBuf, eLen*sizeof(char)); free(eBuf); } return (i32)code; } #else diff --git a/src/windows/sh.c b/src/windows/sh.c index 66fbe6a2..e56d47dc 100644 --- a/src/windows/sh.c +++ b/src/windows/sh.c @@ -1,5 +1,4 @@ #include -#include "../utils/talloc.h" typedef struct { HANDLE hndl; @@ -29,28 +28,33 @@ static DWORD WINAPI winThreadRead(LPVOID arg0) { DWORD dwResult = ERROR_SUCCESS; ThreadIO* arg = arg0; HANDLE hndl = arg->hndl; - u8 buf[1024] = {0}; + u8 buf[4096] = {0}; const usz bufSize = sizeof(buf)/sizeof(u8); - DWORD dwRead = 0; - TSALLOC(char, rBuf, 8); - + DWORD dwRead = 0, dwHasRead = 0; + char* rBuf = NULL; for (;;) { ZeroMemory(buf, bufSize); BOOL bOk = ReadFile(hndl, buf, bufSize, &dwRead, NULL); + if (dwRead == 0) { break; } if (!bOk) { - DWORD dwErr = GetLastError(); - if (dwErr == ERROR_BROKEN_PIPE) { break; } - else { dwResult = dwErr; break; } + dwResult = GetLastError(); + break; } - TSADDA(rBuf, buf, dwRead); + char* newBuf = (rBuf == NULL)? + calloc(dwHasRead+dwRead, sizeof(char)) : + realloc(rBuf, (dwHasRead+dwRead)*sizeof(char)); + if (newBuf == NULL) { dwResult = GetLastError(); break; } + rBuf = newBuf; + memcpy(&rBuf[dwHasRead], buf, dwRead); + dwHasRead += dwRead; } - if (dwResult == ERROR_SUCCESS) { - arg->len = TSSIZE(rBuf); - arg->buf = TALLOCP(char, arg->len); - memcpy(arg->buf, rBuf, arg->len); + if (dwResult != ERROR_SUCCESS) { + if (rBuf != NULL) { free(rBuf); } + } else { + arg->buf = rBuf; + arg->len = dwHasRead; } - TSFREE(rBuf); CloseHandle(hndl); return dwResult; } From e12ca55ee0579407e1fa715f441f9c9bf2c611b7 Mon Sep 17 00:00:00 2001 From: vylsaz Date: Sat, 11 Jan 2025 05:46:39 +0000 Subject: [PATCH 4/7] Windows: use utf16 for file functions --- src/utils/file.c | 58 ++++++++++++++++++++++++++++++++++++--------- src/windows/utf16.c | 8 +++---- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/utils/file.c b/src/utils/file.c index 1588b27c..ab3691d0 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -9,13 +9,26 @@ #if defined(_WIN32) || defined(_WIN64) #include #include "../windows/realpath.c" + #include "../windows/utf16.c" + // use wide char functions for unicode support / longer paths (potentially) + // opendir() is provided by mingw and does unicode convertion already #endif FILE* file_open(B path, char* desc, char* mode) { // doesn't consume +#if !defined(_WIN32) char* p = toCStr(path); FILE* f = fopen(p, mode); freeCStr(p); +#else + WCHAR wmode[8] = {0}; + u64 len = strlen(mode); + assert(len<(sizeof(wmode)/sizeof(WCHAR))); + for (u64 i = 0; ia = data; #if !defined(_WIN32) @@ -379,39 +393,61 @@ void mmap_init() { } #include bool dir_create(B path) { +#if !defined(_WIN32) char* p = toCStr(path); - #if defined(_WIN32) || defined(_WIN64) - bool r = _mkdir(p) == 0; - #else - bool r = mkdir(p, S_IRWXU) == 0; - #endif + bool r = mkdir(p, S_IRWXU) == 0; freeCStr(p); +#else + WCHAR* p = toWStr(path); + bool r = _wmkdir(p) == 0; + freeWStr(p); +#endif return r; } bool path_rename(B old_path, B new_path) { +#if !defined(_WIN32) char* old = toCStr(old_path); char* new = toCStr(new_path); // TODO Fix race condition, e.g., with renameat2 on Linux, etc. bool ok = access(new, F_OK) != 0 && rename(old, new) == 0; freeCStr(new); freeCStr(old); +#else + WCHAR* old = toWStr(old_path); + WCHAR* new = toWStr(new_path); + bool ok = _waccess(new, F_OK) != 0 && _wrename(old, new) == 0; + freeWStr(new); + freeWStr(old); +#endif dec(old_path); return ok; } bool path_remove(B path) { +#if !defined(_WIN32) char* p = toCStr(path); bool ok = unlink(p) == 0; freeCStr(p); +#else + WCHAR* p = toWStr(path); + bool ok = _wunlink(p) == 0; + freeWStr(p); +#endif dec(path); return ok; } int path_stat(struct stat* s, B path) { // doesn't consume; get stat of s; errors if path isn't string; returns non-zero on failure +#if !defined(_WIN32) char* p = toCStr(path); int r = stat(p, s); freeCStr(p); +#else + WCHAR* p = toWStr(path); + int r = wstat(p, s); + freeWStr(p); +#endif return r; } diff --git a/src/windows/utf16.c b/src/windows/utf16.c index 99cbc642..d606b40f 100644 --- a/src/windows/utf16.c +++ b/src/windows/utf16.c @@ -26,13 +26,13 @@ FORCE_INLINE void utf16_w(WCHAR** buf_i, u32 c) *buf_i = buf; } -void toUTF16(B x, WCHAR* p) { +static void toUTF16(B x, WCHAR* p) { SGetU(x) usz ia = IA(x); for (u64 i = 0; i < ia; ++i) utf16_w(&p, o2cG(GetU(x,i))); } -B utf16Decode(const WCHAR* s, i64 len) { +static B utf16Decode(const WCHAR* s, i64 len) { #define UTF16_MASK 0xFC00 #define UTF16_IS_HI(WC) ((UTF16_MASK&(WC))==0xD800) /* 0xD800..0xDBFF */ #define UTF16_IS_LO(WC) ((UTF16_MASK&(WC))==0xDC00) /* 0xDC00..0xDFFF */ @@ -64,13 +64,13 @@ B utf16Decode(const WCHAR* s, i64 len) { #undef UTF16_SURROGATE } -static WCHAR* toWideStr(B x) { // doesn't consume +static WCHAR* toWStr(B x) { // doesn't consume u64 len = utf16lenB(x); TALLOC(WCHAR, p, len+1); toUTF16(x, p); p[len] = 0; return p; } -static void freeWideStr(WCHAR* p) { +static void freeWStr(WCHAR* p) { TFREE(p); } From 24bd6735bc85e72d54f3787bff3b26c7c36544d3 Mon Sep 17 00:00:00 2001 From: vylsaz Date: Sat, 11 Jan 2025 18:08:33 +0000 Subject: [PATCH 5/7] Windows: use _wfullpath for realpath --- src/windows/realpath.c | 9 +++------ src/windows/realpath.h | 7 ------- 2 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 src/windows/realpath.h diff --git a/src/windows/realpath.c b/src/windows/realpath.c index 50a9528f..f3a3fce0 100644 --- a/src/windows/realpath.c +++ b/src/windows/realpath.c @@ -1,9 +1,6 @@ - -#include "realpath.h" - -char* realpath (const char *__restrict path, char *__restrict resolved_path) { - return _fullpath(NULL, path, 0); +WCHAR* realpath (const WCHAR*__restrict path, WCHAR*__restrict resolved_path) { + return _wfullpath(NULL, path, 0); } bool winIsAbsolute(const char* path) { // TODO something more proper return *path && path[1]==':' && (!path[2] || path[2]=='/' || path[2]=='\\'); -} \ No newline at end of file +} diff --git a/src/windows/realpath.h b/src/windows/realpath.h deleted file mode 100644 index bfe555c7..00000000 --- a/src/windows/realpath.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef REALPATH_H -#define REALPATH_H - -char* realpath(const char *__restrict path, char *__restrict resolved_path); -bool winIsAbsolute(const char* path); - -#endif /* REALPATH_H */ \ No newline at end of file From 7d928a3221d4f057730d0f9d2f36249695afb81e Mon Sep 17 00:00:00 2001 From: vylsaz Date: Sat, 11 Jan 2025 18:09:47 +0000 Subject: [PATCH 6/7] Use OsStr for path on both Windows and non-Windows systems --- src/utils/file.c | 93 +++++++++++++++++++++------------------------ src/windows/utf16.c | 4 ++ 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/utils/file.c b/src/utils/file.c index ab3691d0..f60cd4bc 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -6,14 +6,35 @@ #include #include -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) #include - #include "../windows/realpath.c" #include "../windows/utf16.c" // use wide char functions for unicode support / longer paths (potentially) - // opendir() is provided by mingw and does unicode convertion already + #include "../windows/realpath.c" #endif +#if !defined(_WIN32) + typedef char* OsStr; + #define OS_C(C) C + #define toOsStr toCStr + #define freeOsStr freeCStr + #define OsStrDecode0 utf8Decode0 +#else + typedef WCHAR* OsStr; + #define OS_C(C) L##C + #define toOsStr toWStr + #define freeOsStr freeWStr + #define OsStrDecode0 utf16Decode0 + #define DIR _WDIR + #define dirent _wdirent + #define opendir _wopendir + #define readdir _wreaddir + #define closedir _wclosedir + #define mkdir(P, IGNORE) _wmkdir(P) + #define access _waccess + #define rename _wrename + #define unlink _wunlink +#endif FILE* file_open(B path, char* desc, char* mode) { // doesn't consume #if !defined(_WIN32) @@ -33,12 +54,9 @@ FILE* file_open(B path, char* desc, char* mode) { // doesn't consume return f; } static DIR* dir_open(B path) { // doesn't consume - u64 plen = utf8lenB(path); - TALLOC(char, p, plen+1); - toUTF8(path, p); - p[plen] = 0; + OsStr p = toOsStr(path); DIR* f = opendir(p); - TFREE(p); + freeOsStr(p); if (f==NULL) thrF("Couldn't open directory \"%R\"", path); return f; } @@ -184,16 +202,13 @@ B path_abs(B path) { return path; // lazy #else if (q_N(path)) return path; - u64 plen = utf8lenB(path); - TALLOC(char, p, plen+1); - toUTF8(path, p); - p[plen] = 0; - char* res = realpath(p, NULL); + OsStr p = toOsStr(path); + OsStr res = realpath(p, NULL); if (res==NULL) thrF("Failed to resolve \"%R\": %S", path, strerror(errno)); - B r = utf8Decode0(res); + B r = OsStrDecode0(res); free(res); dec(path); - TFREE(p); + freeOsStr(p); return r; #endif } @@ -264,8 +279,10 @@ B path_list(B path) { struct dirent *c; B res = emptySVec(); while ((c = readdir(d)) != NULL) { - char* name = c->d_name; - if (name[0]=='.'? !(name[1]==0 || (name[1]=='.'&&name[2]==0)) : true) res = vec_addN(res, utf8Decode(name, strlen(name))); + OsStr name = c->d_name; + if (name[0]==OS_C('.')? !(name[1]==0 || (name[1]==OS_C('.')&&name[2]==0)) : true) { + res = vec_addN(res, OsStrDecode0(name)); + } } closedir(d); dec(path); @@ -393,61 +410,39 @@ void mmap_init() { } #include bool dir_create(B path) { -#if !defined(_WIN32) - char* p = toCStr(path); + OsStr p = toOsStr(path); bool r = mkdir(p, S_IRWXU) == 0; - freeCStr(p); -#else - WCHAR* p = toWStr(path); - bool r = _wmkdir(p) == 0; - freeWStr(p); -#endif + freeOsStr(p); return r; } bool path_rename(B old_path, B new_path) { -#if !defined(_WIN32) - char* old = toCStr(old_path); - char* new = toCStr(new_path); + OsStr old = toOsStr(old_path); + OsStr new = toOsStr(new_path); // TODO Fix race condition, e.g., with renameat2 on Linux, etc. bool ok = access(new, F_OK) != 0 && rename(old, new) == 0; - freeCStr(new); - freeCStr(old); -#else - WCHAR* old = toWStr(old_path); - WCHAR* new = toWStr(new_path); - bool ok = _waccess(new, F_OK) != 0 && _wrename(old, new) == 0; - freeWStr(new); - freeWStr(old); -#endif + freeOsStr(new); + freeOsStr(old); dec(old_path); return ok; } bool path_remove(B path) { -#if !defined(_WIN32) - char* p = toCStr(path); + OsStr p = toOsStr(path); bool ok = unlink(p) == 0; - freeCStr(p); -#else - WCHAR* p = toWStr(path); - bool ok = _wunlink(p) == 0; - freeWStr(p); -#endif + freeOsStr(p); dec(path); return ok; } int path_stat(struct stat* s, B path) { // doesn't consume; get stat of s; errors if path isn't string; returns non-zero on failure + OsStr p = toOsStr(path); #if !defined(_WIN32) - char* p = toCStr(path); int r = stat(p, s); - freeCStr(p); #else - WCHAR* p = toWStr(path); int r = wstat(p, s); - freeWStr(p); #endif + freeOsStr(p); return r; } diff --git a/src/windows/utf16.c b/src/windows/utf16.c index d606b40f..1ad28383 100644 --- a/src/windows/utf16.c +++ b/src/windows/utf16.c @@ -64,6 +64,10 @@ static B utf16Decode(const WCHAR* s, i64 len) { #undef UTF16_SURROGATE } +static B utf16Decode0(const WCHAR* s) { + return utf16Decode(s, wcslen(s)); +} + static WCHAR* toWStr(B x) { // doesn't consume u64 len = utf16lenB(x); TALLOC(WCHAR, p, len+1); From 517300e567f2aab2572e8a432cfd133e214704f1 Mon Sep 17 00:00:00 2001 From: dzaima Date: Thu, 16 Jan 2025 21:41:26 +0200 Subject: [PATCH 7/7] Windows: static-method-only .c files to .h --- src/builtins/sysfn.c | 6 +++--- src/utils/file.c | 4 ++-- src/windows/{sh.c => sh.h} | 0 src/windows/{utf16.c => utf16.h} | 0 src/windows/{winError.c => winError.h} | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename src/windows/{sh.c => sh.h} (100%) rename src/windows/{utf16.c => utf16.h} (100%) rename src/windows/{winError.c => winError.h} (100%) diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index e3851fba..392aa518 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -1153,9 +1153,9 @@ static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_er } #elif defined(_WIN32) || defined(_WIN64) #define HAS_SH 1 -#include "../windows/winError.c" -#include "../windows/utf16.c" -#include "../windows/sh.c" +#include "../windows/winError.h" +#include "../windows/utf16.h" +#include "../windows/sh.h" static i32 sh_core(bool raw, B x, usz xia, B inObj, u64 iLen, B* s_outp, B* s_errp) { // allocate args diff --git a/src/utils/file.c b/src/utils/file.c index f60cd4bc..92306fc0 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -8,7 +8,7 @@ #if defined(_WIN32) #include - #include "../windows/utf16.c" + #include "../windows/utf16.h" // use wide char functions for unicode support / longer paths (potentially) #include "../windows/realpath.c" #endif @@ -297,7 +297,7 @@ B path_list(B path) { #include #else #include -#include "../windows/winError.c" +#include "../windows/winError.h" #endif typedef struct MmapHolder { diff --git a/src/windows/sh.c b/src/windows/sh.h similarity index 100% rename from src/windows/sh.c rename to src/windows/sh.h diff --git a/src/windows/utf16.c b/src/windows/utf16.h similarity index 100% rename from src/windows/utf16.c rename to src/windows/utf16.h diff --git a/src/windows/winError.c b/src/windows/winError.h similarity index 100% rename from src/windows/winError.c rename to src/windows/winError.h