#include "common.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "strutil.h" typedef void (*_PVFV)(); typedef int (*_PIFV)(); using _onexit_t = _PIFV; namespace msvcrt { int _commode; int _fmode; char** __initenv; uint16_t** __winitenv; uint16_t* _wpgmptr; namespace { struct DllOnExitTable { _PVFV **pbegin; _PVFV **pend; std::vector<_PVFV> callbacks; bool registered; }; constexpr size_t LOCK_TABLE_SIZE = 64; std::array &lockTable() { static std::array table; return table; } std::vector &dllOnExitTables() { static std::vector tables; return tables; } std::mutex &dllOnExitMutex() { static std::mutex mutex; return mutex; } DllOnExitTable &ensureDllOnExitTable(_PVFV **pbegin, _PVFV **pend) { auto &tables = dllOnExitTables(); for (auto &table : tables) { if (table.pbegin == pbegin && table.pend == pend) { return table; } } tables.push_back(DllOnExitTable{pbegin, pend, {}, false}); return tables.back(); } template struct StringListStorage { std::vector> strings; std::unique_ptr pointers; template CharT **assign(char **source, Converter convert) { if (!source) { strings.clear(); pointers.reset(); return nullptr; } size_t count = 0; while (source[count]) { ++count; } strings.clear(); strings.reserve(count); pointers = std::make_unique(count + 1); for (size_t i = 0; i < count; ++i) { auto data = convert(source[i]); auto buffer = std::make_unique(data.size()); std::copy(data.begin(), data.end(), buffer.get()); CharT *raw = buffer.get(); strings.emplace_back(std::move(buffer)); pointers[i] = raw; } pointers[count] = nullptr; return pointers.get(); } }; std::vector copyNarrowString(const char *src) { if (!src) { src = ""; } size_t len = std::strlen(src); std::vector result(len + 1); if (len > 0) { std::memcpy(result.data(), src, len); } result[len] = '\0'; return result; } std::vector copyWideString(const char *src) { if (!src) { src = ""; } return stringToWideString(src); } template // NOLINTNEXTLINE(readability-non-const-parameter) int getMainArgsCommon(int *argcOut, CharT ***argvOut, CharT ***envOut, Converter convert) { if (argcOut) { *argcOut = wibo::argc; } static StringListStorage argvStorage; static StringListStorage envStorage; if (argvOut) { *argvOut = argvStorage.assign(wibo::argv, convert); } CharT **envData = envStorage.assign(environ, convert); if (envOut) { *envOut = envData; } if constexpr (std::is_same_v) { __winitenv = envData; } else if constexpr (std::is_same_v) { __initenv = envData; } return 0; } template size_t envStringLength(const CharT *str) { if (!str) { return 0; } if constexpr (std::is_same_v) { return std::strlen(str); } else { return wstrlen(str); } } template int envStringCompare(const CharT *lhs, const CharT *rhs, size_t count) { if constexpr (std::is_same_v) { return std::strncmp(lhs, rhs, count); } else { return wstrncmp(lhs, rhs, count); } } template struct EnvLookupResult { const CharT *value; size_t length; }; template std::optional> findEnvironmentValue(CharT **env, const CharT *varname) { if (!env || !varname) { return std::nullopt; } size_t nameLength = envStringLength(varname); if (nameLength == 0) { return std::nullopt; } for (CharT **cursor = env; *cursor; ++cursor) { CharT *entry = *cursor; if (envStringCompare(entry, varname, nameLength) == 0 && entry[nameLength] == static_cast('=')) { const CharT *value = entry + nameLength + 1; return EnvLookupResult{value, envStringLength(value)}; } } return std::nullopt; } uint16_t **ensureWideEnvironment() { if (!__winitenv) { getMainArgsCommon(nullptr, nullptr, nullptr, copyWideString); } return __winitenv; } } // namespace // Stub because we're only ever a console application void WIN_ENTRY __set_app_type(int at) { } int* WIN_FUNC __p__fmode() { return &_fmode; } int* WIN_FUNC __p__commode() { return &_commode; } void WIN_ENTRY _initterm(const _PVFV *ppfn, const _PVFV* end) { for (; ppfn < end; ppfn++) { _PVFV func = *ppfn; if (func) { func(); } } } int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) { for (; ppfn < end; ppfn++) { _PIFV func = *ppfn; if (func) { int err = func(); if (err != 0) return err; } } return 0; } 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); return 0; } _PIFV WIN_ENTRY _onexit(_PIFV func) { DEBUG_LOG("_onexit(%p)\n", func); if(!func) return nullptr; if (atexit(reinterpret_cast(func)) != 0) return nullptr; return func; } // NOLINTNEXTLINE(readability-non-const-parameter) int WIN_ENTRY __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo) { DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard); (void)startInfo; if (doWildcard) { DEBUG_LOG("\tWildcard expansion is not implemented\n"); } std::setlocale(LC_CTYPE, ""); return getMainArgsCommon(wargc, wargv, wenv, copyWideString); } // NOLINTNEXTLINE(readability-non-const-parameter) int WIN_ENTRY __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo) { DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard); (void)startInfo; if (doWildcard) { DEBUG_LOG("\tWildcard expansion is not implemented\n"); } return getMainArgsCommon(argc, argv, env, copyNarrowString); } char* WIN_ENTRY getenv(const char *varname){ return std::getenv(varname); } char* WIN_ENTRY setlocale(int category, const char *locale){ return std::setlocale(category, locale); } int WIN_ENTRY _wdupenv_s(uint16_t **buffer, size_t *numberOfElements, const uint16_t *varname){ if (buffer) { *buffer = nullptr; } if (numberOfElements) { *numberOfElements = 0; } if (!buffer || !varname) { DEBUG_LOG("_wdupenv_s: invalid parameter\n"); errno = EINVAL; return EINVAL; } std::string var_str = wideStringToString(varname); DEBUG_LOG("_wdupenv_s: var name %s\n", var_str.c_str()); auto env = ensureWideEnvironment(); auto match = findEnvironmentValue(env, varname); if (!match) { DEBUG_LOG("Could not find env var %s\n", var_str.c_str()); return 0; } size_t value_len = match->length; auto *copy = static_cast(malloc((value_len + 1) * sizeof(uint16_t))); if (!copy) { DEBUG_LOG("_wdupenv_s: allocation failed\n"); errno = ENOMEM; return ENOMEM; } wstrncpy(copy, match->value, value_len); copy[value_len] = 0; *buffer = copy; if (numberOfElements) { *numberOfElements = value_len + 1; } return 0; } int WIN_ENTRY _wgetenv_s(size_t* pReturnValue, uint16_t* buffer, size_t numberOfElements, const uint16_t* varname){ if (pReturnValue) { *pReturnValue = 0; } if (numberOfElements > 0 && buffer) { buffer[0] = 0; } bool bufferRequired = numberOfElements != 0; if (!pReturnValue || !varname || (bufferRequired && !buffer)) { DEBUG_LOG("_wgetenv_s: invalid parameter\n"); errno = EINVAL; return EINVAL; } std::string var_str = wideStringToString(varname); DEBUG_LOG("_wgetenv_s: var name %s\n", var_str.c_str()); auto env = ensureWideEnvironment(); auto match = findEnvironmentValue(env, varname); if (!match) { return 0; } size_t required = match->length + 1; *pReturnValue = required; if (!bufferRequired || !buffer) { return 0; } if (required > numberOfElements) { errno = ERANGE; return ERANGE; } wstrncpy(buffer, match->value, match->length); buffer[match->length] = 0; return 0; } size_t WIN_ENTRY strlen(const char *str) { return ::strlen(str); } int WIN_ENTRY strcmp(const char *lhs, const char *rhs) { return ::strcmp(lhs, rhs); } int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) { return ::strncmp(lhs, rhs, count); } void* WIN_ENTRY malloc(size_t size){ return std::malloc(size); } void* WIN_ENTRY _malloc_crt(size_t size) { return std::malloc(size); } void WIN_ENTRY _lock(int locknum) { if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { DEBUG_LOG("_lock: unsupported lock %d\n", locknum); return; } lockTable()[static_cast(locknum)].lock(); } void WIN_ENTRY _unlock(int locknum) { if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { DEBUG_LOG("_unlock: unsupported lock %d\n", locknum); return; } lockTable()[static_cast(locknum)].unlock(); } _onexit_t WIN_ENTRY __dllonexit(_onexit_t func, _PVFV **pbegin, _PVFV **pend) { if (!pbegin || !pend) { return nullptr; } std::lock_guard guard(dllOnExitMutex()); auto &table = ensureDllOnExitTable(pbegin, pend); if (!table.registered) { wibo::registerOnExitTable(reinterpret_cast(pbegin)); table.registered = true; } if (func) { auto callback = reinterpret_cast<_PVFV>(func); table.callbacks.push_back(callback); wibo::addOnExitFunction(reinterpret_cast(pbegin), reinterpret_cast(callback)); } if (table.callbacks.empty()) { *pbegin = nullptr; *pend = nullptr; } else { _PVFV *dataPtr = table.callbacks.data(); *pbegin = dataPtr; *pend = dataPtr + table.callbacks.size(); } return reinterpret_cast<_onexit_t>(func); } void WIN_ENTRY free(void* ptr){ std::free(ptr); } static uint16_t toLower(uint16_t ch) { if (ch >= 'A' && ch <= 'Z') { return static_cast(ch + ('a' - 'A')); } wchar_t wide = static_cast(ch); wchar_t lowered = std::towlower(wide); if (lowered < 0 || lowered > 0xFFFF) { return ch; } return static_cast(lowered); } int WIN_ENTRY _wcsicmp(const uint16_t *lhs, const uint16_t *rhs) { if (lhs == rhs) { return 0; } if (!lhs) { return -1; } if (!rhs) { return 1; } while (*lhs && *rhs) { uint16_t a = toLower(*lhs++); uint16_t b = toLower(*rhs++); if (a != b) { return static_cast(a) - static_cast(b); } } uint16_t a = toLower(*lhs); uint16_t b = toLower(*rhs); return static_cast(a) - static_cast(b); } int WIN_ENTRY _get_wpgmptr(uint16_t** pValue){ DEBUG_LOG("_get_wpgmptr(%p)\n", pValue); if(!pValue) return 22; char exe_path[PATH_MAX]; ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); if(len == -1){ return 2; } exe_path[len] = 0; std::vector wStr = stringToWideString(exe_path); _wpgmptr = new uint16_t[wStr.size() + 1]; std::copy(wStr.begin(), wStr.end(), _wpgmptr); _wpgmptr[wStr.size()] = 0; *pValue = _wpgmptr; return 0; } 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()); } if(drive && driveNumberOfElements) drive[0] = L'\0'; if(dir && dirNumberOfElements) dir[0] = L'\0'; if(fname && nameNumberOfElements) fname[0] = L'\0'; if(ext && extNumberOfElements) ext[0] = L'\0'; const uint16_t *slash = wstrrchr(path, L'/'); const uint16_t *dot = wstrrchr(path, L'.'); const uint16_t *filename_start = slash ? slash + 1 : path; if (dot && dot < filename_start) dot = nullptr; if (dir && dirNumberOfElements && slash) { size_t dir_len = slash - path + 1; if (dir_len >= dirNumberOfElements) return 34; wstrncpy(dir, path, dir_len); dir[dir_len] = L'\0'; } if (fname && nameNumberOfElements) { size_t fname_len = dot ? (size_t)(dot - filename_start) : wstrlen(filename_start); if (fname_len >= nameNumberOfElements) return 34; wstrncpy(fname, filename_start, fname_len); fname[fname_len] = L'\0'; } if (ext && extNumberOfElements && dot) { size_t ext_len = wstrlen(dot); if (ext_len >= extNumberOfElements) return 34; wstrncpy(ext, dot, ext_len); ext[ext_len] = L'\0'; } if (drive && driveNumberOfElements && path[1] == L':' && path[2] == L'/') { if (driveNumberOfElements < 3) return 34; drive[0] = path[0]; drive[1] = L':'; drive[2] = L'\0'; } return 0; } int WIN_ENTRY wcscat_s(uint16_t *strDestination, size_t numberOfElements, const uint16_t *strSource){ std::string dst_str = wideStringToString(strDestination); std::string src_str = wideStringToString(strSource); DEBUG_LOG("wcscat_s %s %d %s", dst_str.c_str(), numberOfElements, src_str.c_str()); if(!strDestination || !strSource || numberOfElements == 0) return 22; size_t dest_len = wstrlen(strDestination); size_t src_len = wstrlen(strSource); if(dest_len + src_len + 1 > numberOfElements){ if(strDestination && numberOfElements > 0) strDestination[0] = L'\0'; return 34; } wstrcat(strDestination, strSource); dst_str = wideStringToString(strDestination); DEBUG_LOG(" --> %s\n", dst_str.c_str()); return 0; } uint16_t* WIN_ENTRY _wcsdup(const uint16_t *strSource){ // std::string src_str = wideStringToString(strSource); // DEBUG_LOG("_wcsdup: %s", src_str.c_str()); if(!strSource) return nullptr; size_t strLen = wstrlen(strSource); auto *dup = static_cast(malloc((strLen + 1) * sizeof(uint16_t))); if(!dup) return nullptr; for(size_t i = 0; i <= strLen; i++){ dup[i] = strSource[i]; } // std::string dst_str = wideStringToString(dup); // DEBUG_LOG(" --> %s\n", dst_str.c_str()); return dup; } int WIN_ENTRY _waccess_s(const uint16_t* path, int mode){ std::string str = wideStringToString(path); DEBUG_LOG("_waccess_s %s\n", str.c_str()); return access(str.c_str(), mode); } void* WIN_ENTRY memset(void *s, int c, size_t n){ return std::memset(s, c, n); } 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); if(!strDest || !strSource || numberOfElements == 0){ if(strDest && numberOfElements > 0) strDest[0] = L'\0'; return 1; } if(count == (size_t)-1) count = wstrlen(strSource); if(count >= numberOfElements){ strDest[0] = L'\0'; return 1; } wstrncpy(strDest, strSource, count); strDest[count] = L'\0'; // std::string dst_str = wideStringToString(strDest); // DEBUG_LOG(" --> %s\n", dst_str.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); if(!strDest || !strSource || numberOfElements == 0){ if(strDest && numberOfElements > 0) strDest[0] = L'\0'; return 1; } size_t dest_len = wstrlen(strDest); size_t src_len = (count == (size_t)-1) ? wstrlen(strSource) : wstrnlen(strSource, count); if(dest_len + src_len + 1 > numberOfElements){ strDest[0] = L'\0'; return 1; } wstrncat(strDest, strSource, src_len); dst_str = wideStringToString(strDest); DEBUG_LOG(" --> %s\n", dst_str.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); if (!buffer || size == 0) return 22; assert(radix == 10); // only base 10 supported for now std::string str = std::to_string(value); std::vector wStr = stringToWideString(str.c_str()); if(wStr.size() + 1 > size){ buffer[0] = 0; return 34; } std::copy(wStr.begin(), wStr.end(), buffer); buffer[wStr.size()] = 0; return 0; } int WIN_ENTRY _wtoi(const uint16_t* str) { DEBUG_LOG("_wtoi\n"); return wstrtol(str, nullptr, 10); } 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()); if (!dest || !src || dest_size == 0) { return 22; } if (wstrlen(src) + 1 > dest_size) { dest[0] = 0; return 34; } wstrcpy(dest, src); return 0; } int* WIN_ENTRY _get_osfhandle(int fd){ DEBUG_LOG("STUB: _get_osfhandle %d\n", fd); return (int*)fd; } int WIN_ENTRY _write(int fd, const void* buffer, unsigned int count) { return (int)write(fd, buffer, count); } void WIN_ENTRY exit(int status){ _Exit(status); } int WIN_ENTRY wcsncmp(const uint16_t *string1, const uint16_t *string2, size_t 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"); if (!buffer || !format || size == 0) return -1; std::string narrow_fmt = wideStringToString(format); DEBUG_LOG("\tFmt: %s\n", narrow_fmt.c_str()); va_list args; va_start(args, format); int required = vsnprintf(nullptr, 0, narrow_fmt.c_str(), args); va_end(args); if (required < 0) { buffer[0] = 0; return -1; } char buffer_narrow[required + 1]; va_start(args, format); vsnprintf(buffer_narrow, required + 1, narrow_fmt.c_str(), args); va_end(args); DEBUG_LOG("\tBuffer: %s\n", buffer_narrow); std::vector wide = stringToWideString(buffer_narrow); size_t copy_len = std::min(wide.size(), size - 1); std::memcpy(buffer, wide.data(), copy_len * sizeof(uint16_t)); buffer[copy_len] = 0; return static_cast(copy_len); // return vswprintf(buffer, size, format, args); this doesn't work because on this architecture, wchar_t is size 4, instead of size 2 } const uint16_t* WIN_ENTRY wcsstr( const uint16_t *dest, const uint16_t *src ){ return wstrstr(dest, src); } int WIN_ENTRY iswspace(uint32_t w){ return std::iswspace(w); } int WIN_ENTRY iswdigit(uint32_t w){ return std::iswdigit(w); } const uint16_t* WIN_ENTRY wcschr(const uint16_t* str, uint16_t c){ return wstrchr(str, c); } const uint16_t* WIN_ENTRY wcsrchr(const uint16_t *str, uint16_t c){ return wstrrchr(str, c); } unsigned long WIN_ENTRY wcstoul(const uint16_t *strSource, uint16_t **endptr, int base){ return wstrtoul(strSource, endptr, base); } int WIN_ENTRY _dup2(int fd1, int fd2){ return dup2(fd1, fd2); } FILE* WIN_ENTRY _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){ 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()); return fopen(fname_str.c_str(), mode_str.c_str()); } int WIN_ENTRY fputws(const uint16_t* str, FILE* stream){ if(!str || !stream) return EOF; std::string fname_str = wideStringToString(str); DEBUG_LOG("fputws %s\n", fname_str.c_str()); if(fputs(fname_str.c_str(), stream) < 0) return EOF; else return 0; } int WIN_ENTRY puts(const char *str) { if (!str) { str = "(null)"; } DEBUG_LOG("puts %s\n", str); if (std::fputs(str, stdout) < 0) return EOF; if (std::fputc('\n', stdout) == EOF) return EOF; return 0; } int WIN_ENTRY fclose(FILE* stream){ return ::fclose(stream); } int WIN_ENTRY _flushall(){ DEBUG_LOG("flushall\n"); int count = 0; if (fflush(stdin) == 0) count++; if (fflush(stdout) == 0) count++; if (fflush(stderr) == 0) count++; return count; } int* WIN_ENTRY _errno() { return &errno; } intptr_t WIN_ENTRY _wspawnvp(int mode, const uint16_t* cmdname, const uint16_t* const * argv){ std::string str_cmd = wideStringToString(cmdname); DEBUG_LOG("STUB: _wspawnvp %s\n", str_cmd.c_str()); return -1; } int WIN_ENTRY _wunlink(const uint16_t *filename){ std::string str = wideStringToString(filename); 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()); if(!relPath) return nullptr; char resolved[PATH_MAX]; char* realpathResult = realpath(relPathStr.c_str(), resolved); std::string finalPath; if(realpathResult){ finalPath = resolved; } else if (!relPathStr.empty() && relPathStr[0] == '\\') { // this is an absolute path - normalize it before assigning finalPath for (char& c : relPathStr) if (c == '\\') c = '/'; finalPath = relPathStr; } else { DEBUG_LOG("\tcould not find realpath, trying cwd...\n"); char cwd[PATH_MAX]; if(!getcwd(cwd, sizeof(cwd))){ return nullptr; } finalPath = std::string(cwd) + "/" + relPathStr; } std::vector wResolved = stringToWideString(finalPath.c_str()); // If caller provided a buffer, check size if (absPath) { if (wResolved.size() + 1 > maxLength) { return nullptr; // too small } std::copy(wResolved.begin(), wResolved.end(), absPath); absPath[wResolved.size()] = 0; std::string absPathStr = wideStringToString(absPath); DEBUG_LOG("\t-> abspath %s\n", absPathStr.c_str()); return absPath; } else { // Windows behavior: if absPath == NULL, allocate new auto *newBuf = new uint16_t[wResolved.size() + 1]; std::copy(wResolved.begin(), wResolved.end(), newBuf); newBuf[wResolved.size()] = 0; std::string absPathStr = wideStringToString(newBuf); DEBUG_LOG("\t-> abspath %s\n", absPathStr.c_str()); return newBuf; } } } static void *resolveByName(const char *name) { if (strcmp(name, "__set_app_type") == 0) return (void *) msvcrt::__set_app_type; if (strcmp(name, "_fmode") == 0) return (void *)&msvcrt::_fmode; if (strcmp(name, "_commode") == 0) return (void *)&msvcrt::_commode; if (strcmp(name, "__initenv") == 0) return (void *)&msvcrt::__initenv; if (strcmp(name, "__winitenv") == 0) return (void *)&msvcrt::__winitenv; if (strcmp(name, "__p__fmode") == 0) return (void *) msvcrt::__p__fmode; 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_s") == 0) return (void *)msvcrt::_controlfp_s; 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, "_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, "malloc") == 0) return (void*)msvcrt::malloc; if (strcmp(name, "_malloc_crt") == 0) return (void*)msvcrt::_malloc_crt; if (strcmp(name, "_lock") == 0) return (void*)msvcrt::_lock; if (strcmp(name, "_unlock") == 0) return (void*)msvcrt::_unlock; if (strcmp(name, "__dllonexit") == 0) return (void*)msvcrt::__dllonexit; if (strcmp(name, "free") == 0) return (void*)msvcrt::free; if (strcmp(name, "_wcsicmp") == 0) return (void*)msvcrt::_wcsicmp; if (strcmp(name, "_get_wpgmptr") == 0) return (void*)msvcrt::_get_wpgmptr; 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, "memset") == 0) return (void*)msvcrt::memset; if (strcmp(name, "wcsncpy_s") == 0) return (void*)msvcrt::wcsncpy_s; if (strcmp(name, "wcsncat_s") == 0) return (void*)msvcrt::wcsncat_s; if (strcmp(name, "_itow_s") == 0) return (void*)msvcrt::_itow_s; if (strcmp(name, "_wtoi") == 0) return (void*)msvcrt::_wtoi; 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, "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; if (strcmp(name, "wcsstr") == 0) return (void*)msvcrt::wcsstr; if (strcmp(name, "iswspace") == 0) return (void*)msvcrt::iswspace; if (strcmp(name, "wcsrchr") == 0) return (void*)msvcrt::wcsrchr; if (strcmp(name, "wcstoul") == 0) return (void*)msvcrt::wcstoul; if (strcmp(name, "iswdigit") == 0) return (void*)msvcrt::iswdigit; if (strcmp(name, "wcschr") == 0) return (void*)msvcrt::wcschr; 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, "_dup2") == 0) return (void*)msvcrt::_dup2; if (strcmp(name, "_wfsopen") == 0) return (void*)msvcrt::_wfsopen; 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, "_wspawnvp") == 0) return (void*)msvcrt::_wspawnvp; if (strcmp(name, "_wunlink") == 0) return (void*)msvcrt::_wunlink; if (strcmp(name, "_wfullpath") == 0) return (void*)msvcrt::_wfullpath; return nullptr; } wibo::Module lib_msvcrt = { (const char *[]){ "msvcrt", "msvcrt.dll", "msvcrt40", "msvcrt40.dll", "msvcr70", "msvcr70.dll", "msvcr100", "msvcr100.dll", nullptr, }, resolveByName, nullptr, };