#ifndef EL_PLATFORM_WIN_H #define EL_PLATFORM_WIN_H /* * el_platform_win.h — Windows OS-boundary shim for el_runtime.c. * * Branch: feat/windows-el-runtime. Included ONLY when _WIN32 is defined; the POSIX build is * untouched. Goal: let el_runtime.c (a BSD-sockets / dlfcn / fork host) compile and link with * mingw-w64 into a native neuron.exe, with no behavioural change to the Linux/macOS build. * * What it maps: * - sockets : winsock2 (same call names: socket/bind/listen/accept/recv/send/setsockopt). * Sockets close with closesocket() (see el_closesocket), and the stack must be * started once with WSAStartup — done automatically via a load-time constructor. * - dlsym : el_runtime.c uses dlsym(RTLD_DEFAULT, name) to resolve callback/tool symbols * exported by the main module. Windows equivalent: GetProcAddress on the process * module. Link the soul with -Wl,--export-all-symbols so the symbols are findable. * - popen : mapped to _popen/_pclose. * - threads : UNCHANGED. mingw-w64 ships winpthreads, so + -lpthread just work. */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include /* Portable headers mingw-w64 provides (verified present). */ #include #include #include #include #include #include /* strcasecmp */ #include #include #include #include /* mingw-w64 provides gettimeofday here */ #include #include #include #include #include #include /* ── socket close ─────────────────────────────────────────────────────────── */ /* Winsock closes sockets with closesocket(), not close() (close() is for file fds). The POSIX build defines the same helper as close() so the call sites are identical across platforms. */ static inline int el_closesocket(SOCKET s) { return closesocket(s); } /* ── winsock init (once, at load) ─────────────────────────────────────────── */ static void el__win_net_init(void) { static int inited = 0; if (!inited) { WSADATA w; WSAStartup(MAKEWORD(2, 2), &w); inited = 1; } } __attribute__((constructor)) static void el__win_ctor(void) { el__win_net_init(); } /* ── dlsym → GetProcAddress ───────────────────────────────────────────────── */ #ifndef RTLD_DEFAULT #define RTLD_DEFAULT ((void*)0) #endif static inline void* el_win_dlsym(void* handle, const char* name) { (void)handle; return (void*)(uintptr_t)GetProcAddress(GetModuleHandleA(NULL), name); } #define dlsym(h, n) el_win_dlsym((h), (n)) /* ── popen / pclose ───────────────────────────────────────────────────────── */ #define popen _popen #define pclose _pclose /* ── misc POSIX → Win32 shims ─────────────────────────────────────────────── */ #include /* _mkdir */ #define mkdir(path, mode) _mkdir(path) /* POSIX mkdir(path,mode) → _mkdir(path) */ #define timegm _mkgmtime /* UTC tm → time_t */ #define fsync(fd) _commit(fd) /* no fsync() on Windows; _commit() () is the equiv */ /* setenv/unsetenv: not in the Windows CRT; map to _putenv_s / SetEnvironmentVariable. */ static inline int setenv(const char* name, const char* value, int overwrite) { (void)overwrite; return _putenv_s(name, value ? value : ""); } static inline int unsetenv(const char* name) { /* _putenv_s(name, "") sets VAR="" rather than removing it. * SetEnvironmentVariableA(name, NULL) truly deletes it from the Win32 * env block; then we sync the CRT cache with _putenv("NAME="). */ SetEnvironmentVariableA(name, NULL); size_t len = strlen(name); char *buf = (char*)malloc(len + 2); if (!buf) return -1; memcpy(buf, name, len); buf[len] = '='; buf[len + 1] = '\0'; _putenv(buf); free(buf); return 0; } /* nanosleep — not available in MSVC/UCRT; approximate with Sleep(). */ static inline int el_nanosleep(const struct timespec *req, struct timespec *rem) { (void)rem; DWORD ms = (DWORD)((req->tv_sec * 1000ULL) + (req->tv_nsec / 1000000ULL)); Sleep(ms ? ms : 1); return 0; } #define nanosleep(req, rem) el_nanosleep((req), (rem)) /* localtime_r/gmtime_r: Windows offers localtime_s/gmtime_s with reversed arg order. */ static inline struct tm* localtime_r(const time_t* t, struct tm* out) { return localtime_s(out, t) == 0 ? out : (struct tm*)0; } static inline struct tm* gmtime_r(const time_t* t, struct tm* out) { return gmtime_s(out, t) == 0 ? out : (struct tm*)0; } #endif /* EL_PLATFORM_WIN_H */