mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 06:45:05 +00:00
Numerous msvcrt/crt fixes; support variable resolution
This commit is contained in:
30
dll/crt.cpp
30
dll/crt.cpp
@@ -15,6 +15,25 @@
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
FILE *mapToHostFile(_FILE *file) {
|
||||
if (!file)
|
||||
return nullptr;
|
||||
switch (file->_file) {
|
||||
case STDIN_FILENO:
|
||||
return stdin;
|
||||
case STDOUT_FILENO:
|
||||
return stdout;
|
||||
case STDERR_FILENO:
|
||||
return stderr;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crt {
|
||||
|
||||
int _commode = 0;
|
||||
@@ -302,15 +321,18 @@ void *CDECL __acrt_iob_func(unsigned int index) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale,
|
||||
va_list args) {
|
||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
|
||||
va_list args) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
|
||||
return vfprintf(stream, format, args);
|
||||
FILE *hostFile = mapToHostFile(stream);
|
||||
if (!hostFile)
|
||||
return -1;
|
||||
return vfprintf(hostFile, format, args);
|
||||
}
|
||||
|
||||
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
|
||||
void *locale, va_list args) {
|
||||
void *locale, va_list args) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale);
|
||||
if (!buffer || !format)
|
||||
|
||||
20
dll/crt.h
20
dll/crt.h
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef void (_CC_CDECL *_PVFV)();
|
||||
typedef int (_CC_CDECL *_PIFV)();
|
||||
typedef void (_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR);
|
||||
typedef void(_CC_CDECL *_PVFV)();
|
||||
typedef int(_CC_CDECL *_PIFV)();
|
||||
typedef void(_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR);
|
||||
|
||||
typedef enum _crt_app_type {
|
||||
_crt_unknown_app,
|
||||
@@ -18,12 +18,14 @@ typedef enum _crt_argv_mode {
|
||||
_crt_argv_expanded_arguments,
|
||||
} _crt_argv_mode;
|
||||
|
||||
typedef void (_CC_CDECL *signal_handler)(int);
|
||||
typedef int (_CC_CDECL *sort_compare)(const void *, const void *);
|
||||
using FILE = struct _IO_FILE;
|
||||
typedef void(_CC_CDECL *signal_handler)(int);
|
||||
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
||||
|
||||
namespace crt {
|
||||
|
||||
extern int _commode;
|
||||
extern int _fmode;
|
||||
|
||||
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
|
||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
|
||||
void CDECL _set_app_type(_crt_app_type type);
|
||||
@@ -65,10 +67,10 @@ void CDECL _exit(int status);
|
||||
void CDECL abort();
|
||||
signal_handler CDECL signal(int signum, signal_handler handler);
|
||||
void *CDECL __acrt_iob_func(unsigned int index);
|
||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale,
|
||||
va_list args);
|
||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
|
||||
va_list args);
|
||||
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
|
||||
void *locale, va_list args);
|
||||
void *locale, va_list args);
|
||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
||||
int CDECL puts(const char *str);
|
||||
|
||||
|
||||
230
dll/msvcrt.cpp
230
dll/msvcrt.cpp
@@ -34,6 +34,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <spawn.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -50,7 +51,48 @@
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
using _onexit_t = _PIFV;
|
||||
namespace {
|
||||
|
||||
std::mutex g_fileMutex;
|
||||
std::unordered_map<int, FILE *> g_files;
|
||||
|
||||
FILE *mapToHostFile(_FILE *file) {
|
||||
if (!file)
|
||||
return nullptr;
|
||||
switch (file->_file) {
|
||||
case -1:
|
||||
return nullptr;
|
||||
case STDIN_FILENO:
|
||||
return stdin;
|
||||
case STDOUT_FILENO:
|
||||
return stdout;
|
||||
case STDERR_FILENO:
|
||||
return stderr;
|
||||
default:
|
||||
return g_files[file->_file];
|
||||
}
|
||||
}
|
||||
|
||||
_FILE *mapToGuestFile(FILE *file) {
|
||||
if (!file)
|
||||
return nullptr;
|
||||
int fd = file->_fileno;
|
||||
_FILE *out = new (wibo::heap::guestMalloc(sizeof(_FILE))) _FILE(fd);
|
||||
std::lock_guard lock(g_fileMutex);
|
||||
g_files[fd] = file;
|
||||
return out;
|
||||
}
|
||||
|
||||
int closeGuestFile(_FILE *file) {
|
||||
if (!file)
|
||||
return -1;
|
||||
int fd = file->_file;
|
||||
std::lock_guard lock(g_fileMutex);
|
||||
g_files.erase(fd);
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace msvcrt {
|
||||
int _commode;
|
||||
@@ -59,13 +101,15 @@ namespace msvcrt {
|
||||
uint16_t** __winitenv;
|
||||
uint16_t* _wpgmptr = nullptr;
|
||||
char* _pgmptr = nullptr;
|
||||
int __mb_cur_max = 1;
|
||||
_FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}};
|
||||
|
||||
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
|
||||
|
||||
@@ -103,7 +147,7 @@ namespace msvcrt {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int mbCurMaxForCodePage(int codepage);
|
||||
int mbCurMaxForCodePage(int codepage);
|
||||
|
||||
void updateMbctypeForCodePage(int codepage) {
|
||||
auto &table = mbctypeTable();
|
||||
@@ -158,7 +202,7 @@ namespace msvcrt {
|
||||
void ensureMbctypeInitialized() {
|
||||
std::call_once(mbctypeInitFlag(), []() {
|
||||
updateMbctypeForCodePage(mbCodePageSetting);
|
||||
mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting);
|
||||
__mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -205,52 +249,21 @@ namespace msvcrt {
|
||||
return storage;
|
||||
}
|
||||
|
||||
IOBProxy *standardIobEntries() {
|
||||
static IOBProxy entries[3] = {};
|
||||
return entries;
|
||||
_FILE *standardIobEntries() {
|
||||
return _iob;
|
||||
}
|
||||
|
||||
IOBProxy *CDECL __iob_func() {
|
||||
_FILE *CDECL __iob_func() {
|
||||
HOST_CONTEXT_GUARD();
|
||||
return standardIobEntries();
|
||||
return _iob;
|
||||
}
|
||||
|
||||
IOBProxy *CDECL __p__iob() {
|
||||
_FILE *CDECL __p__iob() {
|
||||
HOST_CONTEXT_GUARD();
|
||||
return standardIobEntries();
|
||||
return _iob;
|
||||
}
|
||||
|
||||
std::unordered_map<void *, FILE *> &iobMapping() {
|
||||
static std::unordered_map<void *, FILE *> mapping;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
std::once_flag &iobInitFlag() {
|
||||
static std::once_flag flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
void initializeIobMapping() {
|
||||
std::call_once(iobInitFlag(), []() {
|
||||
auto &mapping = iobMapping();
|
||||
IOBProxy *entries = standardIobEntries();
|
||||
mapping.emplace(static_cast<void *>(&entries[0]), stdin);
|
||||
mapping.emplace(static_cast<void *>(&entries[1]), stdout);
|
||||
mapping.emplace(static_cast<void *>(&entries[2]), stderr);
|
||||
});
|
||||
}
|
||||
|
||||
FILE *mapToHostFile(FILE *stream) {
|
||||
initializeIobMapping();
|
||||
auto &mapping = iobMapping();
|
||||
auto it = mapping.find(stream);
|
||||
if (it != mapping.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
void CDECL setbuf(FILE *stream, char *buffer) {
|
||||
void CDECL setbuf(_FILE *stream, char *buffer) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("setbuf(%p, %p)\n", stream, buffer);
|
||||
if (!stream) {
|
||||
@@ -329,7 +342,7 @@ namespace msvcrt {
|
||||
ext ? ext : "");
|
||||
}
|
||||
|
||||
int CDECL _fileno(FILE *stream) {
|
||||
int CDECL _fileno(_FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("_fileno(%p)\n", stream);
|
||||
if (!stream) {
|
||||
@@ -340,7 +353,7 @@ namespace msvcrt {
|
||||
return ::fileno(host);
|
||||
}
|
||||
|
||||
unsigned int mbCurMaxForCodePage(int codepage) {
|
||||
int mbCurMaxForCodePage(int codepage) {
|
||||
switch (codepage) {
|
||||
case MB_CP_SBCS:
|
||||
case MB_CP_ANSI:
|
||||
@@ -363,7 +376,7 @@ namespace msvcrt {
|
||||
|
||||
void refreshMbCurMax() {
|
||||
ensureMbctypeInitialized();
|
||||
mbCurMaxValue = mbCurMaxForCodePage(mbCodePageSetting);
|
||||
__mb_cur_max = mbCurMaxForCodePage(mbCodePageSetting);
|
||||
}
|
||||
|
||||
int CDECL _getmbcp() {
|
||||
@@ -373,11 +386,11 @@ namespace msvcrt {
|
||||
return mbCodePageSetting;
|
||||
}
|
||||
|
||||
unsigned int* CDECL __p___mb_cur_max() {
|
||||
int* CDECL __p___mb_cur_max() {
|
||||
HOST_CONTEXT_GUARD();
|
||||
ensureMbctypeInitialized();
|
||||
DEBUG_LOG("__p___mb_cur_max() -> %u\n", mbCurMaxValue);
|
||||
return &mbCurMaxValue;
|
||||
DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max);
|
||||
return &__mb_cur_max;
|
||||
}
|
||||
|
||||
int CDECL _setmbcp(int codepage) {
|
||||
@@ -402,7 +415,7 @@ namespace msvcrt {
|
||||
|
||||
mbCodePageSetting = codepage;
|
||||
updateMbctypeForCodePage(codepage);
|
||||
mbCurMaxValue = mbCurMaxForCodePage(codepage);
|
||||
__mb_cur_max = mbCurMaxForCodePage(codepage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -729,11 +742,20 @@ namespace msvcrt {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_PIFV CDECL _onexit(_PIFV func) {
|
||||
static void runExitFunc(int status, void *arg) {
|
||||
(void)status;
|
||||
(void)call__onexit_t(reinterpret_cast<_onexit_t>(arg));
|
||||
}
|
||||
|
||||
_onexit_t CDECL _onexit(_onexit_t func) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("_onexit(%p)\n", func);
|
||||
if(!func) return nullptr;
|
||||
if (atexit(reinterpret_cast<void (*)()>(func)) != 0) return nullptr;
|
||||
if (!func) {
|
||||
return nullptr;
|
||||
}
|
||||
if (on_exit(runExitFunc, reinterpret_cast<void *>(func)) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -1129,7 +1151,7 @@ namespace msvcrt {
|
||||
return result;
|
||||
}
|
||||
|
||||
char *CDECL fgets(char *str, int count, FILE *stream) {
|
||||
char *CDECL fgets(char *str, int count, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fgets(%p, %d, %p)\n", str, count, stream);
|
||||
if (!str || count <= 0) {
|
||||
@@ -1139,14 +1161,14 @@ namespace msvcrt {
|
||||
return ::fgets(str, count, host);
|
||||
}
|
||||
|
||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, FILE *stream) {
|
||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fread(%p, %zu, %zu, %p)\n", buffer, size, count, stream);
|
||||
FILE *host = mapToHostFile(stream);
|
||||
return ::fread(buffer, size, count, host);
|
||||
}
|
||||
|
||||
FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) {
|
||||
_FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("_fsopen(%s, %s, %d)\n", filename ? filename : "(null)", mode ? mode : "(null)", shflag);
|
||||
(void)shflag;
|
||||
@@ -1155,7 +1177,7 @@ namespace msvcrt {
|
||||
return nullptr;
|
||||
}
|
||||
auto hostPath = files::pathFromWindows(filename);
|
||||
return ::fopen(hostPath.c_str(), mode);
|
||||
return mapToGuestFile(::fopen(hostPath.c_str(), mode));
|
||||
}
|
||||
|
||||
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode) {
|
||||
@@ -1802,13 +1824,18 @@ namespace msvcrt {
|
||||
return std::memcmp(lhs, rhs, count);
|
||||
}
|
||||
|
||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, int (*compar)(const void *, const void *)) {
|
||||
static thread_local sort_compare currentCompare = nullptr;
|
||||
|
||||
static int doCompare(const void *a, const void *b) { return call_sort_compare(currentCompare, a, b); }
|
||||
|
||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compar);
|
||||
std::qsort(base, num, size, compar);
|
||||
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compare);
|
||||
currentCompare = compare;
|
||||
::qsort(base, num, size, doCompare);
|
||||
}
|
||||
|
||||
int CDECL fflush(FILE *stream) {
|
||||
int CDECL fflush(_FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fflush(%p)\n", stream);
|
||||
if (!stream) {
|
||||
@@ -1818,10 +1845,10 @@ namespace msvcrt {
|
||||
return std::fflush(host);
|
||||
}
|
||||
|
||||
int CDECL_NO_CONV vfwprintf(FILE *stream, const uint16_t *format, va_list args) {
|
||||
int CDECL_NO_CONV vfwprintf(_FILE *stream, const uint16_t *format, va_list args) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("vfwprintf(%p, %s, ...)\n", stream, wideStringToString(format).c_str());
|
||||
FILE *host = mapToHostFile(stream ? stream : stdout);
|
||||
FILE *host = mapToHostFile(stream ? stream : &_iob[0]);
|
||||
std::wstring fmt;
|
||||
if (format) {
|
||||
for (const uint16_t *ptr = format; *ptr; ++ptr) {
|
||||
@@ -1832,10 +1859,10 @@ namespace msvcrt {
|
||||
return std::vfwprintf(host, fmt.c_str(), args);
|
||||
}
|
||||
|
||||
FILE *CDECL fopen(const char *filename, const char *mode) {
|
||||
_FILE *CDECL fopen(const char *filename, const char *mode) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fopen(%s, %s)\n", filename ? filename : "(null)", mode ? mode : "(null)");
|
||||
return std::fopen(filename, mode);
|
||||
return mapToGuestFile(std::fopen(filename, mode));
|
||||
}
|
||||
|
||||
int CDECL _dup2(int fd1, int fd2) {
|
||||
@@ -1850,25 +1877,28 @@ namespace msvcrt {
|
||||
return isatty(fd);
|
||||
}
|
||||
|
||||
int CDECL fseek(FILE *stream, long offset, int origin) {
|
||||
int CDECL fseek(_FILE *stream, long offset, int origin) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin);
|
||||
return std::fseek(stream, offset, origin);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
return std::fseek(host, offset, origin);
|
||||
}
|
||||
|
||||
long CDECL ftell(FILE *stream) {
|
||||
long CDECL ftell(_FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
VERBOSE_LOG("ftell(%p)\n", stream);
|
||||
return std::ftell(stream);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
return std::ftell(host);
|
||||
}
|
||||
|
||||
int CDECL feof(FILE *stream) {
|
||||
int CDECL feof(_FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
VERBOSE_LOG("feof(%p)\n", stream);
|
||||
return std::feof(stream);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
return std::feof(host);
|
||||
}
|
||||
|
||||
int CDECL fputws(const uint16_t *str, FILE *stream) {
|
||||
int CDECL fputws(const uint16_t *str, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fputws(%s, %p)\n", wideStringToString(str).c_str(), stream);
|
||||
std::wstring temp;
|
||||
@@ -1877,23 +1907,25 @@ namespace msvcrt {
|
||||
temp.push_back(static_cast<wchar_t>(*cursor));
|
||||
}
|
||||
}
|
||||
return std::fputws(temp.c_str(), stream);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
return std::fputws(temp.c_str(), host);
|
||||
}
|
||||
|
||||
int CDECL _cputws(const uint16_t *string) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("_cputws(%s)\n", wideStringToString(string).c_str());
|
||||
return fputws(string, stdout);
|
||||
return fputws(string, &_iob[0]);
|
||||
}
|
||||
|
||||
uint16_t* CDECL fgetws(uint16_t *buffer, int size, FILE *stream) {
|
||||
uint16_t* CDECL fgetws(uint16_t *buffer, int size, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fgetws(%p, %d, %p)\n", buffer, size, stream);
|
||||
if (!buffer || size <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<wchar_t> temp(static_cast<SIZE_T>(size));
|
||||
wchar_t *res = std::fgetws(temp.data(), size, stream);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
wchar_t *res = std::fgetws(temp.data(), size, host);
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1906,13 +1938,14 @@ namespace msvcrt {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
WINT_T CDECL fgetwc(FILE *stream) {
|
||||
WINT_T CDECL fgetwc(_FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
VERBOSE_LOG("fgetwc(%p)\n", stream);
|
||||
return std::fgetwc(stream);
|
||||
FILE* host = mapToHostFile(stream);
|
||||
return std::fgetwc(host);
|
||||
}
|
||||
|
||||
int CDECL _wfopen_s(FILE **stream, const uint16_t *filename, const uint16_t *mode) {
|
||||
int CDECL _wfopen_s(_FILE **stream, const uint16_t *filename, const uint16_t *mode) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(),
|
||||
wideStringToString(mode).c_str());
|
||||
@@ -1927,7 +1960,7 @@ namespace msvcrt {
|
||||
*stream = nullptr;
|
||||
return errno ? errno : EINVAL;
|
||||
}
|
||||
*stream = handle;
|
||||
*stream = mapToGuestFile(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2210,21 +2243,14 @@ namespace msvcrt {
|
||||
std::fflush(nullptr);
|
||||
}
|
||||
|
||||
static FILE *resolveFileStream(FILE *stream) {
|
||||
if (!stream) {
|
||||
return nullptr;
|
||||
}
|
||||
return mapToHostFile(stream);
|
||||
}
|
||||
|
||||
int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args) {
|
||||
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("vfprintf(stream=%p, format=%s, args=%p)\n", stream, format, args);
|
||||
if (!format || !stream) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
FILE *native = resolveFileStream(stream);
|
||||
FILE *native = mapToHostFile(stream);
|
||||
if (!native) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -2236,7 +2262,7 @@ namespace msvcrt {
|
||||
return result;
|
||||
}
|
||||
|
||||
int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...) {
|
||||
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fprintf(%p, %s, ...)\n", stream, format);
|
||||
va_list args;
|
||||
@@ -2246,14 +2272,14 @@ namespace msvcrt {
|
||||
return result;
|
||||
}
|
||||
|
||||
int CDECL fputc(int ch, FILE *stream) {
|
||||
int CDECL fputc(int ch, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fputc(%d, %p)\n", ch, stream);
|
||||
if (!stream) {
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
FILE *native = resolveFileStream(stream);
|
||||
FILE *native = mapToHostFile(stream);
|
||||
if (!native) {
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
@@ -2261,14 +2287,14 @@ namespace msvcrt {
|
||||
return std::fputc(ch, native);
|
||||
}
|
||||
|
||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream) {
|
||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream) {
|
||||
HOST_CONTEXT_GUARD();
|
||||
DEBUG_LOG("fwrite(%p, %zu, %zu, %p)\n", buffer, size, count, stream);
|
||||
if (!buffer || !stream) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
FILE *native = resolveFileStream(stream);
|
||||
FILE *native = mapToHostFile(stream);
|
||||
if (!native) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
@@ -2808,7 +2834,7 @@ namespace msvcrt {
|
||||
return wstrtoul(strSource, endptr, base);
|
||||
}
|
||||
|
||||
FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
|
||||
_FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
|
||||
HOST_CONTEXT_GUARD();
|
||||
if (!filename || !mode) return nullptr;
|
||||
std::string fname_str = wideStringToString(filename);
|
||||
@@ -2832,10 +2858,10 @@ namespace msvcrt {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CDECL fclose(FILE* stream){
|
||||
int CDECL fclose(_FILE* stream){
|
||||
HOST_CONTEXT_GUARD();
|
||||
VERBOSE_LOG("fclose(%p)\n", stream);
|
||||
return ::fclose(stream);
|
||||
return closeGuestFile(stream);
|
||||
}
|
||||
|
||||
int CDECL _flushall(){
|
||||
@@ -2843,9 +2869,15 @@ namespace msvcrt {
|
||||
DEBUG_LOG("_flushall()\n");
|
||||
int count = 0;
|
||||
|
||||
if (msvcrt::fflush(stdin) == 0) count++;
|
||||
if (msvcrt::fflush(stdout) == 0) count++;
|
||||
if (msvcrt::fflush(stderr) == 0) count++;
|
||||
if (::fflush(stdin) == 0) count++;
|
||||
if (::fflush(stdout) == 0) count++;
|
||||
if (::fflush(stderr) == 0) count++;
|
||||
|
||||
std::lock_guard lock(g_fileMutex);
|
||||
for (auto &file : g_files) {
|
||||
if (::fflush(file.second) == 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
79
dll/msvcrt.h
79
dll/msvcrt.h
@@ -7,7 +7,9 @@ using WINT_T = unsigned short;
|
||||
|
||||
typedef void(_CC_CDECL *_PVFV)();
|
||||
typedef int(_CC_CDECL *_PIFV)();
|
||||
using _onexit_t = _PIFV;
|
||||
typedef int(_CC_CDECL *_onexit_t)();
|
||||
typedef void(_CC_CDECL *signal_handler)(int);
|
||||
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
||||
|
||||
struct _utimbuf {
|
||||
long actime;
|
||||
@@ -21,31 +23,26 @@ struct _timeb {
|
||||
short dstflag;
|
||||
};
|
||||
|
||||
typedef void(_CC_CDECL *signal_handler)(int);
|
||||
using FILE = struct _IO_FILE;
|
||||
|
||||
struct IOBProxy {
|
||||
char *_ptr;
|
||||
int _cnt;
|
||||
char *_base;
|
||||
int _flag;
|
||||
int _file;
|
||||
int _charbuf;
|
||||
int _bufsiz;
|
||||
char *_tmpfname;
|
||||
};
|
||||
|
||||
struct lconv;
|
||||
|
||||
namespace msvcrt {
|
||||
|
||||
IOBProxy *CDECL __iob_func();
|
||||
IOBProxy *CDECL __p__iob();
|
||||
void CDECL setbuf(FILE *stream, char *buffer);
|
||||
extern int _commode;
|
||||
extern int _fmode;
|
||||
extern char **__initenv;
|
||||
extern WCHAR **__winitenv;
|
||||
extern WCHAR *_wpgmptr;
|
||||
extern char *_pgmptr;
|
||||
extern int __mb_cur_max;
|
||||
extern _FILE _iob[_IOB_ENTRIES];
|
||||
|
||||
_FILE *CDECL __iob_func();
|
||||
_FILE *CDECL __p__iob();
|
||||
void CDECL setbuf(_FILE *stream, char *buffer);
|
||||
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
|
||||
int CDECL _fileno(FILE *stream);
|
||||
int CDECL _fileno(_FILE *stream);
|
||||
int CDECL _getmbcp();
|
||||
unsigned int *CDECL __p___mb_cur_max();
|
||||
int *CDECL __p___mb_cur_max();
|
||||
int CDECL _setmbcp(int codepage);
|
||||
unsigned char *CDECL __p__mbctype();
|
||||
unsigned short **CDECL __p__pctype();
|
||||
@@ -57,7 +54,7 @@ void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
|
||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
|
||||
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
|
||||
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
|
||||
_PIFV CDECL _onexit(_PIFV func);
|
||||
_onexit_t CDECL _onexit(_onexit_t func);
|
||||
int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo);
|
||||
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo);
|
||||
char *CDECL getenv(const char *varname);
|
||||
@@ -92,9 +89,9 @@ int CDECL_NO_CONV _snprintf(char *buffer, SIZE_T count, const char *format, ...)
|
||||
int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...);
|
||||
int CDECL_NO_CONV printf(const char *format, ...);
|
||||
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
|
||||
char *CDECL fgets(char *str, int count, FILE *stream);
|
||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, FILE *stream);
|
||||
FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag);
|
||||
char *CDECL fgets(char *str, int count, _FILE *stream);
|
||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
||||
_FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag);
|
||||
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode);
|
||||
int CDECL _read(int fd, void *buffer, unsigned int count);
|
||||
int CDECL _close(int fd);
|
||||
@@ -144,20 +141,20 @@ void CDECL free(void *ptr);
|
||||
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
|
||||
void *CDECL memmove(void *dest, const void *src, SIZE_T count);
|
||||
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
|
||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, int (*compar)(const void *, const void *));
|
||||
int CDECL fflush(FILE *stream);
|
||||
int CDECL_NO_CONV vfwprintf(FILE *stream, const WCHAR *format, va_list args);
|
||||
FILE *CDECL fopen(const char *filename, const char *mode);
|
||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
||||
int CDECL fflush(_FILE *stream);
|
||||
int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
|
||||
_FILE *CDECL fopen(const char *filename, const char *mode);
|
||||
int CDECL _dup2(int fd1, int fd2);
|
||||
int CDECL _isatty(int fd);
|
||||
int CDECL fseek(FILE *stream, long offset, int origin);
|
||||
long CDECL ftell(FILE *stream);
|
||||
int CDECL feof(FILE *stream);
|
||||
int CDECL fputws(const WCHAR *str, FILE *stream);
|
||||
int CDECL fseek(_FILE *stream, long offset, int origin);
|
||||
long CDECL ftell(_FILE *stream);
|
||||
int CDECL feof(_FILE *stream);
|
||||
int CDECL fputws(const WCHAR *str, _FILE *stream);
|
||||
int CDECL _cputws(const WCHAR *string);
|
||||
WCHAR *CDECL fgetws(WCHAR *buffer, int size, FILE *stream);
|
||||
WINT_T CDECL fgetwc(FILE *stream);
|
||||
int CDECL _wfopen_s(FILE **stream, const WCHAR *filename, const WCHAR *mode);
|
||||
WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
|
||||
WINT_T CDECL fgetwc(_FILE *stream);
|
||||
int CDECL _wfopen_s(_FILE **stream, const WCHAR *filename, const WCHAR *mode);
|
||||
int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs);
|
||||
int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname,
|
||||
const WCHAR *ext);
|
||||
@@ -175,10 +172,10 @@ int CDECL _crt_debugger_hook(int value);
|
||||
int CDECL _configthreadlocale(int mode);
|
||||
void CDECL __setusermatherr(void *handler);
|
||||
void CDECL _cexit();
|
||||
int CDECL_NO_CONV vfprintf(FILE *stream, const char *format, va_list args);
|
||||
int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...);
|
||||
int CDECL fputc(int ch, FILE *stream);
|
||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, FILE *stream);
|
||||
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
|
||||
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
|
||||
int CDECL fputc(int ch, _FILE *stream);
|
||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
||||
char *CDECL strerror(int errnum);
|
||||
char *CDECL strchr(const char *str, int character);
|
||||
struct lconv *CDECL localeconv();
|
||||
@@ -220,9 +217,9 @@ int CDECL iswdigit(WINT_T w);
|
||||
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
|
||||
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
|
||||
unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base);
|
||||
FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
|
||||
_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
|
||||
int CDECL puts(const char *str);
|
||||
int CDECL fclose(FILE *stream);
|
||||
int CDECL fclose(_FILE *stream);
|
||||
int CDECL _flushall();
|
||||
int *CDECL _errno();
|
||||
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv);
|
||||
|
||||
16
src/types.h
16
src/types.h
@@ -444,3 +444,19 @@ typedef struct _MEMORY_BASIC_INFORMATION {
|
||||
DWORD Protect;
|
||||
DWORD Type;
|
||||
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
|
||||
|
||||
#define _IOB_ENTRIES 20
|
||||
|
||||
typedef struct _iobuf {
|
||||
_iobuf() : _file(-1) {}
|
||||
explicit _iobuf(int file) : _file(file) {}
|
||||
|
||||
char *_ptr = nullptr;
|
||||
int _cnt = 0;
|
||||
char *_base = nullptr;
|
||||
int _flag = 0;
|
||||
int _file;
|
||||
int _charbuf = 0;
|
||||
int _bufsiz = 0;
|
||||
char *_tmpfname = nullptr;
|
||||
} _FILE;
|
||||
|
||||
@@ -29,14 +29,13 @@ from clang.cindex import (
|
||||
Cursor,
|
||||
CursorKind,
|
||||
Index,
|
||||
StorageClass,
|
||||
TranslationUnit,
|
||||
Type,
|
||||
TypeKind,
|
||||
conf,
|
||||
)
|
||||
from clang.cindex import (
|
||||
Type as CXType,
|
||||
)
|
||||
from clang.cindex import Type as CXType
|
||||
|
||||
# Allow libclang path to be specified via environment variable
|
||||
if "LIBCLANG_PATH" in os.environ:
|
||||
@@ -123,6 +122,12 @@ class TypedefInfo:
|
||||
args: List[ArgInfo] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class VarInfo:
|
||||
qualified_ns: str
|
||||
name: str
|
||||
|
||||
|
||||
def parse_tu(
|
||||
headers: List[str], include_dirs: List[str], target: str
|
||||
) -> TranslationUnit:
|
||||
@@ -338,6 +343,35 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
|
||||
return sorted(out.values(), key=lambda t: t.name)
|
||||
|
||||
|
||||
def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[VarInfo]:
|
||||
"""Collect extern variable declarations from the translation unit."""
|
||||
want_ns = ns_filter.split("::") if ns_filter else None
|
||||
out: dict[str, VarInfo] = {}
|
||||
|
||||
def visit(node: Cursor) -> None:
|
||||
if node.kind == CursorKind.VAR_DECL:
|
||||
if node.storage_class != StorageClass.EXTERN or node.is_definition():
|
||||
return
|
||||
ns_parts = _cursor_namespace(node)
|
||||
if want_ns is not None and ns_parts != want_ns:
|
||||
return
|
||||
name = node.spelling
|
||||
if not name:
|
||||
return
|
||||
out[name] = VarInfo(
|
||||
qualified_ns="::".join(ns_parts),
|
||||
name=name,
|
||||
)
|
||||
|
||||
if node.kind in (CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE):
|
||||
for c in node.get_children():
|
||||
visit(c)
|
||||
|
||||
if tu.cursor is not None:
|
||||
visit(tu.cursor)
|
||||
return sorted(out.values(), key=lambda v: v.name)
|
||||
|
||||
|
||||
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
||||
if isinstance(f, TypedefInfo):
|
||||
# Host-to-guest
|
||||
@@ -543,7 +577,10 @@ def emit_host_to_guest_thunks(
|
||||
|
||||
|
||||
def emit_header_mapping(
|
||||
dll: str, funcs: Iterable[FuncInfo], typedefs: Iterable[TypedefInfo]
|
||||
dll: str,
|
||||
funcs: Iterable[FuncInfo],
|
||||
typedefs: Iterable[TypedefInfo],
|
||||
variables: Iterable[VarInfo],
|
||||
) -> str:
|
||||
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
|
||||
lines: List[str] = []
|
||||
@@ -616,6 +653,11 @@ def emit_header_mapping(
|
||||
lines.append(
|
||||
f'\tif (strcmp(name, "{f.name}") == 0) return (void*)&thunk_{dll}_{f.name};'
|
||||
)
|
||||
for v in variables:
|
||||
qualified = f"{v.qualified_ns}::{v.name}" if v.qualified_ns else v.name
|
||||
lines.append(
|
||||
f'\tif (strcmp(name, "{v.name}") == 0) return (void*)&{qualified};'
|
||||
)
|
||||
lines.append("\treturn NULL;")
|
||||
lines.append("}")
|
||||
|
||||
@@ -644,9 +686,10 @@ def main() -> int:
|
||||
tu = parse_tu(args.headers, args.incs, target)
|
||||
funcs = collect_functions(tu, args.ns)
|
||||
typedefs = collect_typedefs(tu)
|
||||
variables = collect_variables(tu, args.ns)
|
||||
|
||||
if not funcs and not typedefs:
|
||||
sys.stderr.write("No functions or typedefs found for generation.\n")
|
||||
if not funcs and not typedefs and not variables:
|
||||
sys.stderr.write("No functions, typedefs, or variables found for generation.\n")
|
||||
return 1
|
||||
|
||||
lines: List[str] = []
|
||||
@@ -659,7 +702,7 @@ def main() -> int:
|
||||
emit_host_to_guest_thunks(lines, typedefs)
|
||||
|
||||
asm = "\n".join(lines) + "\n"
|
||||
hdr = emit_header_mapping(args.dll, funcs, typedefs)
|
||||
hdr = emit_header_mapping(args.dll, funcs, typedefs, variables)
|
||||
|
||||
args.out_asm.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.out_hdr.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user