feat(platform): 新增跨平台抽象层 platform.h + platform.c

- platform.h: 定义跨平台类型 cocoon_socket_t / cocoon_file_t / cocoon_dir_iter_t
- POSIX 路径: fcntl O_NONBLOCK, sendfile 零拷贝, opendir/readdir, sysconf
- Windows 路径: ioctlsocket(FIONBIO), WSAStartup/WSACleanup, FindFirstFile
- 错误码统一: WSAEWOULDBLOCK→EAGAIN, WSAEINTR→EINTR, WSAECONNRESET→ECONNRESET
- 全部中文注释,Doxygen 风格
This commit is contained in:
xfy 2026-06-05 00:50:18 +08:00
parent 9041d8dfc4
commit c9693612bd
2 changed files with 970 additions and 0 deletions

562
platform.c Normal file
View File

@ -0,0 +1,562 @@
/**
* platform.c -
*
*
* - sendfile 使 64KB I/O
* - Windows FindFirstFile
* -
* - socket cocoon_socket_close Windows close()
*
* @author xfy
*/
#include "platform.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ========== POSIX 实现 ========== */
#ifdef COCOON_PLATFORM_POSIX
/**
* POSIX socket
*/
int cocoon_socket_init(void) { return 0; }
/**
* POSIX socket
*/
void cocoon_socket_cleanup(void) { }
/**
* POSIX 使 fcntl O_NONBLOCK
*/
int cocoon_socket_nonblock(cocoon_socket_t fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return -1;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
/**
* POSIX socket close()
*/
int cocoon_socket_close(cocoon_socket_t fd) {
return close(fd);
}
/**
* POSIX 使 shutdown(SHUT_RDWR)
*/
int cocoon_socket_shutdown(cocoon_socket_t fd) {
return shutdown(fd, SHUT_RDWR);
}
/**
* POSIX socket write()
*
*/
ssize_t cocoon_socket_send(cocoon_socket_t fd, const char *buf, size_t len) {
return write(fd, buf, len);
}
ssize_t cocoon_socket_recv(cocoon_socket_t fd, void *buf, size_t len) {
return read(fd, buf, len);
}
/**
* POSIX API
*/
cocoon_file_t cocoon_file_open(const char *path) {
return open(path, O_RDONLY);
}
ssize_t cocoon_file_read(cocoon_file_t fd, void *buf, size_t count) {
return read(fd, buf, count);
}
int64_t cocoon_file_seek(cocoon_file_t fd, int64_t offset, int whence) {
return lseek(fd, (off_t)offset, whence);
}
int cocoon_file_close(cocoon_file_t fd) {
return close(fd);
}
int cocoon_file_stat(const char *path, cocoon_stat_t *st) {
return stat(path, st);
}
int cocoon_file_fstat(cocoon_file_t fd, cocoon_stat_t *st) {
return fstat(fd, st);
}
bool cocoon_stat_isreg(const cocoon_stat_t *st) {
return S_ISREG(st->st_mode);
}
bool cocoon_stat_isdir(const cocoon_stat_t *st) {
return S_ISDIR(st->st_mode);
}
int64_t cocoon_stat_size(const cocoon_stat_t *st) {
return (int64_t)st->st_size;
}
time_t cocoon_stat_mtime(const cocoon_stat_t *st) {
return st->st_mtime;
}
/**
* Linux 使 sendfile
* 退 read+write 64KB
*/
ssize_t cocoon_file_send(cocoon_socket_t sock, cocoon_file_t file,
int64_t offset, size_t count) {
off_t off = (off_t)offset;
ssize_t sent = sendfile(sock, file, &off, count);
if (sent >= 0 || (errno != EINVAL && errno != ENOSYS)) {
return sent;
}
/* sendfile 不支持此场景,回退到 read+write */
if (lseek(file, (off_t)offset, SEEK_SET) < 0) {
return -1;
}
char buf[65536]; /* 64KB 缓冲区,最大化单次 I/O */
size_t total = 0;
while (total < count) {
size_t to_read = count - total;
if (to_read > sizeof(buf)) to_read = sizeof(buf);
ssize_t n = read(file, buf, to_read);
if (n <= 0) {
if (n < 0 && errno == EINTR) continue;
return (total > 0) ? (ssize_t)total : -1;
}
size_t buf_sent = 0;
while (buf_sent < (size_t)n) {
ssize_t w = write(sock, buf + buf_sent, (size_t)n - buf_sent);
if (w < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue;
return (total > 0) ? (ssize_t)total : -1;
}
if (w == 0) return (total > 0) ? (ssize_t)total : -1;
buf_sent += (size_t)w;
}
total += (size_t)n;
}
return (ssize_t)total;
}
/**
* POSIX opendir/readdir/closedir
*/
int cocoon_dir_open(cocoon_dir_iter_t *iter, const char *path) {
if (!iter || !path) return -1;
iter->dir = opendir(path);
return (iter->dir != NULL) ? 0 : -1;
}
int cocoon_dir_next(cocoon_dir_iter_t *iter) {
if (!iter || !iter->dir) return -1;
struct dirent *entry = readdir(iter->dir);
if (!entry) return 1; /* 遍历结束 */
strncpy(iter->name, entry->d_name, sizeof(iter->name) - 1);
iter->name[sizeof(iter->name) - 1] = '\0';
/* 用 d_type 快速判断(如果支持),否则 stat */
#ifdef _DIRENT_HAVE_D_TYPE
iter->is_dir = (entry->d_type == DT_DIR);
#else
char full_path[4096];
/* 注意:这里 path 未存储在 iter 中,调用方需自行判断 */
iter->is_dir = false; /* 保守默认值static.c 会 stat 验证 */
#endif
return 0;
}
void cocoon_dir_close(cocoon_dir_iter_t *iter) {
if (iter && iter->dir) {
closedir(iter->dir);
iter->dir = NULL;
}
}
/**
* POSIX SIGINT + SIGTERM
*/
static void (*g_signal_handler)(int) = NULL;
static void posix_signal_handler(int sig) {
if (g_signal_handler) g_signal_handler(sig);
}
void cocoon_signal_setup(void (*handler)(int)) {
g_signal_handler = handler;
signal(SIGINT, posix_signal_handler);
signal(SIGTERM, posix_signal_handler);
}
/**
* POSIX CPU
*/
uint32_t cocoon_cpu_count(void) {
long n = sysconf(_SC_NPROCESSORS_ONLN);
return (n > 0) ? (uint32_t)n : 4;
}
/**
* POSIX realpath
*/
bool cocoon_realpath(const char *path, char *resolved, size_t resolved_size) {
if (!path || !resolved || resolved_size == 0) return false;
char *r = realpath(path, NULL);
if (r) {
strncpy(resolved, r, resolved_size - 1);
resolved[resolved_size - 1] = '\0';
free(r);
return true;
}
return false;
}
/**
* POSIX
*/
int cocoon_mkdir(const char *path) {
return mkdir(path, 0755);
}
/**
* POSIX errno
*/
int cocoon_get_last_error(void) {
return errno;
}
const char *cocoon_strerror(int err) {
return strerror(err);
}
#endif /* COCOON_PLATFORM_POSIX */
/* ========== Windows 实现 ========== */
#ifdef COCOON_PLATFORM_WINDOWS
#include <fcntl.h> /* _O_RDONLY, _O_BINARY */
/**
* Windows Winsock
* 使线线 accept
*/
static int g_wsa_ref = 0;
int cocoon_socket_init(void) {
if (g_wsa_ref == 0) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return -1;
}
}
g_wsa_ref++;
return 0;
}
void cocoon_socket_cleanup(void) {
if (g_wsa_ref > 0) {
g_wsa_ref--;
if (g_wsa_ref == 0) {
WSACleanup();
}
}
}
/**
* Windows ioctlsocket(FIONBIO)
*/
int cocoon_socket_nonblock(cocoon_socket_t fd) {
u_long mode = 1; /* 1 = 非阻塞 */
return ioctlsocket(fd, FIONBIO, &mode);
}
/**
* Windows socket closesocket() close()
*/
int cocoon_socket_close(cocoon_socket_t fd) {
return closesocket(fd);
}
/**
* Windows shutdown POSIX
*/
int cocoon_socket_shutdown(cocoon_socket_t fd) {
return shutdown(fd, SD_BOTH);
}
/**
* Windows socket send() write()
*/
ssize_t cocoon_socket_send(cocoon_socket_t fd, const char *buf, size_t len) {
/* send() 的 len 参数是 int大于 INT_MAX 时分批发送 */
int chunk = (len > INT_MAX) ? INT_MAX : (int)len;
int r = send(fd, buf, chunk, 0);
if (r == SOCKET_ERROR) {
WSASetLastError(WSAGetLastError()); /* 保持错误码 */
return -1;
}
return (ssize_t)r;
}
ssize_t cocoon_socket_recv(cocoon_socket_t fd, void *buf, size_t len) {
int chunk = (len > INT_MAX) ? INT_MAX : (int)len;
int r = recv(fd, (char *)buf, chunk, 0);
if (r == SOCKET_ERROR) {
WSASetLastError(WSAGetLastError());
return -1;
}
return (ssize_t)r;
}
/**
* Windows _open/_read/_lseek/_close
*/
cocoon_file_t cocoon_file_open(const char *path) {
return _open(path, _O_RDONLY | _O_BINARY);
}
ssize_t cocoon_file_read(cocoon_file_t fd, void *buf, size_t count) {
int chunk = (count > INT_MAX) ? INT_MAX : (int)count;
int r = _read(fd, buf, chunk);
return (r < 0) ? -1 : (ssize_t)r;
}
int64_t cocoon_file_seek(cocoon_file_t fd, int64_t offset, int whence) {
return _lseeki64(fd, offset, whence);
}
int cocoon_file_close(cocoon_file_t fd) {
return _close(fd);
}
/**
* Windows _stat64 2GB
*/
int cocoon_file_stat(const char *path, cocoon_stat_t *st) {
return _stat64(path, st);
}
int cocoon_file_fstat(cocoon_file_t fd, cocoon_stat_t *st) {
return _fstat64(fd, st);
}
bool cocoon_stat_isreg(const cocoon_stat_t *st) {
return S_ISREG(st->st_mode);
}
bool cocoon_stat_isdir(const cocoon_stat_t *st) {
return S_ISDIR(st->st_mode);
}
int64_t cocoon_stat_size(const cocoon_stat_t *st) {
return (int64_t)st->st_size;
}
time_t cocoon_stat_mtime(const cocoon_stat_t *st) {
return st->st_mtime;
}
/**
* Windows sendfile使 read+send
* 64KB I/O /
*/
ssize_t cocoon_file_send(cocoon_socket_t sock, cocoon_file_t file,
int64_t offset, size_t count) {
if (_lseeki64(file, offset, SEEK_SET) < 0) {
return -1;
}
char buf[65536]; /* 64KB现代页表和磁盘 I/O 的最佳平衡点 */
size_t total = 0;
while (total < count) {
size_t to_read = count - total;
if (to_read > sizeof(buf)) to_read = sizeof(buf);
int chunk = (to_read > INT_MAX) ? INT_MAX : (int)to_read;
int n = _read(file, buf, chunk);
if (n <= 0) {
if (n < 0 && errno == EINTR) continue;
return (total > 0) ? (ssize_t)total : -1;
}
size_t buf_sent = 0;
while (buf_sent < (size_t)n) {
int to_send = (int)((size_t)n - buf_sent);
int w = send(sock, buf + buf_sent, to_send, 0);
if (w == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || err == WSAEINTR) continue;
errno = EIO; /* 映射为通用 I/O 错误 */
return (total > 0) ? (ssize_t)total : -1;
}
if (w == 0) return (total > 0) ? (ssize_t)total : -1;
buf_sent += (size_t)w;
}
total += (size_t)n;
}
return (ssize_t)total;
}
/**
* Windows FindFirstFile/FindNextFile
*
*/
int cocoon_dir_open(cocoon_dir_iter_t *iter, const char *path) {
if (!iter || !path) return -1;
/* 构建搜索路径path + \\* */
size_t len = strlen(path);
if (len >= sizeof(iter->path_buf) - 3) return -1;
memcpy(iter->path_buf, path, len);
iter->path_buf[len] = '\\';
iter->path_buf[len + 1] = '*';
iter->path_buf[len + 2] = '\0';
iter->handle = FindFirstFileA(iter->path_buf, &iter->data);
if (iter->handle == INVALID_HANDLE_VALUE) return -1;
iter->first = true;
return 0;
}
int cocoon_dir_next(cocoon_dir_iter_t *iter) {
if (!iter || iter->handle == INVALID_HANDLE_VALUE) return -1;
if (!iter->first) {
if (!FindNextFileA(iter->handle, &iter->data)) {
if (GetLastError() == ERROR_NO_MORE_FILES) return 1;
return -1;
}
}
iter->first = false;
/* 跳过 . 和 .. */
while (iter->data.cFileName[0] == '.') {
if (iter->data.cFileName[1] == '\0') goto skip;
if (iter->data.cFileName[1] == '.' && iter->data.cFileName[2] == '\0') goto skip;
break;
skip:
if (!FindNextFileA(iter->handle, &iter->data)) {
if (GetLastError() == ERROR_NO_MORE_FILES) return 1;
return -1;
}
}
strncpy(iter->name, iter->data.cFileName, sizeof(iter->name) - 1);
iter->name[sizeof(iter->name) - 1] = '\0';
iter->is_dir = (iter->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
return 0;
}
void cocoon_dir_close(cocoon_dir_iter_t *iter) {
if (iter && iter->handle != INVALID_HANDLE_VALUE) {
FindClose(iter->handle);
iter->handle = INVALID_HANDLE_VALUE;
}
}
/**
* Windows POSIX
*/
static void (*g_win_handler)(int) = NULL;
static BOOL WINAPI win_ctrl_handler(DWORD ctrl_type) {
(void)ctrl_type;
if (g_win_handler) g_win_handler(2); /* SIGINT = 2 */
return TRUE;
}
void cocoon_signal_setup(void (*handler)(int)) {
g_win_handler = handler;
SetConsoleCtrlHandler(win_ctrl_handler, TRUE);
}
/**
* Windows GetSystemInfo CPU
*/
uint32_t cocoon_cpu_count(void) {
SYSTEM_INFO si;
GetSystemInfo(&si);
return (si.dwNumberOfProcessors > 0) ? si.dwNumberOfProcessors : 1;
}
/**
* Windows _fullpath
*/
bool cocoon_realpath(const char *path, char *resolved, size_t resolved_size) {
if (!path || !resolved || resolved_size == 0) return false;
char *r = _fullpath(NULL, path, 0);
if (r) {
strncpy(resolved, r, resolved_size - 1);
resolved[resolved_size - 1] = '\0';
free(r);
return true;
}
return false;
}
/**
* Windows
*/
int cocoon_mkdir(const char *path) {
return _mkdir(path);
}
/**
* Windows
* WSAEWOULDBLOCK EAGAIN
* WSAECONNRESET ECONNRESET
*
*/
int cocoon_get_last_error(void) {
int err = WSAGetLastError();
switch (err) {
case WSAEWOULDBLOCK: return EAGAIN;
case WSAEINTR: return EINTR;
case WSAECONNRESET: return ECONNRESET;
case WSAECONNABORTED: return ECONNABORTED;
default: return err;
}
}
/**
* Windows FormatMessage
* 线
*/
static __thread char g_err_buf[256];
const char *cocoon_strerror(int err) {
if (err == 0) return "成功";
DWORD fm = FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, (DWORD)err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
g_err_buf, sizeof(g_err_buf), NULL);
if (fm == 0) {
snprintf(g_err_buf, sizeof(g_err_buf), "未知错误码 %d", err);
}
/* 去除尾部换行符 */
size_t len = strlen(g_err_buf);
while (len > 0 && (g_err_buf[len - 1] == '\n' || g_err_buf[len - 1] == '\r')) {
g_err_buf[--len] = '\0';
}
return g_err_buf;
}
#endif /* COCOON_PLATFORM_WINDOWS */

408
platform.h Normal file
View File

@ -0,0 +1,408 @@
/**
* platform.h -
*
* POSIX Windows API
* API 使 Doxygen
*
*
* 1.
* 2. Windows 使 API
* 3. sendfile Windows TransmitFile read+send
* 4. POSIX errno Windows WSAGetLastError()
*
* @author xfy
*/
#ifndef COCOON_PLATFORM_H
#define COCOON_PLATFORM_H
/* ========== 平台检测与系统头文件 ========== */
#ifdef _WIN32
#define COCOON_PLATFORM_WINDOWS
/* 精简 Windows 头文件,减少编译时间 */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h> /**< Winsock 2必须在 windows.h 之前) */
#include <ws2tcpip.h> /**< IPv6 扩展 */
#include <windows.h> /**< Windows 核心 API */
#include <io.h> /**< _open/_read/_close 等 */
#include <direct.h> /**< _mkdir */
#include <sys/types.h>
#include <sys/stat.h>
/* Windows 下缺失的 POSIX 宏定义 */
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISDIR
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
/* MinGW 已提供 dirent.hMSVC 需要自行实现 */
#ifdef __MINGW32__
#include <dirent.h>
#define COCOON_HAS_DIRENT
#endif
#else
#define COCOON_PLATFORM_POSIX
#include <sys/socket.h> /**< socket/bind/listen/accept */
#include <netinet/in.h> /**< sockaddr_in */
#include <netinet/tcp.h> /**< TCP_NODELAY */
#include <arpa/inet.h> /**< htons/ntohs */
#include <unistd.h> /**< close/read/write */
#include <fcntl.h> /**< fcntl/open */
#include <signal.h> /**< signal/sigaction */
#include <dirent.h> /**< opendir/readdir */
#include <sys/sendfile.h> /**< sendfileLinux 零拷贝) */
#define COCOON_HAS_DIRENT
#endif
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
/* ========== 跨平台类型定义 ========== */
#ifdef COCOON_PLATFORM_WINDOWS
/**
* cocoon_socket_t - socket
*
* Windows SOCKETUINT_PTRPOSIX int
*/
typedef SOCKET cocoon_socket_t;
#define COCOON_INVALID_SOCKET INVALID_SOCKET /**< 无效 socket 值 */
/**
* cocoon_file_t -
*
* Windows _open/_close int
*/
typedef int cocoon_file_t;
/**
* cocoon_socklen_t - socket
*/
typedef int cocoon_socklen_t;
#else
typedef int cocoon_socket_t;
#define COCOON_INVALID_SOCKET (-1)
typedef int cocoon_file_t;
typedef socklen_t cocoon_socklen_t;
#endif
/* ========== socket 生命周期 API ========== */
/**
* cocoon_socket_init - socket
*
* Windows WSAStartupPOSIX
*
* @return 0 -1
*/
int cocoon_socket_init(void);
/**
* cocoon_socket_cleanup - socket
*
* Windows WSACleanupPOSIX
*/
void cocoon_socket_cleanup(void);
/**
* cocoon_socket_nonblock - socket
*
* POSIX: fcntl(fd, F_SETFL, O_NONBLOCK)
* Windows: ioctlsocket(fd, FIONBIO, &mode)
*
* @param fd socket
* @return 0 -1
*/
int cocoon_socket_nonblock(cocoon_socket_t fd);
/**
* cocoon_socket_close - socket
*
* POSIX: close(fd)
* Windows: closesocket(fd)
*
* @param fd socket
* @return 0 -1
*/
int cocoon_socket_close(cocoon_socket_t fd);
/**
* cocoon_socket_shutdown - socket
*
* coco_read
*
* @param fd socket
* @return 0 -1
*/
int cocoon_socket_shutdown(cocoon_socket_t fd);
/**
* cocoon_socket_send - socket
*
* POSIX: write(fd, buf, len)
* Windows: send(fd, buf, len, 0)
*
* EAGAIN/EWOULDBLOCK/EINTR
*
* @param fd socket
* @param buf
* @param len
* @return -1 errno
*/
ssize_t cocoon_socket_send(cocoon_socket_t fd, const char *buf, size_t len);
/**
* cocoon_socket_recv - socket
*
* POSIX: read(fd, buf, len)
* Windows: recv(fd, buf, len, 0)
*
* @param fd socket
* @param buf
* @param len
* @return 0 -1
*/
ssize_t cocoon_socket_recv(cocoon_socket_t fd, void *buf, size_t len);
/* ========== 文件操作 API ========== */
/* 跨平台 stat 类型定义Windows 用 _stat6464位文件大小POSIX 用 struct stat */
#ifdef COCOON_PLATFORM_WINDOWS
typedef struct _stat64 cocoon_stat_t;
#else
typedef struct stat cocoon_stat_t;
#endif
/**
* cocoon_file_open -
*
* @param path
* @return -1
*/
cocoon_file_t cocoon_file_open(const char *path);
/**
* cocoon_file_read -
*
* @param fd
* @param buf
* @param count
* @return 0 EOF-1
*/
ssize_t cocoon_file_read(cocoon_file_t fd, void *buf, size_t count);
/**
* cocoon_file_seek -
*
* @param fd
* @param offset
* @param whence SEEK_SET/SEEK_CUR/SEEK_END
* @return -1
*/
int64_t cocoon_file_seek(cocoon_file_t fd, int64_t offset, int whence);
/**
* cocoon_file_close -
*
* @param fd
* @return 0 -1
*/
int cocoon_file_close(cocoon_file_t fd);
/**
* cocoon_file_stat -
*
* @param path
* @param st stat POSIX struct stat / Windows struct _stat
* @return 0 -1
*/
int cocoon_file_stat(const char *path, cocoon_stat_t *st);
/**
* cocoon_file_fstat -
*
* @param fd
* @param st stat
* @return 0 -1
*/
int cocoon_file_fstat(cocoon_file_t fd, cocoon_stat_t *st);
/**
* cocoon_stat_isreg -
*
* @param st stat
* @return true
*/
bool cocoon_stat_isreg(const cocoon_stat_t *st);
/**
* cocoon_stat_isdir -
*
* @param st stat
* @return true
*/
bool cocoon_stat_isdir(const cocoon_stat_t *st);
/**
* cocoon_stat_size -
*
* @param st stat
* @return
*/
int64_t cocoon_stat_size(const cocoon_stat_t *st);
/**
* cocoon_stat_mtime -
*
* @param st stat
* @return
*/
time_t cocoon_stat_mtime(const cocoon_stat_t *st);
/* ========== 高性能文件发送(零拷贝替代) ========== */
/**
* cocoon_file_send - socket
*
* Linux: 使 sendfile
* Windows/: 使 read+send 64KB
* /
*
* @param sock socket
* @param file
* @param offset
* @param count
* @return -1
*/
ssize_t cocoon_file_send(cocoon_socket_t sock, cocoon_file_t file,
int64_t offset, size_t count);
/* ========== 目录遍历 API ========== */
/**
* cocoon_dir_iter_t -
*
* POSIX: DIR* opendir
* Windows: FindFirstFile/FindNextFile
*/
typedef struct cocoon_dir_iter {
#ifdef COCOON_PLATFORM_WINDOWS
HANDLE handle; /**< FindFirstFile 句柄 */
WIN32_FIND_DATAA data; /**< 当前文件数据 */
bool first; /**< 首次调用标记 */
char path_buf[4096]; /**< 完整搜索路径(含通配符) */
#else
DIR *dir; /**< POSIX 目录句柄 */
#endif
char name[256]; /**< 当前文件名(输出) */
bool is_dir; /**< 当前项是否为目录 */
} cocoon_dir_iter_t;
/**
* cocoon_dir_open -
*
* @param iter
* @param path
* @return 0 -1
*/
int cocoon_dir_open(cocoon_dir_iter_t *iter, const char *path);
/**
* cocoon_dir_next -
*
* @param iter
* @return 0 1 -1
*/
int cocoon_dir_next(cocoon_dir_iter_t *iter);
/**
* cocoon_dir_close -
*
* @param iter
*/
void cocoon_dir_close(cocoon_dir_iter_t *iter);
/* ========== 信号处理 API ========== */
/**
* cocoon_signal_setup - /
*
* POSIX: signal(SIGINT/SIGTERM, handler)
* Windows: SetConsoleCtrlHandlerCtrl+C / Ctrl+Break /
*
* @param handler POSIX sig
*/
void cocoon_signal_setup(void (*handler)(int));
/* ========== 系统信息 API ========== */
/**
* cocoon_cpu_count - CPU
*
* POSIX: sysconf(_SC_NPROCESSORS_ONLN)
* Windows: GetSystemInfo dwNumberOfProcessors
*
* @return CPU 1
*/
uint32_t cocoon_cpu_count(void);
/* ========== 路径处理 API ========== */
/**
* cocoon_realpath -
*
* POSIX: realpath()
* Windows: _fullpath()MinGW GetFullPathNameA()
*
* @param path
* @param resolved
* @param resolved_size
* @return true false
*/
bool cocoon_realpath(const char *path, char *resolved, size_t resolved_size);
/**
* cocoon_mkdir -
*
* POSIX: mkdir(path, 0755)
* Windows: _mkdir(path)
*
* @param path
* @return 0 -1
*/
int cocoon_mkdir(const char *path);
/* ========== 错误处理 API ========== */
/**
* cocoon_get_last_error -
*
*
* - POSIX socket errno
* - Windows socket WSAGetLastError() POSIX errno
* - errno / GetLastError()
*
* @return POSIX errno
*/
int cocoon_get_last_error(void);
/**
* cocoon_strerror -
*
* @param err
* @return 线
*/
const char *cocoon_strerror(int err);
#endif /* COCOON_PLATFORM_H */