From 9dd65bc70addc4b12b178aad056e77f1355408b9 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 29 Sep 2025 20:07:19 -0600 Subject: [PATCH] More msvcrt (WIP quality) and various fixes --- common.h | 13 +- dll/advapi32.cpp | 26 +- dll/crt.cpp | 110 +++- dll/kernel32.cpp | 26 +- dll/lmgr.cpp | 4 +- dll/mscoree.cpp | 11 +- dll/msvcrt.cpp | 1370 ++++++++++++++++++++++++++++++++++++++++++++-- files.cpp | 2 +- processes.cpp | 12 + 9 files changed, 1466 insertions(+), 108 deletions(-) diff --git a/common.h b/common.h index 071b8ed..4361b60 100644 --- a/common.h +++ b/common.h @@ -19,7 +19,18 @@ // force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment. #define WIN_ENTRY __attribute__((force_align_arg_pointer, callee_pop_aggregate_return(0))) #define WIN_FUNC WIN_ENTRY __attribute__((stdcall)) -#define DEBUG_LOG(...) wibo::debug_log(__VA_ARGS__) +#define DEBUG_LOG(...) \ + do { \ + if (wibo::debugEnabled) { \ + wibo::debug_log(__VA_ARGS__); \ + } \ + } while (0) + +#ifndef NDEBUG +#define VERBOSE_LOG(...) DEBUG_LOG(__VA_ARGS__) +#else +#define VERBOSE_LOG(...) ((void)0) +#endif typedef void *HANDLE; typedef void *HMODULE; diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index 8c0a2f6..03039a2 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -286,18 +286,18 @@ namespace { namespace advapi32 { unsigned int WIN_FUNC RegOpenKeyExA(void *hKey, const char *lpSubKey, unsigned int ulOptions, void *samDesired, void **phkResult) { - DEBUG_LOG("RegOpenKeyExA(key=%p, subkey=%s, ...)\n", hKey, lpSubKey); + DEBUG_LOG("STUB: RegOpenKeyExA(%p, %s, ...)\n", hKey, lpSubKey); return 1; // screw them for now } BOOL WIN_FUNC CryptReleaseContext(void* hProv, unsigned int dwFlags) { - DEBUG_LOG("STUB: CryptReleaseContext %p %u\n", hProv, dwFlags); + DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", hProv, dwFlags); return TRUE; } BOOL WIN_FUNC CryptAcquireContextW(void **phProv, const uint16_t *pszContainer, const uint16_t *pszProvider, unsigned int dwProvType, unsigned int dwFlags) { - DEBUG_LOG("STUB: CryptAcquireContextW(%p)\n", phProv); + DEBUG_LOG("STUB: CryptAcquireContextW(%p, %p, %p, %u, %u)\n", phProv, pszContainer, pszProvider, dwProvType, dwFlags); // to quote the guy above me: screw them for now static int lmao = 42; @@ -310,7 +310,7 @@ namespace advapi32 { } BOOL WIN_FUNC CryptGenRandom(void* hProv, unsigned int dwLen, unsigned char* pbBuffer){ - DEBUG_LOG("STUB: CryptGenRandom(%p)\n", hProv); + DEBUG_LOG("CryptGenRandom(%p)\n", hProv); if (!pbBuffer || dwLen == 0) return FALSE; ssize_t ret = getrandom(pbBuffer, dwLen, 0); @@ -322,7 +322,7 @@ namespace advapi32 { } BOOL WIN_FUNC CryptCreateHash(void* hProv, unsigned int Algid, void* hKey, unsigned int dwFlags, void** phHash) { - DEBUG_LOG("CryptCreateHash(Algid=0x%x)\n", Algid); + DEBUG_LOG("CryptCreateHash(%p, %u, %p, %u, %p)\n", hProv, Algid, hKey, dwFlags, phHash); (void)hProv; if (!phHash) { wibo::lastError = ERROR_INVALID_PARAMETER; @@ -351,7 +351,7 @@ namespace advapi32 { } BOOL WIN_FUNC CryptHashData(void* hHash, const unsigned char* pbData, unsigned int dwDataLen, unsigned int dwFlags) { - DEBUG_LOG("CryptHashData(%p, %u bytes)\n", hHash, dwDataLen); + DEBUG_LOG("CryptHashData(%p, %p, %u, %u)\n", hHash, pbData, dwDataLen, dwFlags); if (!hHash || (dwDataLen && !pbData) || dwFlags != 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; @@ -367,7 +367,7 @@ namespace advapi32 { } BOOL WIN_FUNC CryptGetHashParam(void* hHash, unsigned int dwParam, unsigned char* pbData, unsigned int* pdwDataLen, unsigned int dwFlags) { - DEBUG_LOG("CryptGetHashParam(%p, param=0x%x)\n", hHash, dwParam); + DEBUG_LOG("CryptGetHashParam(%p, %u, %p, %p, %u)\n", hHash, dwParam, pbData, pdwDataLen, dwFlags); if (!hHash || !pdwDataLen || dwFlags != 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; @@ -458,7 +458,7 @@ namespace advapi32 { } BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle) { - DEBUG_LOG("OpenProcessToken(process=%p, access=0x%x)\n", ProcessHandle, DesiredAccess); + DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle); if (!TokenHandle) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; @@ -480,7 +480,8 @@ namespace advapi32 { } BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, unsigned int TokenInformationClass, void *TokenInformation, unsigned int TokenInformationLength, unsigned int *ReturnLength) { - DEBUG_LOG("GetTokenInformation(%p, class=%u, len=%u)\n", TokenHandle, TokenInformationClass, TokenInformationLength); + DEBUG_LOG("GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation, + TokenInformationLength, ReturnLength); if (!ReturnLength) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; @@ -547,10 +548,11 @@ namespace advapi32 { } BOOL WIN_FUNC LookupAccountSidW(const uint16_t *lpSystemName, const void *sidPointer, uint16_t *Name, - unsigned long *cchName, uint16_t *ReferencedDomainName, - unsigned long *cchReferencedDomainName, SID_NAME_USE *peUse) { + unsigned long *cchName, uint16_t *ReferencedDomainName, + unsigned long *cchReferencedDomainName, SID_NAME_USE *peUse) { std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)"); - DEBUG_LOG("LookupAccountSidW(system=%s, sid=%p)\n", systemName.c_str(), sidPointer); + DEBUG_LOG("LookupAccountSidW(%s, %p, %p, %p, %p, %p, %p)\n", systemName.c_str(), sidPointer, Name, cchName, + ReferencedDomainName, cchReferencedDomainName, peUse); (void) lpSystemName; // Only local lookup supported if (!sidPointer || !cchName || !cchReferencedDomainName || !peUse) { wibo::lastError = ERROR_INVALID_PARAMETER; diff --git a/dll/crt.cpp b/dll/crt.cpp index f89b963..7a06545 100644 --- a/dll/crt.cpp +++ b/dll/crt.cpp @@ -40,16 +40,20 @@ std::vector<_PVFV> atexitFuncs; _invalid_parameter_handler invalidParameterHandler = nullptr; void WIN_ENTRY _initterm(const _PVFV *ppfn, const _PVFV *end) { + DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end); do { if (_PVFV pfn = *++ppfn) { + DEBUG_LOG("-> calling %p\n", pfn); pfn(); } } while (ppfn < end); } int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) { + DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end); do { if (_PIFV pfn = *++ppfn) { + DEBUG_LOG("-> calling %p\n", pfn); if (int err = pfn()) return err; } @@ -66,9 +70,15 @@ int WIN_ENTRY _set_fmode(int mode) { return 0; } -int *WIN_ENTRY __p__commode() { return &_commode; } +int *WIN_ENTRY __p__commode() { + DEBUG_LOG("__p__commode()\n"); + return &_commode; +} -int *WIN_ENTRY __p__fmode() { return &_fmode; } +int *WIN_ENTRY __p__fmode() { + DEBUG_LOG("__p__fmode()\n"); + return &_fmode; +} int WIN_ENTRY _crt_atexit(void (*func)()) { DEBUG_LOG("_crt_atexit(%p)\n", func); @@ -108,37 +118,85 @@ int WIN_ENTRY _set_new_mode(int newhandlermode) { return 0; } -char **WIN_ENTRY _get_initial_narrow_environment() { return environ; } +char **WIN_ENTRY _get_initial_narrow_environment() { + DEBUG_LOG("_get_initial_narrow_environment()\n"); + return environ; +} -char ***WIN_ENTRY __p__environ() { return &environ; } +char ***WIN_ENTRY __p__environ() { + DEBUG_LOG("__p__environ()\n"); + return &environ; +} -char ***WIN_ENTRY __p___argv() { return &wibo::argv; } +char ***WIN_ENTRY __p___argv() { + DEBUG_LOG("__p___argv()\n"); + return &wibo::argv; +} -int *WIN_ENTRY __p___argc() { return &wibo::argc; } +int *WIN_ENTRY __p___argc() { + DEBUG_LOG("__p___argc()\n"); + return &wibo::argc; +} -size_t WIN_ENTRY strlen(const char *str) { return ::strlen(str); } +size_t WIN_ENTRY strlen(const char *str) { + VERBOSE_LOG("strlen(%p)\n", str); + return ::strlen(str); +} -int WIN_ENTRY strcmp(const char *lhs, const char *rhs) { return ::strcmp(lhs, rhs); } +int WIN_ENTRY strcmp(const char *lhs, const char *rhs) { + VERBOSE_LOG("strcmp(%p, %p)\n", lhs, rhs); + return ::strcmp(lhs, rhs); +} -int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { return ::strncmp(lhs, rhs, count); } +int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { + VERBOSE_LOG("strncmp(%p, %p, %zu)\n", lhs, rhs, count); + return ::strncmp(lhs, rhs, count); +} -char *WIN_ENTRY strcpy(char *dest, const char *src) { return ::strcpy(dest, src); } +char *WIN_ENTRY strcpy(char *dest, const char *src) { + VERBOSE_LOG("strcpy(%p, %p)\n", dest, src); + return ::strcpy(dest, src); +} -void *WIN_ENTRY malloc(size_t size) { return ::malloc(size); } +void *WIN_ENTRY malloc(size_t size) { + VERBOSE_LOG("malloc(%zu)\n", size); + return ::malloc(size); +} -void *WIN_ENTRY calloc(size_t count, size_t size) { return ::calloc(count, size); } +void *WIN_ENTRY calloc(size_t count, size_t size) { + VERBOSE_LOG("calloc(%zu, %zu)\n", count, size); + return ::calloc(count, size); +} -void *WIN_ENTRY realloc(void *ptr, size_t newSize) { return ::realloc(ptr, newSize); } +void *WIN_ENTRY realloc(void *ptr, size_t newSize) { + VERBOSE_LOG("realloc(%p, %zu)\n", ptr, newSize); + return ::realloc(ptr, newSize); +} -void WIN_ENTRY free(void *ptr) { ::free(ptr); } +void WIN_ENTRY free(void *ptr) { + VERBOSE_LOG("free(%p)\n", ptr); + ::free(ptr); +} -void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) { return std::memcpy(dest, src, count); } +void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) { + VERBOSE_LOG("memcpy(%p, %p, %zu)\n", dest, src, count); + return std::memcpy(dest, src, count); +} -void *WIN_ENTRY memmove(void *dest, const void *src, size_t count) { return std::memmove(dest, src, count); } +void *WIN_ENTRY memmove(void *dest, const void *src, size_t count) { + VERBOSE_LOG("memmove(%p, %p, %zu)\n", dest, src, count); + return std::memmove(dest, src, count); +} -void *WIN_ENTRY memset(void *dest, int ch, size_t count) { return std::memset(dest, ch, count); } +void *WIN_ENTRY memset(void *dest, int ch, size_t count) { + VERBOSE_LOG("memset(%p, %i, %zu)\n", dest, ch, count); + return std::memset(dest, ch, count); +} -int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) { return std::memcmp(lhs, rhs, count); } +int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) { + VERBOSE_LOG("memcmp(%p, %p, %zu)\n", lhs, rhs, count); + return std::memcmp(lhs, rhs, count); +} int WIN_ENTRY __setusermatherr(void *handler) { DEBUG_LOG("STUB: __setusermatherr(%p)\n", handler); @@ -192,9 +250,13 @@ void WIN_ENTRY abort(void) { using signal_handler = void (*)(int); -signal_handler WIN_ENTRY signal(int signum, signal_handler handler) { return std::signal(signum, handler); } +signal_handler WIN_ENTRY signal(int signum, signal_handler handler) { + DEBUG_LOG("signal(%i, %p)\n", signum, handler); + return std::signal(signum, handler); +} void *WIN_ENTRY __acrt_iob_func(unsigned int index) { + DEBUG_LOG("__acrt_iob_func(%u)\n", index); if (index == 0) return stdin; if (index == 1) @@ -204,13 +266,15 @@ void *WIN_ENTRY __acrt_iob_func(unsigned int index) { return nullptr; } -int WIN_ENTRY __stdio_common_vfprintf(unsigned long long /*options*/, FILE *stream, const char *format, - void * /*locale*/, va_list args) { +int WIN_ENTRY __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale, + va_list args) { + DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args); return vfprintf(stream, format, args); } -int WIN_ENTRY __stdio_common_vsprintf(unsigned long long /*options*/, char *buffer, size_t len, const char *format, - void * /*locale*/, va_list args) { +int WIN_ENTRY __stdio_common_vsprintf(unsigned long long options, char *buffer, size_t len, const char *format, + void *locale, va_list args) { + DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale); if (!buffer || !format) return -1; int result = vsnprintf(buffer, len, format, args); diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 661336a..bf7ef29 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -495,7 +495,7 @@ namespace kernel32 { } BOOL WIN_FUNC Wow64DisableWow64FsRedirection(void **OldValue) { - DEBUG_LOG("Wow64DisableWow64FsRedirection\n"); + DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection\n"); if (OldValue) { *OldValue = nullptr; } @@ -504,7 +504,7 @@ namespace kernel32 { } BOOL WIN_FUNC Wow64RevertWow64FsRedirection(void *OldValue) { - DEBUG_LOG("Wow64RevertWow64FsRedirection\n"); + DEBUG_LOG("STUB: Wow64RevertWow64FsRedirection\n"); (void) OldValue; wibo::lastError = ERROR_SUCCESS; return TRUE; @@ -523,6 +523,7 @@ namespace kernel32 { // @brief returns a pseudo handle to the current process void *WIN_FUNC GetCurrentProcess() { + DEBUG_LOG("STUB: GetCurrentProcess() -> %p\n", (void *) 0xFFFFFFFF); // pseudo handle is always returned, and is -1 (a special constant) return (void *) 0xFFFFFFFF; } @@ -530,15 +531,14 @@ namespace kernel32 { // @brief DWORD (unsigned int) returns a process identifier of the calling process. unsigned int WIN_FUNC GetCurrentProcessId() { uint32_t pid = getpid(); - DEBUG_LOG("Current processID is: %d\n", pid); - + DEBUG_LOG("GetCurrentProcessId() -> %d\n", pid); return pid; } unsigned int WIN_FUNC GetCurrentThreadId() { pthread_t thread_id; thread_id = pthread_self(); - DEBUG_LOG("Current thread ID is: %lu\n", thread_id); + DEBUG_LOG("GetCurrentThreadId() -> %lu\n", thread_id); // Cast thread_id to unsigned int to fit a DWORD unsigned int u_thread_id = (unsigned int) thread_id; @@ -547,7 +547,7 @@ namespace kernel32 { } void WIN_FUNC ExitProcess(unsigned int uExitCode) { - DEBUG_LOG("ExitProcess %d\n", uExitCode); + DEBUG_LOG("ExitProcess(%u)\n", uExitCode); exit(uExitCode); } @@ -680,9 +680,12 @@ namespace kernel32 { lpProcessInformation ); - std::string application = lpApplicationName ? lpApplicationName : ""; + bool useSearchPath = lpApplicationName == nullptr; + std::string application; std::vector arguments = processes::splitCommandLine(lpCommandLine); - if (application.empty()) { + if (lpApplicationName) { + application = lpApplicationName; + } else { if (arguments.empty()) { wibo::lastError = ERROR_FILE_NOT_FOUND; return 0; @@ -692,8 +695,13 @@ namespace kernel32 { if (arguments.empty()) { arguments.push_back(application); } + DEBUG_LOG(" -> args:"); + for (const auto &arg : arguments) { + DEBUG_LOG(" '%s'", arg.c_str()); + } + DEBUG_LOG("\n"); - auto resolved = processes::resolveExecutable(application, true); + auto resolved = processes::resolveExecutable(application, useSearchPath); if (!resolved) { wibo::lastError = ERROR_FILE_NOT_FOUND; return 0; diff --git a/dll/lmgr.cpp b/dll/lmgr.cpp index 4ed6d16..40c37c9 100644 --- a/dll/lmgr.cpp +++ b/dll/lmgr.cpp @@ -2,13 +2,13 @@ namespace lmgr { int WIN_ENTRY lp_checkout(int a, int b, const char* c, const char* d, int e, const char* f, int* out) { - DEBUG_LOG("lp_checkout %d %d %s %s %d %s\n", a, b, c, d, e, f); + DEBUG_LOG("lp_checkout(%d, %d, %s, %s, %d, %s)\n", a, b, c, d, e, f); *out = 1234; return 0; } int WIN_ENTRY lp_checkin() { - DEBUG_LOG("lp_checkin\n"); + DEBUG_LOG("lp_checkin()\n"); return 0; } } diff --git a/dll/mscoree.cpp b/dll/mscoree.cpp index deeb4f7..922bd46 100644 --- a/dll/mscoree.cpp +++ b/dll/mscoree.cpp @@ -1,14 +1,17 @@ #include "common.h" namespace mscoree { - void WIN_FUNC CorExitProcess(int exitCode) { - exit(exitCode); - } + +void WIN_FUNC CorExitProcess(int exitCode) { + DEBUG_LOG("CorExitProcess(%i)\n", exitCode); + exit(exitCode); } +} // namespace mscoree static void *resolveByName(const char *name) { - if (strcmp(name, "CorExitProcess") == 0) return (void *) mscoree::CorExitProcess; + if (strcmp(name, "CorExitProcess") == 0) + return (void *)mscoree::CorExitProcess; return nullptr; } diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index b72fb17..8702194 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +29,14 @@ #include #include #include +#include +#include +#include +#include +#include +#ifndef O_BINARY +#define O_BINARY 0 +#endif #include "files.h" #include "processes.h" #include "strutil.h" @@ -36,13 +47,164 @@ using _onexit_t = _PIFV; extern "C" char **environ; +struct _utimbuf { + long actime; + long modtime; +}; + +struct _timeb { + time_t time; + unsigned short millitm; + short timezone; + short dstflag; +}; + namespace msvcrt { int _commode; int _fmode; char** __initenv; uint16_t** __winitenv; - uint16_t* _wpgmptr; + uint16_t* _wpgmptr = nullptr; + char* _pgmptr = nullptr; + constexpr int MB_CP_ANSI = -3; + constexpr int MB_CP_OEM = -2; + constexpr int MB_CP_LOCALE = -4; + constexpr int MB_CP_SBCS = 0; + constexpr int MB_CP_UTF8 = -5; + static unsigned int mbCurMaxValue = 1; + static int mbCodePageSetting = MB_CP_ANSI; + static unsigned int floatingPointControlWord = 0x0009001F; // _CW_DEFAULT for x87 + + constexpr unsigned short PCTYPE_UPPER = 0x0001; + constexpr unsigned short PCTYPE_LOWER = 0x0002; + constexpr unsigned short PCTYPE_DIGIT = 0x0004; + constexpr unsigned short PCTYPE_SPACE = 0x0008; + constexpr unsigned short PCTYPE_PUNCT = 0x0010; + constexpr unsigned short PCTYPE_CONTROL = 0x0020; + constexpr unsigned short PCTYPE_BLANK = 0x0040; + constexpr unsigned short PCTYPE_HEX = 0x0080; + constexpr unsigned short PCTYPE_LEADBYTE = 0x8000; + + constexpr unsigned char _MS = 0x01; + constexpr unsigned char _MP = 0x02; + constexpr unsigned char _M1 = 0x04; + constexpr unsigned char _M2 = 0x08; + constexpr unsigned char _SBUP = 0x10; + constexpr unsigned char _SBLOW = 0x20; + + using ByteRange = std::pair; + + std::array &mbctypeTable() { + static std::array table = {}; + return table; + } + + template + void setMbctypeFlag(unsigned char flag, const std::array &ranges) { + auto &table = mbctypeTable(); + for (const auto &range : ranges) { + for (int value = range.first; value <= range.second; ++value) { + table[static_cast(value)] |= flag; + } + } + } + + unsigned int mbCurMaxForCodePage(int codepage); + + void updateMbctypeForCodePage(int codepage) { + auto &table = mbctypeTable(); + table.fill(0); + + switch (codepage) { + case 932: { + const std::array lead{{ByteRange{0x81, 0x9F}, ByteRange{0xE0, 0xFC}}}; + const std::array trail{{ByteRange{0x40, 0x7E}, ByteRange{0x80, 0xFC}}}; + setMbctypeFlag(_M1, lead); + setMbctypeFlag(_M2, trail); + break; + } + case 936: { + const std::array lead{{ByteRange{0x81, 0xFE}}}; + const std::array trail{{ByteRange{0x40, 0xFE}}}; + setMbctypeFlag(_M1, lead); + setMbctypeFlag(_M2, trail); + break; + } + case 949: { + const std::array lead{{ByteRange{0x81, 0xFE}}}; + const std::array trail{{ByteRange{0x41, 0x5A}, ByteRange{0x61, 0x7A}, ByteRange{0x81, 0xFE}}}; + setMbctypeFlag(_M1, lead); + setMbctypeFlag(_M2, trail); + break; + } + case 950: { + const std::array lead{{ByteRange{0x81, 0xFE}}}; + const std::array trail{{ByteRange{0x40, 0x7E}, ByteRange{0xA1, 0xFE}}}; + setMbctypeFlag(_M1, lead); + setMbctypeFlag(_M2, trail); + break; + } + case 1361: { + const std::array lead{{ByteRange{0x81, 0xFE}}}; + const std::array trail{{ByteRange{0x31, 0x7E}, ByteRange{0x81, 0xFE}}}; + setMbctypeFlag(_M1, lead); + setMbctypeFlag(_M2, trail); + break; + } + default: + break; + } + } + + std::once_flag &mbctypeInitFlag() { + static std::once_flag flag; + return flag; + } + + void ensureMbctypeInitialized() { + std::call_once(mbctypeInitFlag(), []() { + updateMbctypeForCodePage(mbCodePageSetting); + mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); + }); + } + + bool isLeadByte(unsigned char byte) { + ensureMbctypeInitialized(); + return (mbctypeTable()[byte] & _M1) != 0; + } + + bool isTrailByte(unsigned char byte) { + ensureMbctypeInitialized(); + return (mbctypeTable()[byte] & _M2) != 0; + } + + std::once_flag &pctypeInitFlag() { + static std::once_flag flag; + return flag; + } + + std::array &pctypeTable() { + static std::array table = {}; + std::call_once(pctypeInitFlag(), []() { + table[0] = 0; + for (int i = 0; i < 256; ++i) { + unsigned short flags = 0; + unsigned char ch = static_cast(i); + if (std::isupper(ch)) flags |= PCTYPE_UPPER; + if (std::islower(ch)) flags |= PCTYPE_LOWER; + if (std::isdigit(ch)) flags |= PCTYPE_DIGIT; + if (std::isspace(ch)) flags |= PCTYPE_SPACE; + if (std::iscntrl(ch)) flags |= PCTYPE_CONTROL; + if (ch == ' ' || ch == '\t') flags |= PCTYPE_BLANK; + if (std::ispunct(ch)) flags |= PCTYPE_PUNCT; + if (std::isxdigit(ch)) flags |= PCTYPE_HEX; + if (isLeadByte(ch)) flags |= PCTYPE_LEADBYTE; + table[i + 1] = flags; + } + }); + return table; + } struct IOBProxy { char *_ptr; @@ -55,16 +217,10 @@ namespace msvcrt { char *_tmpfname; }; - using UserMathErrHandler = int (*)(struct _exception *); - - UserMathErrHandler &mathErrHandler() { - static UserMathErrHandler handler = nullptr; - return handler; - } - - std::mutex &mathErrMutex() { - static std::mutex mutex; - return mutex; + int WIN_ENTRY _except_handler4_common(void *, void *, void *, void *); + std::vector &putenvStorage() { + static std::vector storage; + return storage; } IOBProxy *standardIobEntries() { @@ -76,6 +232,10 @@ namespace msvcrt { return standardIobEntries(); } + IOBProxy *WIN_ENTRY __p__iob() { + return standardIobEntries(); + } + std::unordered_map &iobMapping() { static std::unordered_map mapping; return mapping; @@ -106,7 +266,85 @@ namespace msvcrt { return stream; } + void WIN_ENTRY setbuf(FILE *stream, char *buffer) { + DEBUG_LOG("setbuf(%p, %p)\n", stream, buffer); + if (!stream) { + return; + } + FILE *host = mapToHostFile(stream); + if (buffer) { + setvbuf(host, buffer, _IOFBF, BUFSIZ); + } else { + setvbuf(host, nullptr, _IONBF, 0); + } + } + + void WIN_ENTRY _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext) { + if (drive) drive[0] = '\0'; + if (dir) dir[0] = '\0'; + if (fname) fname[0] = '\0'; + if (ext) ext[0] = '\0'; + + if (!path) { + errno = EINVAL; + return; + } + + const char *cursor = path; + if (cursor[0] && cursor[1] == ':') { + if (drive) { + drive[0] = cursor[0]; + drive[1] = ':'; + drive[2] = '\0'; + } + cursor += 2; + } + + const char *dirEnd = nullptr; + for (const char *scan = cursor; *scan; ++scan) { + if (*scan == '/' || *scan == '\\') { + dirEnd = scan + 1; + } + } + + const char *filename = cursor; + if (dirEnd) { + if (dir) { + size_t dirLen = static_cast(dirEnd - cursor); + std::memcpy(dir, cursor, dirLen); + dir[dirLen] = '\0'; + } + filename = dirEnd; + } + + const char *extStart = nullptr; + for (const char *scan = filename; *scan; ++scan) { + if (*scan == '.') { + extStart = scan; + } + } + + const char *nameEnd = extStart ? extStart : filename + std::strlen(filename); + + if (fname) { + auto nameLen = static_cast(nameEnd - filename); + std::memcpy(fname, filename, nameLen); + fname[nameLen] = '\0'; + } + if (ext && extStart) { + std::strcpy(ext, extStart); + } + + DEBUG_LOG("_splitpath(%s) -> drive='%s' dir='%s' fname='%s' ext='%s'\n", + path, + drive ? drive : "", + dir ? dir : "", + fname ? fname : "", + ext ? ext : ""); + } + int WIN_ENTRY _fileno(FILE *stream) { + DEBUG_LOG("_fileno(%p)\n", stream); if (!stream) { errno = EINVAL; return -1; @@ -115,8 +353,91 @@ namespace msvcrt { return ::fileno(host); } + unsigned int mbCurMaxForCodePage(int codepage) { + switch (codepage) { + case MB_CP_SBCS: + case MB_CP_ANSI: + case MB_CP_OEM: + case MB_CP_LOCALE: + return 1; + case MB_CP_UTF8: + case 65001: + return 4; + case 932: + case 936: + case 949: + case 950: + case 1361: + return 2; + default: + return 1; + } + } + void refreshMbCurMax() { - mbCurMaxValue = static_cast(MB_CUR_MAX); + ensureMbctypeInitialized(); + mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting); + } + + int WIN_ENTRY _getmbcp() { + ensureMbctypeInitialized(); + DEBUG_LOG("_getmbcp() -> %d\n", mbCodePageSetting); + return mbCodePageSetting; + } + + unsigned int* WIN_ENTRY __p___mb_cur_max() { + ensureMbctypeInitialized(); + DEBUG_LOG("__p___mb_cur_max() -> %u\n", mbCurMaxValue); + return &mbCurMaxValue; + } + + int WIN_ENTRY _setmbcp(int codepage) { + DEBUG_LOG("_setmbcp(%d)\n", codepage); + ensureMbctypeInitialized(); + + switch (codepage) { + case MB_CP_SBCS: + case MB_CP_UTF8: + case MB_CP_OEM: + case MB_CP_ANSI: + case MB_CP_LOCALE: + break; + default: + if (codepage < 0) { + errno = EINVAL; + return -1; + } + break; + } + + mbCodePageSetting = codepage; + updateMbctypeForCodePage(codepage); + mbCurMaxValue = mbCurMaxForCodePage(codepage); + return 0; + } + + unsigned char *WIN_ENTRY __p__mbctype() { + ensureMbctypeInitialized(); + DEBUG_LOG("__p__mbctype() -> %p\n", mbctypeTable().data()); + return mbctypeTable().data(); + } + + unsigned short **WIN_ENTRY __p__pctype() { + DEBUG_LOG("__p__pctype()\n"); + static unsigned short *pointer = nullptr; + pointer = pctypeTable().data() + 1; + return &pointer; + } + + int WIN_ENTRY _isctype(int ch, int mask) { + DEBUG_LOG("_isctype(%d, %d)\n", ch, mask); + if (ch == EOF) { + return 0; + } + if (ch < 0 || ch > 255) { + return 0; + } + return (pctypeTable()[static_cast(ch) + 1] & mask) != 0; } namespace { @@ -345,30 +666,38 @@ namespace msvcrt { // Stub because we're only ever a console application void WIN_ENTRY __set_app_type(int at) { + DEBUG_LOG("STUB: __set_app_type(%d)\n", at); + (void)at; } int* WIN_FUNC __p__fmode() { + DEBUG_LOG("__p__fmode() -> %p\n", &_fmode); return &_fmode; } int* WIN_FUNC __p__commode() { + DEBUG_LOG("__p__commode() -> %p\n", &_commode); return &_commode; } void WIN_ENTRY _initterm(const _PVFV *ppfn, const _PVFV* end) { + DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end); for (; ppfn < end; ppfn++) { _PVFV func = *ppfn; if (func) { + DEBUG_LOG("_initterm: calling %p\n", func); func(); } } } int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) { + DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end); for (; ppfn < end; ppfn++) { _PIFV func = *ppfn; if (func) { int err = func(); + DEBUG_LOG("_initterm_e: calling %p -> %d\n", func, err); if (err != 0) return err; } @@ -376,8 +705,27 @@ namespace msvcrt { return 0; } + unsigned int WIN_ENTRY _controlfp(unsigned int newControl, unsigned int mask) { + DEBUG_LOG("_controlfp(newControl=%08x, mask=%08x)\n", newControl, mask); + unsigned int previous = floatingPointControlWord; + if (mask != 0) { + floatingPointControlWord = (floatingPointControlWord & ~mask) | (newControl & mask); + } + return previous; + } + int WIN_ENTRY _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask) { - DEBUG_LOG("STUB: _controlfp_s(%p, %u, %u)\n", currentControl, newControl, mask); + DEBUG_LOG("_controlfp_s(currentControl=%p, newControl=%08x, mask=%08x)\n", currentControl, newControl, mask); + if (mask != 0 && (mask & 0xFF000000) != 0) { + // Unsupported bits: match real CRT behaviour by ignoring but logging. + DEBUG_LOG("STUB: _controlfp_s unsupported mask bits %08x\n", mask); + } + if (mask != 0) { + floatingPointControlWord = (floatingPointControlWord & ~mask) | (newControl & mask); + } + if (currentControl) { + *currentControl = floatingPointControlWord; + } return 0; } @@ -411,18 +759,671 @@ namespace msvcrt { } char* WIN_ENTRY getenv(const char *varname){ + DEBUG_LOG("getenv(%s)\n", varname); return std::getenv(varname); } -char* WIN_ENTRY setlocale(int category, const char *locale){ - char *result = std::setlocale(category, locale); - if (result) { - refreshMbCurMax(); + char*** WIN_ENTRY __p___initenv() { + DEBUG_LOG("__p___initenv() -> %p\n", &__initenv); + return &__initenv; + } + + char* WIN_ENTRY strcat(char *dest, const char *src) { + VERBOSE_LOG("strcat(%s, %s)\n", dest, src); + return std::strcat(dest, src); + } + + char* WIN_ENTRY strcpy(char *dest, const char *src) { + VERBOSE_LOG("strcpy(%s, %s)\n", dest, src); + return std::strcpy(dest, src); + } + + int WIN_ENTRY _access(const char *path, int mode) { + DEBUG_LOG("_access(%s, %d)\n", path ? path : "(null)", mode); + if (!path) { + errno = EINVAL; + return -1; + } + + auto hostPath = files::pathFromWindows(path); + int flags = F_OK; + if (mode & 2) { + flags |= W_OK; + } + if (mode & 4) { + flags |= R_OK; + } + if (mode & 1) { + flags |= X_OK; + } + + if (::access(hostPath.c_str(), flags) == 0) { + return 0; + } + + return -1; + } + + int WIN_ENTRY _ismbblead(unsigned int c) { + DEBUG_LOG("_ismbblead(%d)\n", c); + if (c > 0xFF) { + return 0; + } + return isLeadByte(static_cast(c)) ? 1 : 0; + } + + int WIN_ENTRY _ismbbtrail(unsigned int c) { + DEBUG_LOG("_ismbbtrail(%d)\n", c); + if (c > 0xFF) { + return 0; + } + return isTrailByte(static_cast(c)) ? 1 : 0; + } + + int WIN_ENTRY _ismbcspace(unsigned int c) { + DEBUG_LOG("_ismbcspace(%d)\n", c); + if (c <= 0xFF) { + return std::isspace(static_cast(c)) ? 1 : 0; + } + + unsigned char lead = static_cast((c >> 8) & 0xFF); + unsigned char trail = static_cast(c & 0xFF); + if (isLeadByte(lead) && isTrailByte(trail)) { + // Treat known double-byte ideographic space as whitespace (CP932/936 etc.) + if ((lead == 0x81 && trail == 0x40) || (lead == 0xA1 && trail == 0xA1)) { + return 1; + } + } + return 0; + } + + void WIN_ENTRY _mbccpy(unsigned char *dest, const unsigned char *src) { + DEBUG_LOG("_mbccpy(%s, %s)\n", dest, src); + if (!dest || !src) { + return; + } + + dest[0] = src[0]; + if (isLeadByte(src[0]) && src[1]) { + dest[1] = src[1]; + } + } + + unsigned char* WIN_ENTRY _mbsinc(const unsigned char *str) { + DEBUG_LOG("_mbsinc(%s)\n", str); + if (!str) { + return nullptr; + } + if (*str == '\0') { + return const_cast(str); + } + if (isLeadByte(static_cast(*str)) && str[1] != '\0') { + return const_cast(str + 2); + } + return const_cast(str + 1); + } + + unsigned char* WIN_ENTRY _mbsdec(const unsigned char *start, const unsigned char *current) { + DEBUG_LOG("_mbsdec(%s, %s)\n", start, current); + if (!start || !current || current <= start) { + DEBUG_LOG("_mbsdec invalid args start=%p current=%p\n", start, current); + return nullptr; + } + + const unsigned char *iter = start; + const unsigned char *prev = nullptr; + while (iter < current) { + if (*iter == '\0') { + break; + } + prev = iter; + const unsigned char *next = _mbsinc(iter); + if (next >= current) { + break; + } + iter = next; + } + + if (!prev) { + long diff = static_cast(current - start); + DEBUG_LOG("_mbsdec fallback start=%p current=%p diff=%ld first-bytes=%02x %02x %02x %02x\n", + start, current, diff, + start ? start[0] : 0, start ? start[1] : 0, + start ? start[2] : 0, start ? start[3] : 0); + const unsigned char *fallback = current ? current - 1 : current; + if (diff >= 2 && start && start[0] == 0 && start[1] != 0) { + fallback = current - 2; + } + return const_cast(fallback); + } + return const_cast(prev); + } + + unsigned int WIN_ENTRY _mbclen(const unsigned char *str) { + DEBUG_LOG("_mbclen(%s)\n", str); + if (!str || *str == '\0') { + return 0; + } + return (isLeadByte(*str) && str[1] != '\0') ? 2U : 1U; + } + + int WIN_ENTRY _mbscmp(const unsigned char *lhs, const unsigned char *rhs) { + DEBUG_LOG("_mbscmp(%s, %s)\n", lhs, rhs); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + return std::strcmp(reinterpret_cast(lhs), reinterpret_cast(rhs)); + } + + int WIN_ENTRY _mbsicmp(const unsigned char *lhs, const unsigned char *rhs) { + DEBUG_LOG("_mbsicmp(%s, %s)\n", lhs, rhs); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + return strcasecmp(reinterpret_cast(lhs), reinterpret_cast(rhs)); + } + + unsigned char* WIN_ENTRY _mbsstr(const unsigned char *haystack, const unsigned char *needle) { + DEBUG_LOG("_mbsstr(%s, %s)\n", haystack, needle); + if (!haystack || !needle) { + return nullptr; + } + const char *result = std::strstr(reinterpret_cast(haystack), reinterpret_cast(needle)); + return result ? reinterpret_cast(const_cast(result)) : nullptr; + } + + unsigned char* WIN_ENTRY _mbschr(const unsigned char *str, unsigned int ch) { + DEBUG_LOG("_mbschr(%s, %d)\n", str, ch); + if (!str) { + return nullptr; + } + unsigned char target = static_cast(ch & 0xFF); + const char *result = std::strchr(reinterpret_cast(str), target); + return result ? reinterpret_cast(const_cast(result)) : nullptr; + } + + unsigned char* WIN_ENTRY _mbsrchr(const unsigned char *str, unsigned int ch) { + DEBUG_LOG("_mbsrchr(%s, %d)\n", str, ch); + if (!str) { + return nullptr; + } + unsigned char target = static_cast(ch & 0xFF); + const char *result = std::strrchr(reinterpret_cast(str), target); + return result ? reinterpret_cast(const_cast(result)) : nullptr; + } + + unsigned char* WIN_ENTRY _mbslwr(unsigned char *str) { + DEBUG_LOG("_mbslwr(%p)\n", str); + if (!str) { + return nullptr; + } + for (unsigned char *p = str; *p; ++p) { + *p = static_cast(std::tolower(*p)); + } + return str; + } + + unsigned char* WIN_ENTRY _mbsupr(unsigned char *str) { + DEBUG_LOG("_mbsupr(%p)\n", str); + if (!str) { + return nullptr; + } + for (unsigned char *p = str; *p; ++p) { + *p = static_cast(std::toupper(*p)); + } + return str; + } + + unsigned char *WIN_ENTRY _mbsinc_l(const unsigned char *str, void *) { + DEBUG_LOG("_mbsinc_l(%p)\n", str); + return _mbsinc(str); + } + + unsigned char *WIN_ENTRY _mbsdec_l(const unsigned char *start, const unsigned char *current, void *locale) { + DEBUG_LOG("_mbsdec_l(%p, %p, %p)\n", start, current, locale); + return _mbsdec(start, current); + } + + int WIN_ENTRY _mbsncmp(const unsigned char *lhs, const unsigned char *rhs, size_t count) { + DEBUG_LOG("_mbsncmp(%s, %s, %zu)\n", lhs, rhs, count); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + return std::strncmp(reinterpret_cast(lhs), reinterpret_cast(rhs), count); + } + + size_t WIN_ENTRY _mbsspn(const unsigned char *str, const unsigned char *set) { + DEBUG_LOG("_mbsspn(%s, %s)\n", str, set); + if (!str || !set) { + return 0; + } + return std::strspn(reinterpret_cast(str), reinterpret_cast(set)); + } + + int WIN_ENTRY _ismbcdigit(unsigned int ch) { + DEBUG_LOG("_ismbcdigit(%d)\n", ch); + if (ch <= 0xFF) { + return std::isdigit(static_cast(ch)) ? 1 : 0; + } + return 0; + } + + int WIN_ENTRY _stricmp(const char *lhs, const char *rhs) { + DEBUG_LOG("_stricmp(%s, %s)\n", lhs, rhs); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + return strcasecmp(lhs, rhs); + } + + int WIN_ENTRY _strnicmp(const char *lhs, const char *rhs, size_t count) { + DEBUG_LOG("_strnicmp(%s, %s, %zu)\n", lhs, rhs, count); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + return strncasecmp(lhs, rhs, count); + } + + int WIN_ENTRY _memicmp(const void *lhs, const void *rhs, size_t count) { + DEBUG_LOG("_memicmp(%p, %p, %zu)\n", lhs, rhs, count); + if (!lhs || !rhs) { + return (lhs == rhs) ? 0 : (lhs ? 1 : -1); + } + const auto *a = static_cast(lhs); + const auto *b = static_cast(rhs); + for (size_t i = 0; i < count; ++i) { + const auto ca = static_cast(std::tolower(a[i])); + const auto cb = static_cast(std::tolower(b[i])); + if (ca != cb) { + return (ca < cb) ? -1 : 1; + } + } + return 0; + } + + int WIN_ENTRY _vsnprintf(char *buffer, size_t count, const char *format, va_list args) { + DEBUG_LOG("_vsnprintf(%p, %zu, %s, %p)\n", buffer, count, format, args); + if (!buffer || !format) { + errno = EINVAL; + return -1; + } + int result = vsnprintf(buffer, count, format, args); + if (result < 0) { + return -1; + } + if (static_cast(result) >= count) { + buffer[count ? count - 1 : 0] = '\0'; + return -1; + } + return result; + } + + int WIN_ENTRY _snprintf(char *buffer, size_t count, const char *format, ...) { + DEBUG_LOG("_snprintf(%p, %zu, %s, ...)\n", buffer, count, format); + va_list args; + va_start(args, format); + int result = _vsnprintf(buffer, count, format, args); + va_end(args); + return result; + } + + int WIN_ENTRY sprintf(char *buffer, const char *format, ...) { + DEBUG_LOG("sprintf(%p, %s, ...)\n", buffer, format); + va_list args; + va_start(args, format); + int result = ::vsprintf(buffer, format, args); + va_end(args); + return result; + } + + int WIN_ENTRY printf(const char *format, ...) { + DEBUG_LOG("printf(%s, ...)\n", format); + va_list args; + va_start(args, format); + int result = ::vprintf(format, args); + va_end(args); + return result; + } + + int WIN_ENTRY sscanf(const char *buffer, const char *format, ...) { + DEBUG_LOG("sscanf(%p, %p, ...)\n", buffer, format); + va_list args; + va_start(args, format); + int result = ::vsscanf(buffer, format, args); + va_end(args); + return result; + } + + char *WIN_ENTRY fgets(char *str, int count, FILE *stream) { + DEBUG_LOG("fgets(%p, %d, %p)\n", str, count, stream); + if (!str || count <= 0) { + return nullptr; + } + FILE *host = mapToHostFile(stream); + return ::fgets(str, count, host); + } + + size_t WIN_ENTRY fread(void *buffer, size_t size, size_t count, FILE *stream) { + DEBUG_LOG("fread(%p, %zu, %zu, %p)\n", buffer, size, count, stream); + FILE *host = mapToHostFile(stream); + return ::fread(buffer, size, count, host); + } + + FILE *WIN_ENTRY _fsopen(const char *filename, const char *mode, int shflag) { + DEBUG_LOG("_fsopen(%s, %s, %d)\n", filename ? filename : "(null)", mode ? mode : "(null)", shflag); + (void)shflag; + if (!filename || !mode) { + errno = EINVAL; + return nullptr; + } + auto hostPath = files::pathFromWindows(filename); + return ::fopen(hostPath.c_str(), mode); + } + + int WIN_ENTRY _sopen(const char *path, int oflag, int shflag, int pmode) { + DEBUG_LOG("_sopen(%s, %d, %d, %d)\n", path ? path : "(null)", oflag, shflag, pmode); + (void)shflag; + if (!path) { + errno = EINVAL; + return -1; + } + auto hostPath = files::pathFromWindows(path); + int flags = oflag; + flags &= ~O_BINARY; + return ::open(hostPath.c_str(), flags, pmode); + } + + int WIN_ENTRY _read(int fd, void *buffer, unsigned int count) { + DEBUG_LOG("_read(%d, %p, %u)\n", fd, buffer, count); + return static_cast(::read(fd, buffer, count)); + } + + int WIN_ENTRY _close(int fd) { + DEBUG_LOG("_close(%d)\n", fd); + return ::close(fd); + } + + long WIN_ENTRY _lseek(int fd, long offset, int origin) { + DEBUG_LOG("_lseek(%d, %ld, %d)\n", fd, offset, origin); + off_t result = ::lseek(fd, static_cast(offset), origin); + return static_cast(result); + } + + int WIN_ENTRY _unlink(const char *path) { + DEBUG_LOG("_unlink(%s)\n", path ? path : "(null)"); + if (!path) { + errno = EINVAL; + return -1; + } + auto hostPath = files::pathFromWindows(path); + return ::unlink(hostPath.c_str()); + } + + int WIN_ENTRY _utime(const char *path, const _utimbuf *times) { + DEBUG_LOG("_utime(%s, %p)\n", path ? path : "(null)", times); + if (!path) { + errno = EINVAL; + return -1; + } + auto hostPath = files::pathFromWindows(path); + if (!times) { + return ::utime(hostPath.c_str(), nullptr); + } + utimbuf native{static_cast(times->actime), static_cast(times->modtime)}; + return ::utime(hostPath.c_str(), &native); + } + + int WIN_ENTRY _chsize(int fd, long size) { + DEBUG_LOG("_chsize(%d, %ld)\n", fd, size); + return ::ftruncate(fd, static_cast(size)); + } + + char* WIN_ENTRY strncpy(char *dest, const char *src, size_t count) { + DEBUG_LOG("strncpy(%p, %s, %zu)\n", dest, src ? src : "(null)", count); + return std::strncpy(dest, src, count); + } + + char* WIN_ENTRY strpbrk(const char *str, const char *accept) { + const char *result = std::strpbrk(str, accept); + DEBUG_LOG("strpbrk(%s, %s) -> %p\n", str ? str : "(null)", accept ? accept : "(null)", result); + return result ? const_cast(result) : nullptr; + } + + char* WIN_ENTRY strstr(const char *haystack, const char *needle) { + const char *result = std::strstr(haystack, needle); + DEBUG_LOG("strstr(%s, %s) -> %p\n", haystack ? haystack : "(null)", needle ? needle : "(null)", result); + return result ? const_cast(result) : nullptr; + } + + char* WIN_ENTRY strrchr(const char *str, int ch) { + DEBUG_LOG("strrchr(%s, %c)\n", str ? str : "(null)", ch); + const char *result = std::strrchr(str, ch); + return result ? const_cast(result) : nullptr; + } + + char* WIN_ENTRY strtok(char *str, const char *delim) { + DEBUG_LOG("strtok(%p, %s)\n", str, delim ? delim : "(null)"); + return std::strtok(str, delim); + } + + long WIN_ENTRY _adj_fdiv_r(long value) { + DEBUG_LOG("STUB: _adj_fdiv_r(%ld)\n", value); + return value; + } + + void WIN_ENTRY _adjust_fdiv(long n) { + DEBUG_LOG("STUB: _adjust_fdiv(%ld)\n", n); + (void)n; + } + + int WIN_ENTRY _ftime(struct _timeb *timeptr) { + DEBUG_LOG("_ftime(%p)\n", timeptr); + if (!timeptr) { + errno = EINVAL; + return -1; + } + struct timeval tv; + if (gettimeofday(&tv, nullptr) != 0) { + return -1; + } + timeptr->time = tv.tv_sec; + timeptr->millitm = static_cast(tv.tv_usec / 1000); + timeptr->timezone = 0; + timeptr->dstflag = 0; + return 0; + } + + unsigned long WIN_ENTRY _ultoa(unsigned long value, char *str, int radix) { + DEBUG_LOG("_ultoa(%lu, %s, %d)\n", value, str ? str : "(null)", radix); + if (!str || radix < 2 || radix > 36) { + errno = EINVAL; + return 0; + } + char buffer[65]; + char *cursor = buffer + sizeof(buffer); + *--cursor = '\0'; + if (value == 0) { + *--cursor = '0'; + } + while (value > 0) { + unsigned long digit = value % static_cast(radix); + value /= static_cast(radix); + *--cursor = static_cast(digit < 10 ? '0' + digit : 'A' + (digit - 10)); + } + std::strcpy(str, cursor); + return static_cast(std::strlen(str)); + } + + char* WIN_ENTRY _ltoa(long value, char *str, int radix) { + DEBUG_LOG("_ltoa(%ld, %s, %d)\n", value, str ? str : "(null)", radix); + if (!str || radix < 2 || radix > 36) { + errno = EINVAL; + return nullptr; + } + bool negative = value < 0; + unsigned long absValue = negative ? static_cast(-value) : static_cast(value); + char buffer[65]; + unsigned long length = _ultoa(absValue, buffer, radix); + std::string result; + if (negative) { + result.push_back('-'); + } + result.append(buffer, buffer + length); + std::strcpy(str, result.c_str()); + return str; + } + + char* WIN_ENTRY _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext) { + if (!path) { + return nullptr; + } + std::string result; + if (drive && drive[0]) { + result.append(drive); + if (result.back() != ':') { + result.push_back(':'); + } + } + if (dir && dir[0]) { + result.append(dir); + char last = result.empty() ? '\0' : result.back(); + if (last != '/' && last != '\\') { + result.push_back('\\'); + } + } + if (fname && fname[0]) { + result.append(fname); + } + if (ext && ext[0]) { + if (ext[0] != '.') { + result.push_back('.'); + } + result.append(ext); + } + DEBUG_LOG("_makepath(%p, %s, %s, %s, %s) -> %s\n", path, drive ? drive : "(null)", dir ? dir : "(null)", + fname ? fname : "(null)", ext ? ext : "(null)", result.c_str()); + std::strcpy(path, result.c_str()); + return path; + } + + char* WIN_ENTRY _fullpath(char *absPath, const char *relPath, size_t maxLength) { + DEBUG_LOG("_fullpath(%p, %s, %zu)\n", absPath, relPath ? relPath : "(null)", maxLength); + if (!relPath) { + errno = EINVAL; + return nullptr; + } + std::filesystem::path hostPath = files::pathFromWindows(relPath); + std::filesystem::path resolved = hostPath; + if (!hostPath.is_absolute()) { + resolved = std::filesystem::absolute(hostPath); + } + std::string winPath = files::pathToWindows(resolved); + if (absPath) { + if (winPath.size() + 1 > maxLength) { + errno = ERANGE; + return nullptr; + } + std::strcpy(absPath, winPath.c_str()); + return absPath; + } + char *result = static_cast(std::malloc(winPath.size() + 1)); + if (!result) { + errno = ENOMEM; + return nullptr; + } + DEBUG_LOG("-> %s\n", winPath.c_str()); + std::strcpy(result, winPath.c_str()); + return result; + } + + int WIN_ENTRY _putenv(const char *envString) { + DEBUG_LOG("_putenv(%s)\n", envString ? envString : "(null)"); + if (!envString) { + errno = EINVAL; + return -1; + } + std::string entry(envString); + if (entry.find('=') == std::string::npos) { + errno = EINVAL; + return -1; + } + auto &storage = putenvStorage(); + storage.push_back(entry); + char *stored = storage.back().data(); + return ::putenv(stored); + } + + char *WIN_ENTRY _mktemp(char *templateName) { + DEBUG_LOG("_mktemp(%s)\n", templateName); + if (!templateName) { + errno = EINVAL; + return nullptr; + } + size_t originalLen = std::strlen(templateName); + std::string hostTemplate = files::pathFromWindows(templateName).string(); + if (hostTemplate.empty()) { + hostTemplate = templateName; + } + std::vector mutableTemplate(hostTemplate.begin(), hostTemplate.end()); + mutableTemplate.push_back('\0'); + int fd = mkstemp(mutableTemplate.data()); + if (fd == -1) { + templateName[0] = '\0'; + return templateName; + } + ::close(fd); + ::unlink(mutableTemplate.data()); + std::string hostResult(mutableTemplate.data()); + std::string winResult = files::pathToWindows(std::filesystem::path(hostResult)); + std::strncpy(templateName, winResult.c_str(), originalLen); + templateName[originalLen] = '\0'; + DEBUG_LOG("-> %s\n", templateName); + return templateName; + } + + int WIN_ENTRY _except_handler3(void *record, void *frame, void *context, void *dispatch) { + DEBUG_LOG("_except_handler3(%p, %p, %p, %p)\n", record, frame, context, dispatch); + return _except_handler4_common(record, frame, context, dispatch); + } + + int WIN_ENTRY getchar() { + VERBOSE_LOG("getchar()\n"); + return std::getchar(); + } + + time_t WIN_ENTRY time(time_t *t) { + DEBUG_LOG("time(%p)\n", t); + time_t result = std::time(nullptr); + if (t) { + *t = result; + } + return result; + } + + char *WIN_ENTRY __unDName(char *outputString, const char *mangledName, int maxStringLength, + void *(*allocFunc)(size_t), void (*freeFunc)(void *), unsigned short) { + DEBUG_LOG("STUB: __unDName(%p, %s, %d, %p, %p)\n", outputString, mangledName ? mangledName : "(null)", + maxStringLength, allocFunc, freeFunc); + (void)allocFunc; + (void)freeFunc; + if (outputString && maxStringLength > 0) { + outputString[0] = '\0'; + return outputString; + } + return nullptr; + } + + char* WIN_ENTRY setlocale(int category, const char *locale){ + DEBUG_LOG("setlocale(%d, %s)\n", category, locale ? locale : "(null)"); + char *result = std::setlocale(category, locale); + if (result) { + refreshMbCurMax(); + } + return result; } - return result; -} int WIN_ENTRY _wdupenv_s(uint16_t **buffer, size_t *numberOfElements, const uint16_t *varname){ + DEBUG_LOG("_wdupenv_s(%p, %p, %s)\n", buffer, numberOfElements, wideStringToString(varname).c_str()); if (buffer) { *buffer = nullptr; } @@ -464,6 +1465,8 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _wgetenv_s(size_t* pReturnValue, uint16_t* buffer, size_t numberOfElements, const uint16_t* varname){ + DEBUG_LOG("_wgetenv_s(%p, %p, %zu, %s)\n", pReturnValue, buffer, numberOfElements, + wideStringToString(varname).c_str()); if (pReturnValue) { *pReturnValue = 0; } @@ -503,17 +1506,28 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return 0; } - size_t WIN_ENTRY strlen(const char *str) { return ::strlen(str); } + size_t WIN_ENTRY strlen(const char *str) { + VERBOSE_LOG("strlen(%s)\n", str); + return ::strlen(str); + } - int WIN_ENTRY strcmp(const char *lhs, const char *rhs) { return ::strcmp(lhs, rhs); } + int WIN_ENTRY strcmp(const char *lhs, const char *rhs) { + VERBOSE_LOG("strcmp(%s, %s)\n", lhs, rhs); + return ::strcmp(lhs, rhs); + } - int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { return ::strncmp(lhs, rhs, count); } + int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { + VERBOSE_LOG("strncmp(%s, %s, %zu)\n", lhs, rhs, count); + return ::strncmp(lhs, rhs, count); + } void WIN_ENTRY _exit(int status) { + DEBUG_LOG("_exit(%d)\n", status); _Exit(status); } int WIN_ENTRY strcpy_s(char *dest, size_t dest_size, const char *src) { + VERBOSE_LOG("strcpy_s(%p, %zu, %s)\n", dest, dest_size, src); if (!dest || !src || dest_size == 0) { return 22; } @@ -529,6 +1543,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY strcat_s(char *dest, size_t numberOfElements, const char *src) { + DEBUG_LOG("strcat_s(%p, %zu, %s)\n", dest, numberOfElements, src); if (!dest || !src || numberOfElements == 0) { return 22; } @@ -545,6 +1560,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY strncpy_s(char *dest, size_t dest_size, const char *src, size_t count) { + DEBUG_LOG("strncpy_s(%p, %zu, %s, %zu)\n", dest, dest_size, src, count); constexpr size_t TRUNCATE = static_cast(-1); constexpr int STRUNCATE = 80; @@ -591,6 +1607,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } char *WIN_ENTRY _strdup(const char *strSource) { + DEBUG_LOG("_strdup(%s)\n", strSource); if (!strSource) { return nullptr; } @@ -606,26 +1623,32 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } unsigned long WIN_ENTRY strtoul(const char *str, char **endptr, int base) { + VERBOSE_LOG("strtoul(%s, %p, %d)\n", str, endptr, base); return ::strtoul(str, endptr, base); } void* WIN_ENTRY malloc(size_t size){ + VERBOSE_LOG("malloc(%zu)\n", size); return std::malloc(size); } void* WIN_ENTRY calloc(size_t count, size_t size){ + VERBOSE_LOG("calloc(%zu, %zu)\n", count, size); return std::calloc(count, size); } void* WIN_ENTRY realloc(void *ptr, size_t size) { + VERBOSE_LOG("realloc(%p, %zu)\n", ptr, size); return std::realloc(ptr, size); } void* WIN_ENTRY _malloc_crt(size_t size) { + VERBOSE_LOG("_malloc_crt(%zu)\n", size); return std::malloc(size); } void WIN_ENTRY _lock(int locknum) { + VERBOSE_LOG("_lock(%d)\n", locknum); if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { DEBUG_LOG("_lock: unsupported lock %d\n", locknum); return; @@ -634,6 +1657,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } void WIN_ENTRY _unlock(int locknum) { + VERBOSE_LOG("_unlock(%d)\n", locknum); if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { DEBUG_LOG("_unlock: unsupported lock %d\n", locknum); return; @@ -642,6 +1666,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } _onexit_t WIN_ENTRY __dllonexit(_onexit_t func, _PVFV **pbegin, _PVFV **pend) { + DEBUG_LOG("__dllonexit(%p, %p, %p)\n", func, pbegin, pend); if (!pbegin || !pend) { return nullptr; } @@ -672,26 +1697,32 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } void WIN_ENTRY free(void* ptr){ + VERBOSE_LOG("free(%p)\n", ptr); std::free(ptr); } void* WIN_ENTRY memcpy(void *dest, const void *src, size_t count) { + VERBOSE_LOG("memcpy(%p, %p, %zu)\n", dest, src, count); return std::memcpy(dest, src, count); } void* WIN_ENTRY memmove(void *dest, const void *src, size_t count) { + VERBOSE_LOG("memmove(%p, %p, %zu)\n", dest, src, count); return std::memmove(dest, src, count); } int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) { + VERBOSE_LOG("memcmp(%p, %p, %zu)\n", lhs, rhs, count); return std::memcmp(lhs, rhs, count); } void WIN_ENTRY qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)) { + DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compar); std::qsort(base, num, size, compar); } int WIN_ENTRY fflush(FILE *stream) { + DEBUG_LOG("fflush(%p)\n", stream); if (!stream) { return std::fflush(nullptr); } @@ -700,6 +1731,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY vfwprintf(FILE *stream, const uint16_t *format, va_list args) { + DEBUG_LOG("vfwprintf(%p, %s, ...)\n", stream, wideStringToString(format).c_str()); FILE *host = mapToHostFile(stream ? stream : stdout); std::wstring fmt; if (format) { @@ -712,30 +1744,37 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } FILE *WIN_ENTRY fopen(const char *filename, const char *mode) { + DEBUG_LOG("fopen(%s, %s)\n", filename ? filename : "(null)", mode ? mode : "(null)"); return std::fopen(filename, mode); } int WIN_ENTRY _dup2(int fd1, int fd2) { + VERBOSE_LOG("_dup2(%d, %d)\n", fd1, fd2); return dup2(fd1, fd2); } int WIN_ENTRY _isatty(int fd) { + VERBOSE_LOG("_isatty(%d)\n", fd); return isatty(fd); } int WIN_ENTRY fseek(FILE *stream, long offset, int origin) { + VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin); return std::fseek(stream, offset, origin); } long WIN_ENTRY ftell(FILE *stream) { + VERBOSE_LOG("ftell(%p)\n", stream); return std::ftell(stream); } int WIN_ENTRY feof(FILE *stream) { + VERBOSE_LOG("feof(%p)\n", stream); return std::feof(stream); } int WIN_ENTRY fputws(const uint16_t *str, FILE *stream) { + DEBUG_LOG("fputws(%s, %p)\n", wideStringToString(str).c_str(), stream); std::wstring temp; if (str) { for (const uint16_t *cursor = str; *cursor; ++cursor) { @@ -746,10 +1785,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _cputws(const uint16_t *string) { + DEBUG_LOG("_cputws(%s)\n", wideStringToString(string).c_str()); return fputws(string, stdout); } uint16_t* WIN_ENTRY fgetws(uint16_t *buffer, int size, FILE *stream) { + DEBUG_LOG("fgetws(%p, %d, %p)\n", buffer, size, stream); if (!buffer || size <= 0) { return nullptr; } @@ -768,10 +1809,13 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } wint_t WIN_ENTRY fgetwc(FILE *stream) { + VERBOSE_LOG("fgetwc(%p)\n", stream); return std::fgetwc(stream); } int WIN_ENTRY _wfopen_s(FILE **stream, const uint16_t *filename, const uint16_t *mode) { + DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(), + wideStringToString(mode).c_str()); if (!stream || !filename || !mode) { errno = EINVAL; return EINVAL; @@ -788,6 +1832,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _wcsicmp(const uint16_t *lhs, const uint16_t *rhs) { + VERBOSE_LOG("_wcsicmp(%s, %s)\n", wideStringToString(lhs).c_str(), wideStringToString(rhs).c_str()); if (lhs == rhs) { return 0; } @@ -813,6 +1858,8 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ int WIN_ENTRY _wmakepath_s(uint16_t *path, size_t sizeInWords, const uint16_t *drive, const uint16_t *dir, const uint16_t *fname, const uint16_t *ext) { + DEBUG_LOG("_wmakepath_s(%p, %zu, %s, %s, %s, %s)\n", path, sizeInWords, wideStringToString(drive).c_str(), + wideStringToString(dir).c_str(), wideStringToString(fname).c_str(), wideStringToString(ext).c_str()); if (!path || sizeInWords == 0) { return EINVAL; } @@ -866,6 +1913,8 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } } + DEBUG_LOG("-> %s\n", wideStringToString(reinterpret_cast(result.c_str())).c_str()); + size_t required = result.size() + 1; if (required > sizeInWords) { path[0] = 0; @@ -880,6 +1929,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _wputenv_s(const uint16_t *varname, const uint16_t *value) { + DEBUG_LOG("_wputenv_s(%p, %p)\n", varname, value); if (!varname || !value) { errno = EINVAL; return EINVAL; @@ -926,6 +1976,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } unsigned long WIN_ENTRY wcsspn(const uint16_t *str1, const uint16_t *str2) { + VERBOSE_LOG("wcsspn(%p, %p)\n", str1, str2); if (!str1 || !str2) { return 0; } @@ -947,10 +1998,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } long WIN_ENTRY _wtol(const uint16_t *str) { + VERBOSE_LOG("_wtol(%p)\n", str); return wstrtol(str, nullptr, 10); } int WIN_ENTRY _wcsupr_s(uint16_t *str, size_t size) { + VERBOSE_LOG("_wcsupr_s(%p, %zu)\n", str, size); if (!str || size == 0) { return EINVAL; } @@ -966,6 +2019,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _wcslwr_s(uint16_t *str, size_t size) { + VERBOSE_LOG("_wcslwr_s(%p, %zu)\n", str, size); if (!str || size == 0) { return EINVAL; } @@ -981,21 +2035,44 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } wint_t WIN_ENTRY towlower(wint_t ch) { + VERBOSE_LOG("towlower(%d)\n", ch); return static_cast(std::towlower(static_cast(ch))); } + unsigned int WIN_ENTRY _mbctolower(unsigned int ch) { + VERBOSE_LOG("_mbctolower(%u)\n", ch); + if (ch <= 0xFF) { + unsigned char byte = static_cast(ch); + unsigned char lowered = static_cast(std::tolower(static_cast(byte))); + return static_cast(lowered); + } + return ch; + } + + int WIN_ENTRY toupper(int ch) { + VERBOSE_LOG("toupper(%d)\n", ch); + return std::toupper(ch); + } + + int WIN_ENTRY tolower(int ch) { + VERBOSE_LOG("tolower(%d)\n", ch); + return std::tolower(ch); + } + int WIN_ENTRY _ftime64_s(void *timeb) { DEBUG_LOG("STUB: _ftime64_s(%p)\n", timeb); + (void)timeb; return 0; } int WIN_ENTRY _crt_debugger_hook(int value) { - DEBUG_LOG("_crt_debugger_hook(%d)\n", value); + DEBUG_LOG("STUB: _crt_debugger_hook(%d)\n", value); (void)value; return 0; } int WIN_ENTRY _configthreadlocale(int mode) { + DEBUG_LOG("_configthreadlocale(mode=%d)\n", mode); static int currentMode = 0; int previous = currentMode; if (mode == -1) { @@ -1009,9 +2086,9 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return -1; } - void WIN_ENTRY __setusermatherr(UserMathErrHandler handler) { - std::lock_guard lock(mathErrMutex()); - mathErrHandler() = handler; + void WIN_ENTRY __setusermatherr(void* handler) { + DEBUG_LOG("STUB: __setusermatherr(handler=%p)\n", handler); + (void)handler; } void WIN_ENTRY _cexit() { @@ -1027,6 +2104,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY vfprintf(FILE *stream, const char *format, va_list args) { + DEBUG_LOG("vfprintf(stream=%p, format=%s, args=%p)\n", stream, format, args); if (!format || !stream) { errno = EINVAL; return -1; @@ -1044,6 +2122,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY fprintf(FILE *stream, const char *format, ...) { + DEBUG_LOG("fprintf(%p, %s, ...)\n", stream, format); va_list args; va_start(args, format); int result = msvcrt::vfprintf(stream, format, args); @@ -1052,6 +2131,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY fputc(int ch, FILE *stream) { + DEBUG_LOG("fputc(%d, %p)\n", ch, stream); if (!stream) { errno = EINVAL; return EOF; @@ -1065,6 +2145,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } size_t WIN_ENTRY fwrite(const void *buffer, size_t size, size_t count, FILE *stream) { + DEBUG_LOG("fwrite(%p, %zu, %zu, %p)\n", buffer, size, count, stream); if (!buffer || !stream) { errno = EINVAL; return 0; @@ -1078,24 +2159,35 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } char *WIN_ENTRY strerror(int errnum) { + DEBUG_LOG("strerror(%d)\n", errnum); return std::strerror(errnum); } char *WIN_ENTRY strchr(const char *str, int character) { + VERBOSE_LOG("strchr(%s, %d)\n", str, character); return const_cast(std::strchr(str, character)); } struct lconv *WIN_ENTRY localeconv() { + VERBOSE_LOG("localeconv()\n"); return std::localeconv(); } using SignalHandler = void (*)(int); SignalHandler WIN_ENTRY signal(int sig, SignalHandler handler) { + DEBUG_LOG("signal(%d, %p)\n", sig, handler); + if (sig != SIGABRT && sig != SIGFPE && sig != SIGILL && sig != SIGINT && + sig != SIGSEGV && sig != SIGTERM) { + DEBUG_LOG("signal: unsupported signal %d\n", sig); + errno = EINVAL; + return SIG_ERR; + } return std::signal(sig, handler); } size_t WIN_ENTRY wcslen(const uint16_t *str) { + VERBOSE_LOG("wcslen(%p)\n", str); return wstrlen(str); } @@ -1109,6 +2201,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY atoi(const char *str) { + VERBOSE_LOG("atoi(%s)\n", str); if (!str) { errno = EINVAL; return 0; @@ -1123,7 +2216,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } void WIN_ENTRY _invoke_watson(const uint16_t *, const uint16_t *, const uint16_t *, unsigned int, uintptr_t) { - DEBUG_LOG("_invoke_watson\n"); + DEBUG_LOG("_invoke_watson(...)\n"); abort_and_log("_invoke_watson"); } @@ -1137,12 +2230,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _except_handler4_common(void *, void *, void *, void *) { - DEBUG_LOG("_except_handler4_common\n"); + DEBUG_LOG("STUB: _except_handler4_common\n"); return 0; } long WIN_ENTRY _XcptFilter(unsigned long code, void *) { - DEBUG_LOG("_XcptFilter(%lu)\n", code); + DEBUG_LOG("STUB: _XcptFilter(%lu)\n", code); return 0; } @@ -1157,7 +2250,16 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } exe_path[len] = 0; - std::vector wStr = stringToWideString(exe_path); + std::string exePathStr(exe_path); + if (_pgmptr) { + free(_pgmptr); + } + _pgmptr = ::strdup(exePathStr.c_str()); + + std::vector wStr = stringToWideString(exePathStr.c_str()); + if (_wpgmptr) { + delete[] _wpgmptr; + } _wpgmptr = new uint16_t[wStr.size() + 1]; std::copy(wStr.begin(), wStr.end(), _wpgmptr); _wpgmptr[wStr.size()] = 0; @@ -1166,17 +2268,21 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return 0; } + char** WIN_ENTRY __p__pgmptr() { + return &_pgmptr; + } + int WIN_ENTRY _wsplitpath_s(const uint16_t * path, uint16_t * drive, size_t driveNumberOfElements, uint16_t *dir, size_t dirNumberOfElements, uint16_t * fname, size_t nameNumberOfElements, uint16_t * ext, size_t extNumberOfElements){ - DEBUG_LOG("_wsplitpath_s - "); if(!path){ - DEBUG_LOG("no path\n"); return 22; } else { std::string path_str = wideStringToString(path); - DEBUG_LOG("path: %s\n", path_str.c_str()); } + DEBUG_LOG("_wsplitpath_s(path=%p, drive=%p, driveNumberOfElements=%zu, dir=%p, dirNumberOfElements=%zu, " + "fname=%p, nameNumberOfElements=%zu, ext=%p, extNumberOfElements=%zu)\n", + path, drive, driveNumberOfElements, dir, dirNumberOfElements, fname, nameNumberOfElements, ext, extNumberOfElements); if(drive && driveNumberOfElements) drive[0] = L'\0'; if(dir && dirNumberOfElements) dir[0] = L'\0'; @@ -1278,7 +2384,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ int WIN_ENTRY wcsncpy_s(uint16_t *strDest, size_t numberOfElements, const uint16_t *strSource, size_t count){ std::string src_str = wideStringToString(strSource); - DEBUG_LOG("wcsncpy_s dest size %d, src str %s, src size %d\n", numberOfElements, src_str.c_str(), count); + DEBUG_LOG("wcsncpy_s(%p, %zu, %p, %zu)\n", strDest, numberOfElements, strSource, count); if(!strDest || !strSource || numberOfElements == 0){ if(strDest && numberOfElements > 0) strDest[0] = L'\0'; @@ -1294,16 +2400,15 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ wstrncpy(strDest, strSource, count); strDest[count] = L'\0'; - // std::string dst_str = wideStringToString(strDest); - // DEBUG_LOG(" --> %s\n", dst_str.c_str()); + VERBOSE_LOG(" -> %s\n", wideStringToString(strDest).c_str()); return 0; } int WIN_ENTRY wcsncat_s(uint16_t *strDest, size_t numberOfElements, const uint16_t *strSource, size_t count){ std::string dst_str = wideStringToString(strDest); std::string src_str = wideStringToString(strSource); - DEBUG_LOG("wscncat_s dest str %s, dest size %d, src str %s, src size %d", dst_str.c_str(), numberOfElements, src_str.c_str(), count); - + DEBUG_LOG("wscncat_s(%p, %zu, %p, %zu)\n", strDest, numberOfElements, strSource, count); + if(!strDest || !strSource || numberOfElements == 0){ if(strDest && numberOfElements > 0) strDest[0] = L'\0'; return 1; @@ -1318,13 +2423,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } wstrncat(strDest, strSource, src_len); - dst_str = wideStringToString(strDest); - DEBUG_LOG(" --> %s\n", dst_str.c_str()); + VERBOSE_LOG(" -> %s\n", wideStringToString(strDest).c_str()); return 0; } int WIN_ENTRY _itow_s(int value, uint16_t *buffer, size_t size, int radix){ - DEBUG_LOG("_itow_s value %d, size %d, radix %d\n", value, size, radix); + VERBOSE_LOG("_itow_s(%d, %p, %zu, %d)\n", value, buffer, size, radix); if (!buffer || size == 0) return 22; assert(radix == 10); // only base 10 supported for now @@ -1342,11 +2446,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY _wtoi(const uint16_t* str) { - DEBUG_LOG("_wtoi\n"); + VERBOSE_LOG("_wtoi(%p)\n", str); return wstrtol(str, nullptr, 10); } int WIN_ENTRY _ltoa_s(long value, char *buffer, size_t sizeInChars, int radix) { + VERBOSE_LOG("_ltoa_s(%ld, %p, %zu, %d)\n", value, buffer, sizeInChars, radix); if (!buffer || sizeInChars == 0) { return 22; } @@ -1384,7 +2489,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ int WIN_ENTRY wcscpy_s(uint16_t *dest, size_t dest_size, const uint16_t *src){ std::string src_str = wideStringToString(src); - DEBUG_LOG("wcscpy_s %s\n", src_str.c_str()); + VERBOSE_LOG("wcscpy_s(%p, %zu, %p)\n", dest, dest_size, src); if (!dest || !src || dest_size == 0) { return 22; } @@ -1399,6 +2504,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY swprintf_s(uint16_t *buffer, size_t sizeOfBuffer, const uint16_t *format, ...) { + VERBOSE_LOG("swprintf_s(%p, %zu, %p, ...)\n", buffer, sizeOfBuffer, format); if (!buffer || sizeOfBuffer == 0 || !format) { errno = EINVAL; return EINVAL; @@ -1425,6 +2531,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY swscanf_s(const uint16_t *buffer, const uint16_t *format, ...) { + VERBOSE_LOG("swscanf_s(%p, %p, ...)\n", buffer, format); if (!buffer || !format) { errno = EINVAL; return EOF; @@ -1447,24 +2554,27 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int* WIN_ENTRY _get_osfhandle(int fd){ - DEBUG_LOG("STUB: _get_osfhandle %d\n", fd); + DEBUG_LOG("STUB: _get_osfhandle(%d)\n", fd); return (int*)fd; } int WIN_ENTRY _write(int fd, const void* buffer, unsigned int count) { + VERBOSE_LOG("_write(fd=%d, buffer=%p, count=%u)\n", fd, buffer, count); return (int)write(fd, buffer, count); } - void WIN_ENTRY exit(int status){ + void WIN_ENTRY exit(int status) { + VERBOSE_LOG("exit(%d)\n", status); _Exit(status); } - int WIN_ENTRY wcsncmp(const uint16_t *string1, const uint16_t *string2, size_t count){ + int WIN_ENTRY wcsncmp(const uint16_t *string1, const uint16_t *string2, size_t count) { + VERBOSE_LOG("wcsncmp(%p, %p, %zu)\n", string1, string2, count); return wstrncmp(string1, string2, count); } int WIN_ENTRY _vswprintf_c_l(uint16_t* buffer, size_t size, const uint16_t* format, ...) { - DEBUG_LOG("_vswprintf_c_l\n"); + DEBUG_LOG("_vswprintf_c_l(%p, %zu, %p, ...)\n", buffer, size, format); if (!buffer || !format || size == 0) return -1; @@ -1496,26 +2606,32 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } const uint16_t* WIN_ENTRY wcsstr( const uint16_t *dest, const uint16_t *src ){ + VERBOSE_LOG("wcsstr(%p, %p)\n", dest, src); return wstrstr(dest, src); } int WIN_ENTRY iswspace(uint32_t w){ + VERBOSE_LOG("iswspace(%u)\n", w); return std::iswspace(w); } int WIN_ENTRY iswdigit(uint32_t w){ + VERBOSE_LOG("iswdigit(%u)\n", w); return std::iswdigit(w); } const uint16_t* WIN_ENTRY wcschr(const uint16_t* str, uint16_t c){ + VERBOSE_LOG("wcschr(%p, %u)\n", str, c); return wstrchr(str, c); } const uint16_t* WIN_ENTRY wcsrchr(const uint16_t *str, uint16_t c){ + VERBOSE_LOG("wcsrchr(%p, %u)\n", str, c); return wstrrchr(str, c); } unsigned long WIN_ENTRY wcstoul(const uint16_t *strSource, uint16_t **endptr, int base){ + VERBOSE_LOG("wcstoul(%p, %p, %d)\n", strSource, endptr, base); return wstrtoul(strSource, endptr, base); } @@ -1523,7 +2639,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ if (!filename || !mode) return nullptr; std::string fname_str = wideStringToString(filename); std::string mode_str = wideStringToString(mode); - DEBUG_LOG("_wfsopen file %s, mode %s\n", fname_str.c_str(), mode_str.c_str()); + DEBUG_LOG("_wfsopen(%s, %s)\n", fname_str.c_str(), mode_str.c_str()); (void)shflag; return fopen(fname_str.c_str(), mode_str.c_str()); @@ -1533,7 +2649,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ if (!str) { str = "(null)"; } - DEBUG_LOG("puts %s\n", str); + DEBUG_LOG("puts(%s)\n", str); if (std::fputs(str, stdout) < 0) return EOF; if (std::fputc('\n', stdout) == EOF) @@ -1542,11 +2658,12 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int WIN_ENTRY fclose(FILE* stream){ + VERBOSE_LOG("fclose(%p)\n", stream); return ::fclose(stream); } int WIN_ENTRY _flushall(){ - DEBUG_LOG("flushall\n"); + DEBUG_LOG("_flushall()\n"); int count = 0; if (msvcrt::fflush(stdin) == 0) count++; @@ -1557,6 +2674,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } int* WIN_ENTRY _errno() { + VERBOSE_LOG("_errno()\n"); return &errno; } @@ -1567,7 +2685,7 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ } std::string command = wideStringToString(cmdname); - DEBUG_LOG("_wspawnvp(mode=%d, cmd=%s)\n", mode, command.c_str()); + DEBUG_LOG("_wspawnvp(%d, %s)\n", mode, command.c_str()); std::vector argStorage; for (const uint16_t *const *cursor = argv; *cursor; ++cursor) { @@ -1576,21 +2694,27 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ if (argStorage.empty()) { argStorage.emplace_back(command); } + DEBUG_LOG("-> argv:"); + for (const auto &arg : argStorage) { + DEBUG_LOG(" '%s'", arg.c_str()); + } - auto resolved = processes::resolveExecutable(command, true); + auto resolved = processes::resolveExecutable(command, false); if (!resolved) { errno = ENOENT; - DEBUG_LOG("\tfailed to resolve executable for %s\n", command.c_str()); + DEBUG_LOG("-> failed to resolve executable for %s\n", command.c_str()); return -1; } + DEBUG_LOG("-> resolved to %s\n", resolved->c_str()); pid_t pid = -1; int spawnResult = processes::spawnViaWibo(*resolved, argStorage, &pid); if (spawnResult != 0) { errno = spawnResult; - DEBUG_LOG("\tspawnViaWibo failed: %d\n", spawnResult); + DEBUG_LOG("-> spawnViaWibo failed: %d\n", spawnResult); return -1; } + DEBUG_LOG("-> spawned pid %d\n", pid); constexpr int P_WAIT = 0; constexpr int P_DETACH = 2; @@ -1618,15 +2742,77 @@ char* WIN_ENTRY setlocale(int category, const char *locale){ return static_cast(pid); } + intptr_t WIN_ENTRY _spawnvp(int mode, const char *cmdname, const char * const *argv) { + if (!cmdname || !argv) { + errno = EINVAL; + return -1; + } + + std::string command(cmdname); + DEBUG_LOG("_spawnvp(%d, %s)\n", mode, command.c_str()); + + std::vector argStorage; + for (const char * const *cursor = argv; *cursor; ++cursor) { + argStorage.emplace_back(*cursor); + } + if (argStorage.empty()) { + argStorage.emplace_back(command); + } + DEBUG_LOG("-> argv:"); + for (const auto &arg : argStorage) { + DEBUG_LOG(" '%s'", arg.c_str()); + } + + auto resolved = processes::resolveExecutable(command, false); + if (!resolved) { + errno = ENOENT; + DEBUG_LOG("-> failed to resolve executable for %s\n", command.c_str()); + return -1; + } + DEBUG_LOG("-> resolved to %s\n", resolved->c_str()); + + pid_t pid = -1; + int spawnResult = processes::spawnViaWibo(*resolved, argStorage, &pid); + if (spawnResult != 0) { + errno = spawnResult; + DEBUG_LOG("-> spawnViaWibo failed: %d\n", spawnResult); + return -1; + } + DEBUG_LOG("-> spawned pid %d\n", pid); + + constexpr int P_WAIT = 0; + constexpr int P_DETACH = 2; + + if (mode == P_WAIT) { + int status = 0; + if (waitpid(pid, &status, 0) == -1) { + return -1; + } + if (WIFEXITED(status)) { + return static_cast(WEXITSTATUS(status)); + } + if (WIFSIGNALED(status)) { + errno = EINTR; + } + return -1; + } + + if (mode == P_DETACH) { + return 0; + } + + return static_cast(pid); + } + int WIN_ENTRY _wunlink(const uint16_t *filename){ std::string str = wideStringToString(filename); - DEBUG_LOG("_wunlink %s\n", str.c_str()); + DEBUG_LOG("_wunlink(%s)\n", str.c_str()); return unlink(str.c_str()); } uint16_t* WIN_ENTRY _wfullpath(uint16_t* absPath, const uint16_t* relPath, size_t maxLength){ std::string relPathStr = wideStringToString(relPath); - DEBUG_LOG("_wfullpath, relpath %s\n", relPathStr.c_str()); + DEBUG_LOG("_wfullpath(%s, %zu)\n", relPathStr.c_str(), maxLength); if(!relPath) return nullptr; char resolved[PATH_MAX]; @@ -1689,21 +2875,38 @@ static void *resolveByName(const char *name) { if (strcmp(name, "__p__commode") == 0) return (void *) msvcrt::__p__commode; if (strcmp(name, "_initterm") == 0) return (void *)msvcrt::_initterm; if (strcmp(name, "_initterm_e") == 0) return (void *)msvcrt::_initterm_e; + if (strcmp(name, "_controlfp") == 0) return (void *)msvcrt::_controlfp; if (strcmp(name, "_controlfp_s") == 0) return (void *)msvcrt::_controlfp_s; + if (strcmp(name, "__p___initenv") == 0) return (void *)msvcrt::__p___initenv; if (strcmp(name, "_onexit") == 0) return (void*)msvcrt::_onexit; if (strcmp(name, "__getmainargs") == 0) return (void*)msvcrt::__getmainargs; if (strcmp(name, "__wgetmainargs") == 0) return (void*)msvcrt::__wgetmainargs; if (strcmp(name, "setlocale") == 0) return (void*)msvcrt::setlocale; if (strcmp(name, "__mb_cur_max") == 0) return (void *)&msvcrt::mbCurMaxValue; + if (strcmp(name, "__p__mbctype") == 0) return (void *)msvcrt::__p__mbctype; + if (strcmp(name, "__p__pctype") == 0) return (void *)msvcrt::__p__pctype; + if (strcmp(name, "__p___mb_cur_max") == 0) return (void *)msvcrt::__p___mb_cur_max; + if (strcmp(name, "_isctype") == 0) return (void *)msvcrt::_isctype; + if (strcmp(name, "__unDName") == 0) return (void *)msvcrt::__unDName; if (strcmp(name, "__setusermatherr") == 0) return (void *)msvcrt::__setusermatherr; if (strcmp(name, "_wdupenv_s") == 0) return (void*)msvcrt::_wdupenv_s; if (strcmp(name, "strlen") == 0) return (void *)msvcrt::strlen; if (strcmp(name, "strcmp") == 0) return (void *)msvcrt::strcmp; if (strcmp(name, "strncmp") == 0) return (void *)msvcrt::strncmp; + if (strcmp(name, "strcat") == 0) return (void *)msvcrt::strcat; + if (strcmp(name, "strcpy") == 0) return (void *)msvcrt::strcpy; if (strcmp(name, "strcpy_s") == 0) return (void *)msvcrt::strcpy_s; if (strcmp(name, "strcat_s") == 0) return (void *)msvcrt::strcat_s; if (strcmp(name, "strncpy_s") == 0) return (void *)msvcrt::strncpy_s; if (strcmp(name, "_strdup") == 0) return (void *)msvcrt::_strdup; + if (strcmp(name, "strncpy") == 0) return (void *)msvcrt::strncpy; + if (strcmp(name, "strpbrk") == 0) return (void *)msvcrt::strpbrk; + if (strcmp(name, "strstr") == 0) return (void *)msvcrt::strstr; + if (strcmp(name, "strrchr") == 0) return (void *)msvcrt::strrchr; + if (strcmp(name, "strtok") == 0) return (void *)msvcrt::strtok; + if (strcmp(name, "sprintf") == 0) return (void *)msvcrt::sprintf; + if (strcmp(name, "printf") == 0) return (void *)msvcrt::printf; + if (strcmp(name, "sscanf") == 0) return (void *)msvcrt::sscanf; if (strcmp(name, "strtoul") == 0) return (void *)msvcrt::strtoul; if (strcmp(name, "malloc") == 0) return (void*)msvcrt::malloc; if (strcmp(name, "calloc") == 0) return (void*)msvcrt::calloc; @@ -1719,6 +2922,8 @@ static void *resolveByName(const char *name) { if (strcmp(name, "_wsplitpath_s") == 0) return (void*)msvcrt::_wsplitpath_s; if (strcmp(name, "wcscat_s") == 0) return (void*)msvcrt::wcscat_s; if (strcmp(name, "_wcsdup") == 0) return (void*)msvcrt::_wcsdup; + if (strcmp(name, "__p__pgmptr") == 0) return (void*)msvcrt::__p__pgmptr; + if (strcmp(name, "_splitpath") == 0) return (void*)msvcrt::_splitpath; if (strcmp(name, "memset") == 0) return (void*)msvcrt::memset; if (strcmp(name, "memcpy") == 0) return (void*)msvcrt::memcpy; if (strcmp(name, "memmove") == 0) return (void*)msvcrt::memmove; @@ -1731,6 +2936,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "feof") == 0) return (void*)msvcrt::feof; if (strcmp(name, "fgetws") == 0) return (void*)msvcrt::fgetws; if (strcmp(name, "fgetwc") == 0) return (void*)msvcrt::fgetwc; + if (strcmp(name, "fgets") == 0) return (void*)msvcrt::fgets; if (strcmp(name, "fputws") == 0) return (void*)msvcrt::fputws; if (strcmp(name, "_cputws") == 0) return (void*)msvcrt::_cputws; if (strcmp(name, "vfwprintf") == 0) return (void*)msvcrt::vfwprintf; @@ -1745,12 +2951,34 @@ static void *resolveByName(const char *name) { if (strcmp(name, "swprintf_s") == 0) return (void*)msvcrt::swprintf_s; if (strcmp(name, "swscanf_s") == 0) return (void*)msvcrt::swscanf_s; if (strcmp(name, "towlower") == 0) return (void*)msvcrt::towlower; + if (strcmp(name, "toupper") == 0) return (void*)msvcrt::toupper; + if (strcmp(name, "tolower") == 0) return (void*)msvcrt::tolower; + if (strcmp(name, "setbuf") == 0) return (void*)msvcrt::setbuf; + if (strcmp(name, "_mbctolower") == 0) return (void*)msvcrt::_mbctolower; + if (strcmp(name, "_ismbcspace") == 0) return (void*)msvcrt::_ismbcspace; + if (strcmp(name, "_ismbcdigit") == 0) return (void*)msvcrt::_ismbcdigit; + if (strcmp(name, "_ismbblead") == 0) return (void*)msvcrt::_ismbblead; + if (strcmp(name, "_ismbbtrail") == 0) return (void*)msvcrt::_ismbbtrail; + if (strcmp(name, "_mbccpy") == 0) return (void*)msvcrt::_mbccpy; + if (strcmp(name, "_mbsinc") == 0) return (void*)msvcrt::_mbsinc; + if (strcmp(name, "_mbsdec") == 0) return (void*)msvcrt::_mbsdec; + if (strcmp(name, "_mbclen") == 0) return (void*)msvcrt::_mbclen; + if (strcmp(name, "_mbscmp") == 0) return (void*)msvcrt::_mbscmp; + if (strcmp(name, "_mbsicmp") == 0) return (void*)msvcrt::_mbsicmp; + if (strcmp(name, "_mbsstr") == 0) return (void*)msvcrt::_mbsstr; + if (strcmp(name, "_mbschr") == 0) return (void*)msvcrt::_mbschr; + if (strcmp(name, "_mbsrchr") == 0) return (void*)msvcrt::_mbsrchr; + if (strcmp(name, "_mbslwr") == 0) return (void*)msvcrt::_mbslwr; + if (strcmp(name, "_mbsupr") == 0) return (void*)msvcrt::_mbsupr; + if (strcmp(name, "_mbsspn") == 0) return (void*)msvcrt::_mbsspn; + if (strcmp(name, "_mbsncmp") == 0) return (void*)msvcrt::_mbsncmp; if (strcmp(name, "_ftime64_s") == 0) return (void*)msvcrt::_ftime64_s; if (strcmp(name, "_crt_debugger_hook") == 0) return (void*)msvcrt::_crt_debugger_hook; if (strcmp(name, "_configthreadlocale") == 0) return (void*)msvcrt::_configthreadlocale; if (strcmp(name, "_amsg_exit") == 0) return (void*)msvcrt::_amsg_exit; if (strcmp(name, "_invoke_watson") == 0) return (void*)msvcrt::_invoke_watson; if (strcmp(name, "_except_handler4_common") == 0) return (void*)msvcrt::_except_handler4_common; + if (strcmp(name, "_except_handler3") == 0) return (void*)msvcrt::_except_handler3; if (strcmp(name, "_XcptFilter") == 0) return (void*)msvcrt::_XcptFilter; if (strcmp(name, "?terminate@@YAXXZ") == 0) return (void*)msvcrt::terminateShim; if (strcmp(name, "_purecall") == 0) return (void*)msvcrt::_purecall; @@ -1762,6 +2990,10 @@ static void *resolveByName(const char *name) { if (strcmp(name, "wcscpy_s") == 0) return (void*)msvcrt::wcscpy_s; if (strcmp(name, "_get_osfhandle") == 0) return (void*)msvcrt::_get_osfhandle; if (strcmp(name, "_write") == 0) return (void*)msvcrt::_write; + if (strcmp(name, "_read") == 0) return (void*)msvcrt::_read; + if (strcmp(name, "_close") == 0) return (void*)msvcrt::_close; + if (strcmp(name, "_lseek") == 0) return (void*)msvcrt::_lseek; + if (strcmp(name, "_chsize") == 0) return (void*)msvcrt::_chsize; if (strcmp(name, "exit") == 0) return (void*)msvcrt::exit; if (strcmp(name, "wcsncmp") == 0) return (void*)msvcrt::wcsncmp; if (strcmp(name, "_vswprintf_c_l") == 0) return (void*)msvcrt::_vswprintf_c_l; @@ -1774,18 +3006,24 @@ static void *resolveByName(const char *name) { if (strcmp(name, "getenv") == 0) return (void*)msvcrt::getenv; if (strcmp(name, "_wgetenv_s") == 0) return (void*)msvcrt::_wgetenv_s; if (strcmp(name, "_waccess_s") == 0) return (void*)msvcrt::_waccess_s; + if (strcmp(name, "_access") == 0) return (void*)msvcrt::_access; if (strcmp(name, "_dup2") == 0) return (void*)msvcrt::_dup2; if (strcmp(name, "_wfsopen") == 0) return (void*)msvcrt::_wfsopen; + if (strcmp(name, "_fsopen") == 0) return (void*)msvcrt::_fsopen; + if (strcmp(name, "_sopen") == 0) return (void*)msvcrt::_sopen; if (strcmp(name, "fputws") == 0) return (void*)msvcrt::fputws; if (strcmp(name, "puts") == 0) return (void*)msvcrt::puts; if (strcmp(name, "fclose") == 0) return (void*)msvcrt::fclose; if (strcmp(name, "_flushall") == 0) return (void*)msvcrt::_flushall; if (strcmp(name, "_errno") == 0) return (void*)msvcrt::_errno; + if (strcmp(name, "_getmbcp") == 0) return (void*)msvcrt::_getmbcp; + if (strcmp(name, "_setmbcp") == 0) return (void*)msvcrt::_setmbcp; if (strcmp(name, "_wspawnvp") == 0) return (void*)msvcrt::_wspawnvp; if (strcmp(name, "_wunlink") == 0) return (void*)msvcrt::_wunlink; if (strcmp(name, "_wfullpath") == 0) return (void*)msvcrt::_wfullpath; if (strcmp(name, "_cexit") == 0) return (void*)msvcrt::_cexit; if (strcmp(name, "_iob") == 0) return (void*)msvcrt::standardIobEntries(); + if (strcmp(name, "__p__iob") == 0) return (void*)msvcrt::__p__iob; if (strcmp(name, "abort") == 0) return (void*)msvcrt::abort; if (strcmp(name, "atoi") == 0) return (void*)msvcrt::atoi; if (strcmp(name, "fprintf") == 0) return (void*)msvcrt::fprintf; @@ -1797,6 +3035,26 @@ static void *resolveByName(const char *name) { if (strcmp(name, "strchr") == 0) return (void*)msvcrt::strchr; if (strcmp(name, "strerror") == 0) return (void*)msvcrt::strerror; if (strcmp(name, "wcslen") == 0) return (void*)msvcrt::wcslen; + if (strcmp(name, "fread") == 0) return (void*)msvcrt::fread; + if (strcmp(name, "_unlink") == 0) return (void*)msvcrt::_unlink; + if (strcmp(name, "_utime") == 0) return (void*)msvcrt::_utime; + if (strcmp(name, "_ultoa") == 0) return (void*)msvcrt::_ultoa; + if (strcmp(name, "_ltoa") == 0) return (void*)msvcrt::_ltoa; + if (strcmp(name, "_makepath") == 0) return (void*)msvcrt::_makepath; + if (strcmp(name, "_fullpath") == 0) return (void*)msvcrt::_fullpath; + if (strcmp(name, "_vsnprintf") == 0) return (void*)msvcrt::_vsnprintf; + if (strcmp(name, "_snprintf") == 0) return (void*)msvcrt::_snprintf; + if (strcmp(name, "_adj_fdiv_r") == 0) return (void*)msvcrt::_adj_fdiv_r; + if (strcmp(name, "_adjust_fdiv") == 0) return (void*)msvcrt::_adjust_fdiv; + if (strcmp(name, "_memicmp") == 0) return (void*)msvcrt::_memicmp; + if (strcmp(name, "_stricmp") == 0) return (void*)msvcrt::_stricmp; + if (strcmp(name, "_strnicmp") == 0) return (void*)msvcrt::_strnicmp; + if (strcmp(name, "_putenv") == 0) return (void*)msvcrt::_putenv; + if (strcmp(name, "_mktemp") == 0) return (void*)msvcrt::_mktemp; + if (strcmp(name, "_spawnvp") == 0) return (void*)msvcrt::_spawnvp; + if (strcmp(name, "_ftime") == 0) return (void*)msvcrt::_ftime; + if (strcmp(name, "getchar") == 0) return (void*)msvcrt::getchar; + if (strcmp(name, "time") == 0) return (void*)msvcrt::time; return nullptr; } diff --git a/files.cpp b/files.cpp index 034ca98..c91649c 100644 --- a/files.cpp +++ b/files.cpp @@ -69,7 +69,7 @@ namespace files { } // Remove the drive letter - if (str.rfind("z:/", 0) == 0 || str.rfind("Z:/", 0) == 0) { + if (str.rfind("z:/", 0) == 0 || str.rfind("Z:/", 0) == 0 || str.rfind("c:/", 0) == 0 || str.rfind("C:/", 0) == 0) { str.erase(0, 2); } diff --git a/processes.cpp b/processes.cpp index ff584ce..f084e50 100644 --- a/processes.cpp +++ b/processes.cpp @@ -112,6 +112,9 @@ namespace processes { static std::vector buildSearchDirectories() { std::vector dirs; + if (wibo::guestExecutablePath.has_parent_path()) { + dirs.push_back(wibo::guestExecutablePath.parent_path()); + } dirs.push_back(std::filesystem::current_path()); if (const char *envPath = std::getenv("PATH")) { auto parsed = parseHostPath(envPath); @@ -198,6 +201,15 @@ namespace processes { } nativeArgs.push_back(nullptr); + DEBUG_LOG("Spawning process: %s, args: [", wibo::executableName.c_str()); + for (size_t i = 0; i < storage.size(); ++i) { + if (i != 0) { + DEBUG_LOG(", "); + } + DEBUG_LOG("'%s'", storage[i].c_str()); + } + DEBUG_LOG("]\n"); + posix_spawn_file_actions_t actions; posix_spawn_file_actions_init(&actions);