mirror of
https://github.com/decompals/wibo.git
synced 2025-10-19 00:15:46 +00:00
msvcrt: Clean up __wgetmainargs, _wdupenv_s, _wgetenv_s; add __getmainargs
This commit is contained in:
parent
104e9e869d
commit
b5da26aa48
@ -7,17 +7,24 @@
|
|||||||
- Sample fixtures for exercising the loader live in `test/`; keep new repros small and self-contained.
|
- Sample fixtures for exercising the loader live in `test/`; keep new repros small and self-contained.
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
## Build, Test, and Development Commands
|
||||||
- `cmake -B build -DCMAKE_BUILD_TYPE=Debug` configures a 32-bit toolchain; ensure multilib packages are present.
|
- `cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` configures a 32-bit toolchain; ensure multilib packages are present.
|
||||||
- `cmake --build build --target wibo` compiles the shim; switch to `-DCMAKE_BUILD_TYPE=Release` for optimised binaries.
|
- `cmake --build build --target wibo` compiles the shim; switch to `-DCMAKE_BUILD_TYPE=Release` for optimised binaries.
|
||||||
- `./build/wibo /path/to/program.exe` runs a Windows binary through the shim; use `WIBO_DEBUG=1` for verbose logging.
|
- `./build/wibo /path/to/program.exe` runs a Windows binary through the shim; use `WIBO_DEBUG=1` for verbose logging.
|
||||||
- `cmake -B build -DBUILD_TESTING=ON` + `ctest --test-dir build --output-on-failure` runs the self-checking WinAPI fixtures (requires `i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`).
|
- `cmake -B build -DBUILD_TESTING=ON` + `ctest --test-dir build --output-on-failure` runs the self-checking WinAPI fixtures (requires `i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`).
|
||||||
- `clang-format -i path/to/file.cpp` and `clang-tidy path/to/file.cpp -p build` keep contributions aligned with the repo's tooling.
|
- `clang-format -i path/to/file.cpp` and `clang-tidy path/to/file.cpp -p build` keep contributions aligned with the repo's tooling.
|
||||||
|
- DON'T use `clang-format` on existing files, only new or heavily modified ones; the repo hasn't been fully formatted yet.
|
||||||
|
|
||||||
## Coding Style & Naming Conventions
|
## Coding Style & Naming Conventions
|
||||||
- Formatting follows `.clang-format` (LLVM base, tabbed indentation width 4, 120 column limit); never hand-wrap differently.
|
- Formatting follows `.clang-format` (LLVM base, tabbed indentation width 4, 120 column limit); never hand-wrap differently.
|
||||||
- Prefer PascalCase for emulated Win32 entry points, camelCase for internal helpers, and SCREAMING_SNAKE_CASE for constants or macros.
|
- Prefer PascalCase for emulated Win32 entry points, camelCase for internal helpers, and SCREAMING_SNAKE_CASE for constants or macros.
|
||||||
- Document non-obvious control flow with short comments and keep platform-specific code paths behind descriptive helper functions.
|
- Document non-obvious control flow with short comments and keep platform-specific code paths behind descriptive helper functions.
|
||||||
|
|
||||||
|
## Shim Implementation Guidelines
|
||||||
|
- Target pre-XP behavior; our binaries are old and don't expect modern WinAPI behavior.
|
||||||
|
- Use the `microsoft_docs` tools to fetch WinAPI signatures and documentation; always fetch the documentation when working on an API function.
|
||||||
|
- Create minimal, self-contained repros in `test/` when implementing or debugging APIs; this aids both development and future testing.
|
||||||
|
- Stub unimplemented APIs with `DEBUG_LOG` calls to track usage; prioritize based on the needs of real-world binaries.
|
||||||
|
|
||||||
## Testing Guidelines
|
## Testing Guidelines
|
||||||
- Fixture binaries live in `test/` and are compiled automatically when `BUILD_TESTING` is enabled; keep new repros small and self-contained (`test_<feature>.c`).
|
- Fixture binaries live in `test/` and are compiled automatically when `BUILD_TESTING` is enabled; keep new repros small and self-contained (`test_<feature>.c`).
|
||||||
- All fixtures must self-assert; use `test_assert.h` helpers so `ctest` fails on mismatched WinAPI behaviour.
|
- All fixtures must self-assert; use `test_assert.h` helpers so `ctest` fails on mismatched WinAPI behaviour.
|
||||||
|
@ -1907,25 +1907,6 @@ namespace kernel32 {
|
|||||||
DEBUG_LOG("-> %p\n", result);
|
DEBUG_LOG("-> %p\n", result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DEBUG_LOG("VirtualAlloc %p %u %u %u\n",lpAddress, dwSize, flAllocationType, flProtect);
|
|
||||||
// if (flAllocationType & 0x2000 || lpAddress == NULL) { // MEM_RESERVE
|
|
||||||
// // do this for now...
|
|
||||||
// assert(lpAddress == NULL);
|
|
||||||
// void *mem = 0;
|
|
||||||
// posix_memalign(&mem, 0x1000, dwSize);
|
|
||||||
// memset(mem, 0, dwSize);
|
|
||||||
|
|
||||||
// // Windows only fences off the lower 2GB of the 32-bit address space for the private use of processes.
|
|
||||||
// assert(mem < (void*)0x80000000);
|
|
||||||
|
|
||||||
// DEBUG_LOG("-> %p\n", mem);
|
|
||||||
// return mem;
|
|
||||||
// } else {
|
|
||||||
// assert(lpAddress != NULL);
|
|
||||||
// return lpAddress;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int WIN_FUNC VirtualFree(void *lpAddress, unsigned int dwSize, int dwFreeType) {
|
unsigned int WIN_FUNC VirtualFree(void *lpAddress, unsigned int dwSize, int dwFreeType) {
|
||||||
|
368
dll/msvcrt.cpp
368
dll/msvcrt.cpp
@ -1,16 +1,21 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <climits>
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <cwctype>
|
#include <cwctype>
|
||||||
#include <errno.h>
|
#include <memory>
|
||||||
#include <limits.h>
|
#include <optional>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
|
||||||
typedef void (*_PVFV)();
|
typedef void (*_PVFV)();
|
||||||
@ -19,9 +24,152 @@ typedef int (*_PIFV)();
|
|||||||
namespace msvcrt {
|
namespace msvcrt {
|
||||||
int _commode;
|
int _commode;
|
||||||
int _fmode;
|
int _fmode;
|
||||||
|
char** __initenv;
|
||||||
uint16_t** __winitenv;
|
uint16_t** __winitenv;
|
||||||
uint16_t* _wpgmptr;
|
uint16_t* _wpgmptr;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename CharT>
|
||||||
|
struct StringListStorage {
|
||||||
|
std::vector<std::unique_ptr<CharT[]>> strings;
|
||||||
|
std::unique_ptr<CharT*[]> pointers;
|
||||||
|
|
||||||
|
template <typename Converter>
|
||||||
|
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<CharT *[]>(count + 1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
auto data = convert(source[i]);
|
||||||
|
auto buffer = std::make_unique<CharT[]>(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<char> copyNarrowString(const char *src) {
|
||||||
|
if (!src) {
|
||||||
|
src = "";
|
||||||
|
}
|
||||||
|
size_t len = std::strlen(src);
|
||||||
|
std::vector<char> result(len + 1);
|
||||||
|
if (len > 0) {
|
||||||
|
std::memcpy(result.data(), src, len);
|
||||||
|
}
|
||||||
|
result[len] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint16_t> copyWideString(const char *src) {
|
||||||
|
if (!src) {
|
||||||
|
src = "";
|
||||||
|
}
|
||||||
|
return stringToWideString(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, typename Converter>
|
||||||
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
|
int getMainArgsCommon(int *argcOut, CharT ***argvOut, CharT ***envOut, Converter convert) {
|
||||||
|
if (argcOut) {
|
||||||
|
*argcOut = wibo::argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringListStorage<CharT> argvStorage;
|
||||||
|
static StringListStorage<CharT> 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<CharT, uint16_t>) {
|
||||||
|
__winitenv = envData;
|
||||||
|
} else if constexpr (std::is_same_v<CharT, char>) {
|
||||||
|
__initenv = envData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
size_t envStringLength(const CharT *str) {
|
||||||
|
if (!str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if constexpr (std::is_same_v<CharT, char>) {
|
||||||
|
return std::strlen(str);
|
||||||
|
} else {
|
||||||
|
return wstrlen(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
int envStringCompare(const CharT *lhs, const CharT *rhs, size_t count) {
|
||||||
|
if constexpr (std::is_same_v<CharT, char>) {
|
||||||
|
return std::strncmp(lhs, rhs, count);
|
||||||
|
} else {
|
||||||
|
return wstrncmp(lhs, rhs, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
struct EnvLookupResult {
|
||||||
|
const CharT *value;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
std::optional<EnvLookupResult<CharT>> 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<CharT>('=')) {
|
||||||
|
const CharT *value = entry + nameLength + 1;
|
||||||
|
return EnvLookupResult<CharT>{value, envStringLength(value)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t **ensureWideEnvironment() {
|
||||||
|
if (!__winitenv) {
|
||||||
|
getMainArgsCommon<uint16_t>(nullptr, nullptr, nullptr, copyWideString);
|
||||||
|
}
|
||||||
|
return __winitenv;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Stub because we're only ever a console application
|
// Stub because we're only ever a console application
|
||||||
void WIN_ENTRY __set_app_type(int at) {
|
void WIN_ENTRY __set_app_type(int at) {
|
||||||
}
|
}
|
||||||
@ -63,80 +211,30 @@ namespace msvcrt {
|
|||||||
_PIFV WIN_ENTRY _onexit(_PIFV func) {
|
_PIFV WIN_ENTRY _onexit(_PIFV func) {
|
||||||
DEBUG_LOG("_onexit(%p)\n", func);
|
DEBUG_LOG("_onexit(%p)\n", func);
|
||||||
if(!func) return nullptr;
|
if(!func) return nullptr;
|
||||||
if (atexit((void(*)(void))func) != 0) return nullptr;
|
if (atexit(reinterpret_cast<void (*)()>(func)) != 0) return nullptr;
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wgetmainargs references:
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
// https://github.com/reactos/reactos/blob/fade0c3b8977d43f3a9e0b8887d18afcabd8e145/sdk/lib/crt/misc/getargs.c#L328
|
int WIN_ENTRY __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo) {
|
||||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=msvc-170
|
DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard);
|
||||||
|
(void)startInfo;
|
||||||
int WIN_ENTRY __wgetmainargs(int* wargc, uint16_t*** wargv, uint16_t*** wenv, int doWildcard, int* startInfo){
|
if (doWildcard) {
|
||||||
DEBUG_LOG("__wgetmainargs\n");
|
DEBUG_LOG("\tWildcard expansion is not implemented\n");
|
||||||
// get the regular, non-wide versions of argc/argv/env
|
}
|
||||||
// argc: the number of args in argv. always >= 1
|
|
||||||
// argv: array of null-terminated strings for command-line args.
|
|
||||||
// argv[0] = the command to invoke the program
|
|
||||||
// argv[1] = the first command-line arg
|
|
||||||
// argv[argc - 1] = the last command-line arg
|
|
||||||
// argv[argc] = NULL
|
|
||||||
// env: array of strings for user's environment variables. always terminated by NULL entry.
|
|
||||||
int* regular_argc = &wibo::argc;
|
|
||||||
char*** regular_argv = &wibo::argv;
|
|
||||||
char** regular_env = environ;
|
|
||||||
|
|
||||||
int argc = *regular_argc;
|
|
||||||
char** argv = *regular_argv;
|
|
||||||
char** env = regular_env;
|
|
||||||
|
|
||||||
// DEBUG_LOG("Wildcard: %d\n", doWildcard);
|
|
||||||
// if(startInfo){
|
|
||||||
// DEBUG_LOG("Start info: %d\n", *startInfo);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(wargc) *wargc = argc;
|
|
||||||
|
|
||||||
std::setlocale(LC_CTYPE, "");
|
std::setlocale(LC_CTYPE, "");
|
||||||
|
return getMainArgsCommon<uint16_t>(wargc, wargv, wenv, copyWideString);
|
||||||
|
}
|
||||||
|
|
||||||
if(wargv){
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
*wargv = new uint16_t*[argc + 1]; // allocate array of our future wstrings
|
int WIN_ENTRY __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo) {
|
||||||
for(int i = 0; i < argc; i++){
|
DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard);
|
||||||
const char* cur_arg = argv[i];
|
(void)startInfo;
|
||||||
|
if (doWildcard) {
|
||||||
std::vector<uint16_t> wStr = stringToWideString(cur_arg);
|
DEBUG_LOG("\tWildcard expansion is not implemented\n");
|
||||||
|
|
||||||
// allocate a copy on the heap,
|
|
||||||
// since wStr will go out of scope
|
|
||||||
(*wargv)[i] = new uint16_t[wStr.size() + 1];
|
|
||||||
std::copy(wStr.begin(), wStr.end(), (*wargv)[i]);
|
|
||||||
(*wargv)[i][wStr.size()] = 0;
|
|
||||||
}
|
|
||||||
(*wargv)[argc] = nullptr;
|
|
||||||
}
|
}
|
||||||
|
return getMainArgsCommon<char>(argc, argv, env, copyNarrowString);
|
||||||
if(wenv){
|
|
||||||
int count = 0;
|
|
||||||
for(; env[count] != nullptr; count++);
|
|
||||||
// DEBUG_LOG("Found env count %d\n", count);
|
|
||||||
*wenv = new uint16_t*[count + 1]; // allocate array of our future wstrings
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
const char* cur_env = env[i];
|
|
||||||
// DEBUG_LOG("Adding env %s\n", cur_env);
|
|
||||||
|
|
||||||
std::vector<uint16_t> wStr = stringToWideString(cur_env);
|
|
||||||
|
|
||||||
// allocate a copy on the heap,
|
|
||||||
// since wStr will go out of scope
|
|
||||||
(*wenv)[i] = new uint16_t[wStr.size() + 1];
|
|
||||||
std::copy(wStr.begin(), wStr.end(), (*wenv)[i]);
|
|
||||||
(*wenv)[i][wStr.size()] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*wenv)[count] = nullptr;
|
|
||||||
|
|
||||||
__winitenv = *wenv;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* WIN_ENTRY getenv(const char *varname){
|
char* WIN_ENTRY getenv(const char *varname){
|
||||||
@ -148,65 +246,83 @@ namespace msvcrt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int WIN_ENTRY _wdupenv_s(uint16_t **buffer, size_t *numberOfElements, const uint16_t *varname){
|
int WIN_ENTRY _wdupenv_s(uint16_t **buffer, size_t *numberOfElements, const uint16_t *varname){
|
||||||
std::string var_str = wideStringToString(varname);
|
if (buffer) {
|
||||||
DEBUG_LOG("_wdupenv_s: var name %s\n", var_str.c_str());
|
*buffer = nullptr;
|
||||||
if(!buffer || !varname) return 22;
|
}
|
||||||
*buffer = nullptr;
|
if (numberOfElements) {
|
||||||
if(numberOfElements) *numberOfElements = 0;
|
*numberOfElements = 0;
|
||||||
|
|
||||||
size_t varnamelen = wstrlen(varname);
|
|
||||||
|
|
||||||
// DEBUG_LOG("\tSearching env vars...\n");
|
|
||||||
for(uint16_t** env = __winitenv; env && *env; ++env){
|
|
||||||
uint16_t* cur = *env;
|
|
||||||
std::string cur_str = wideStringToString(cur);
|
|
||||||
// DEBUG_LOG("\tCur env var: %s\n", cur_str.c_str());
|
|
||||||
if(wstrncmp(cur, varname, varnamelen) == 0 && cur[varnamelen] == L'='){
|
|
||||||
DEBUG_LOG("Found the env var %s!\n", var_str.c_str());
|
|
||||||
uint16_t* value = cur + varnamelen + 1;
|
|
||||||
size_t value_len = wstrlen(value);
|
|
||||||
|
|
||||||
uint16_t* copy = (uint16_t*)malloc((value_len + 1) * sizeof(uint16_t));
|
|
||||||
if(!copy) return 12;
|
|
||||||
|
|
||||||
wstrncpy(copy, value, value_len + 1);
|
|
||||||
*buffer = copy;
|
|
||||||
|
|
||||||
if(numberOfElements) *numberOfElements = value_len + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Could not find env var %s\n", var_str.c_str());
|
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<uint16_t *>(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WIN_ENTRY _wgetenv_s(size_t* pReturnValue, uint16_t* buffer, size_t numberOfElements, const uint16_t* varname){
|
int WIN_ENTRY _wgetenv_s(size_t* pReturnValue, uint16_t* buffer, size_t numberOfElements, const uint16_t* varname){
|
||||||
std::string var_str = wideStringToString(varname);
|
if (pReturnValue) {
|
||||||
DEBUG_LOG("_wgetenv_s: var name %s\n", var_str.c_str());
|
*pReturnValue = 0;
|
||||||
if(!buffer || !varname) return 22;
|
}
|
||||||
|
if (numberOfElements > 0 && buffer) {
|
||||||
size_t varnamelen = wstrlen(varname);
|
buffer[0] = 0;
|
||||||
|
|
||||||
for(uint16_t** env = __winitenv; env && *env; ++env){
|
|
||||||
uint16_t* cur = *env;
|
|
||||||
// std::string cur_str = wideStringToString(cur);
|
|
||||||
// DEBUG_LOG("\tCur env var: %s\n", cur_str.c_str());
|
|
||||||
if(wstrncmp(cur, varname, varnamelen) == 0 && cur[varnamelen] == L'='){
|
|
||||||
uint16_t* value = cur + varnamelen + 1;
|
|
||||||
size_t value_len = wstrlen(value);
|
|
||||||
|
|
||||||
size_t copy_len = (value_len < numberOfElements - 1) ? value_len : numberOfElements - 1;
|
|
||||||
wstrncpy(buffer, value, copy_len);
|
|
||||||
buffer[copy_len] = 0;
|
|
||||||
|
|
||||||
if(pReturnValue) *pReturnValue = value_len + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[0] = 0;
|
bool bufferRequired = numberOfElements != 0;
|
||||||
if(pReturnValue) *pReturnValue = 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +434,7 @@ namespace msvcrt {
|
|||||||
if(!strSource) return nullptr;
|
if(!strSource) return nullptr;
|
||||||
size_t strLen = wstrlen(strSource);
|
size_t strLen = wstrlen(strSource);
|
||||||
|
|
||||||
uint16_t* dup = (uint16_t*)malloc((strLen + 1) * sizeof(uint16_t));
|
auto *dup = static_cast<uint16_t *>(malloc((strLen + 1) * sizeof(uint16_t)));
|
||||||
if(!dup) return nullptr;
|
if(!dup) return nullptr;
|
||||||
|
|
||||||
for(size_t i = 0; i <= strLen; i++){
|
for(size_t i = 0; i <= strLen; i++){
|
||||||
@ -471,7 +587,7 @@ namespace msvcrt {
|
|||||||
std::memcpy(buffer, wide.data(), copy_len * sizeof(uint16_t));
|
std::memcpy(buffer, wide.data(), copy_len * sizeof(uint16_t));
|
||||||
buffer[copy_len] = 0;
|
buffer[copy_len] = 0;
|
||||||
|
|
||||||
return copy_len;
|
return static_cast<int>(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
|
// return vswprintf(buffer, size, format, args); this doesn't work because on this architecture, wchar_t is size 4, instead of size 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,7 +721,7 @@ namespace msvcrt {
|
|||||||
return absPath;
|
return absPath;
|
||||||
} else {
|
} else {
|
||||||
// Windows behavior: if absPath == NULL, allocate new
|
// Windows behavior: if absPath == NULL, allocate new
|
||||||
uint16_t* newBuf = new uint16_t[wResolved.size() + 1];
|
auto *newBuf = new uint16_t[wResolved.size() + 1];
|
||||||
std::copy(wResolved.begin(), wResolved.end(), newBuf);
|
std::copy(wResolved.begin(), wResolved.end(), newBuf);
|
||||||
newBuf[wResolved.size()] = 0;
|
newBuf[wResolved.size()] = 0;
|
||||||
|
|
||||||
@ -622,6 +738,7 @@ static void *resolveByName(const char *name) {
|
|||||||
if (strcmp(name, "__set_app_type") == 0) return (void *) msvcrt::__set_app_type;
|
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, "_fmode") == 0) return (void *)&msvcrt::_fmode;
|
||||||
if (strcmp(name, "_commode") == 0) return (void *)&msvcrt::_commode;
|
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, "__winitenv") == 0) return (void *)&msvcrt::__winitenv;
|
||||||
if (strcmp(name, "__p__fmode") == 0) return (void *) msvcrt::__p__fmode;
|
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, "__p__commode") == 0) return (void *) msvcrt::__p__commode;
|
||||||
@ -629,6 +746,7 @@ static void *resolveByName(const char *name) {
|
|||||||
if (strcmp(name, "_initterm_e") == 0) return (void *)msvcrt::_initterm_e;
|
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, "_controlfp_s") == 0) return (void *)msvcrt::_controlfp_s;
|
||||||
if (strcmp(name, "_onexit") == 0) return (void*)msvcrt::_onexit;
|
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, "__wgetmainargs") == 0) return (void*)msvcrt::__wgetmainargs;
|
||||||
if (strcmp(name, "setlocale") == 0) return (void*)msvcrt::setlocale;
|
if (strcmp(name, "setlocale") == 0) return (void*)msvcrt::setlocale;
|
||||||
if (strcmp(name, "_wdupenv_s") == 0) return (void*)msvcrt::_wdupenv_s;
|
if (strcmp(name, "_wdupenv_s") == 0) return (void*)msvcrt::_wdupenv_s;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user