/** * Platform compatibility layer for POSIX functions on Windows */ #ifndef PLATFORM_COMPAT_H #define PLATFORM_COMPAT_H #ifdef _WIN32 #include #include #include #include #include // POSIX functions missing on Windows #define strcasecmp _stricmp #define strncasecmp _strnicmp // poll() implementation for Windows #ifndef POLLIN #define POLLIN 0x0001 #endif #ifndef POLLOUT #define POLLOUT 0x0004 #endif #ifndef POLLERR #define POLLERR 0x0008 #endif #ifndef POLLHUP #define POLLHUP 0x0010 #endif #ifndef POLLNVAL #define POLLNVAL 0x0020 #endif #ifndef POLLPRI #define POLLPRI 0x0002 #endif struct pollfd { int fd; short events; short revents; }; // gettimeofday for Windows struct timezone { int tz_minuteswest; int tz_dsttime; }; static inline int gettimeofday(struct timeval *tv, struct timezone *tz) { (void)tz; if (tv) { FILETIME ft; ULARGE_INTEGER ull; GetSystemTimeAsFileTime(&ft); ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; // Convert from 100-nanosecond intervals since 1601 to Unix epoch tv->tv_sec = (long)(ull.QuadPart / 10000000ULL - 11644473600ULL); tv->tv_usec = (long)((ull.QuadPart % 10000000ULL) / 10); } return 0; } // Pipe creation for Windows static inline int pipe(int pipefd[2]) { return _pipe(pipefd, 4096, _O_BINARY); } // poll() using select() for Windows static inline int poll(struct pollfd *fds, nfds_t nfds, int timeout) { fd_set readfds, writefds, exceptfds; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); int max_fd = -1; for (nfds_t i = 0; i < nfds; i++) { if (fds[i].fd < 0) continue; if (fds[i].events & POLLIN) FD_SET(fds[i].fd, &readfds); if (fds[i].events & POLLOUT) FD_SET(fds[i].fd, &writefds); FD_SET(fds[i].fd, &exceptfds); if (fds[i].fd > max_fd) max_fd = fds[i].fd; } struct timeval tv, *ptv = NULL; if (timeout >= 0) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; ptv = &tv; } int ret = select(max_fd + 1, &readfds, &writefds, &exceptfds, ptv); if (ret < 0) return ret; // Set revents for (nfds_t i = 0; i < nfds; i++) { fds[i].revents = 0; if (fds[i].fd < 0) continue; if (FD_ISSET(fds[i].fd, &readfds)) fds[i].revents |= POLLIN; if (FD_ISSET(fds[i].fd, &writefds)) fds[i].revents |= POLLOUT; if (FD_ISSET(fds[i].fd, &exceptfds)) fds[i].revents |= POLLERR; } return ret; } // fcntl replacement for Windows (simplified - only supports F_GETFL/F_SETFL with O_NONBLOCK) #define F_GETFL 3 #define F_SETFL 4 #define O_NONBLOCK 0x4000 static inline int fcntl(int fd, int cmd, ... /* arg */ ) { va_list ap; va_start(ap, cmd); if (cmd == F_GETFL) { va_end(ap); // Return current flags (always 0 on Windows, can't query easily) return 0; } else if (cmd == F_SETFL) { int flags = va_arg(ap, int); va_end(ap); if (flags & O_NONBLOCK) { // Set non-blocking mode u_long mode = 1; return ioctlsocket(fd, FIONBIO, &mode); } return 0; } va_end(ap); errno = EINVAL; return -1; } // nanosleep replacement static inline int nanosleep(const struct timespec *req, struct timespec *rem) { (void)rem; Sleep((DWORD)(req->tv_sec * 1000 + req->tv_nsec / 1000000)); return 0; } #else // POSIX - include standard headers #include #include #include #include #include #include #include #endif #endif // PLATFORM_COMPAT_H