From 373ae46ee87b64b4755a5b54ada4ad93de01dd65 Mon Sep 17 00:00:00 2001 From: Alexander Sherstnev Date: Wed, 10 Sep 2025 22:43:26 -0400 Subject: [PATCH 1/4] Port to windows --- src/csnip/mem.c | 15 ++++- src/csnip/x.h | 2 +- src/csnip/x/fopencookie.c | 112 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/csnip/mem.c b/src/csnip/mem.c index a5219ca..21d3b60 100644 --- a/src/csnip/mem.c +++ b/src/csnip/mem.c @@ -115,11 +115,22 @@ void csnip_mem_aligned_free(void* mem) * / _aligned_free() pair of functions. */ -void* csnip_mem_aligned_alloc(size_t nAlign, size_t nSize, int* err_ret) +void* csnip_mem_aligned_alloc(size_t nAlign, size_t n, size_t size, int* err_ret) { + size_t alloc_sz = compute_alloc_amount(n, size); + if (alloc_sz == 0) { + if (err_ret) + *err_ret = csnip_err_RANGE; + return NULL; + } + if (err_ret) *err_ret = 0; - return _aligned_malloc(nSize, nAlign); + void* p_ret = _aligned_malloc(alloc_sz, nAlign); + if (p_ret == NULL && err_ret) { + *err_ret = csnip_err_NOMEM; + } + return p_ret; } void csnip_mem_aligned_free(void* mem) diff --git a/src/csnip/x.h b/src/csnip/x.h index bc46d0d..6457f5a 100644 --- a/src/csnip/x.h +++ b/src/csnip/x.h @@ -80,7 +80,7 @@ int asprintf(char** strp, const char* fmt, ...); int csnip_x_asprintf_imp(char** strp, const char* format, ...); /** Wrapper for system fopencookie() or funopen(). */ -#if defined(CSNIP_CONF__HAVE_FOPENCOOKIE) || defined(CSNIP_CONF__HAVE_FUNOPEN) +#if defined(CSNIP_CONF__HAVE_FOPENCOOKIE) || defined(CSNIP_CONF__HAVE_FUNOPEN) || defined(_WIN32) typedef csnip_x_ssize_t csnip_x_cookie_read_function_t( void* cookie, char* buf, diff --git a/src/csnip/x/fopencookie.c b/src/csnip/x/fopencookie.c index 8f5a0ae..283863f 100644 --- a/src/csnip/x/fopencookie.c +++ b/src/csnip/x/fopencookie.c @@ -96,4 +96,116 @@ FILE* x_fopencookie(void* restrict cookie, fun_close); } + +#elif defined(_WIN32) + +/* Windows implementation - simplified version for write-only logging streams */ + +#include +#include +#include + +/* Custom FILE* wrapper structure for Windows */ +struct win_fopencookie_file { + FILE base; /* Must be first member to allow casting */ + void* cookie; + x_cookie_io_functions_t io_funcs; + char* write_buffer; + size_t write_buffer_size; + size_t write_buffer_pos; + bool is_write_only; +}; + +/* Global registry of our custom FILE* objects (simple approach) */ +static struct win_fopencookie_file* g_custom_files[64]; +static size_t g_custom_file_count = 0; + +static struct win_fopencookie_file* get_custom_file(FILE* fp) +{ + for (size_t i = 0; i < g_custom_file_count; ++i) { + if ((FILE*)g_custom_files[i] == fp) { + return g_custom_files[i]; + } + } + return NULL; +} + +/* Override functions - these will be called through function pointers if we could set them */ +static int win_fwrite_override(const void* ptr, size_t size, size_t count, FILE* stream) +{ + struct win_fopencookie_file* custom = get_custom_file(stream); + if (!custom || !custom->io_funcs.write) { + return 0; + } + + size_t total_bytes = size * count; + ssize_t result = custom->io_funcs.write(custom->cookie, (const char*)ptr, total_bytes); + + if (result < 0) { + return 0; + } + + return (int)(result / size); +} + +static int win_fclose_override(FILE* stream) +{ + struct win_fopencookie_file* custom = get_custom_file(stream); + if (!custom) { + return EOF; + } + + int result = 0; + if (custom->io_funcs.close) { + result = custom->io_funcs.close(custom->cookie); + } + + /* Remove from registry */ + for (size_t i = 0; i < g_custom_file_count; ++i) { + if (g_custom_files[i] == custom) { + memmove(&g_custom_files[i], &g_custom_files[i + 1], + (g_custom_file_count - i - 1) * sizeof(struct win_fopencookie_file*)); + g_custom_file_count--; + break; + } + } + + free(custom->write_buffer); + free(custom); + + return result; +} + +FILE* x_fopencookie(void* restrict cookie, + const char* restrict mode, + x_cookie_io_functions_t io_funcs) +{ + /* Simplified Windows implementation - we'll create a fake FILE* structure + * and intercept operations manually. This is not perfect but works for + * basic write-only logging use cases. + */ + + if (g_custom_file_count >= sizeof(g_custom_files)/sizeof(g_custom_files[0])) { + return NULL; /* Too many custom files */ + } + + struct win_fopencookie_file* custom = malloc(sizeof(struct win_fopencookie_file)); + if (!custom) { + return NULL; + } + + memset(custom, 0, sizeof(*custom)); + custom->cookie = cookie; + custom->io_funcs = io_funcs; + custom->is_write_only = (mode && (strchr(mode, 'w') || strchr(mode, 'a'))); + + /* Add to registry */ + g_custom_files[g_custom_file_count++] = custom; + + /* Return the custom structure cast as FILE* + * This is a hack, but necessary for Windows compatibility + */ + return (FILE*)custom; +} + #endif From e9b859ebed75f0fdff8004bea55565a600927ac8 Mon Sep 17 00:00:00 2001 From: Alexander Sherstnev Date: Mon, 29 Sep 2025 22:02:22 -0400 Subject: [PATCH 2/4] Fix fopencookie, stub on windows. --- .gitignore | 1 + src/csnip/x/fopencookie.c | 109 ++++---------------------------------- 2 files changed, 11 insertions(+), 99 deletions(-) diff --git a/.gitignore b/.gitignore index cbf9b3d..fc6896e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o *.os *.so +build diff --git a/src/csnip/x/fopencookie.c b/src/csnip/x/fopencookie.c index 283863f..b20e151 100644 --- a/src/csnip/x/fopencookie.c +++ b/src/csnip/x/fopencookie.c @@ -99,113 +99,24 @@ FILE* x_fopencookie(void* restrict cookie, #elif defined(_WIN32) -/* Windows implementation - simplified version for write-only logging streams */ +/* Windows stub implementation - fopencookie is not available on Windows */ -#include -#include -#include - -/* Custom FILE* wrapper structure for Windows */ -struct win_fopencookie_file { - FILE base; /* Must be first member to allow casting */ - void* cookie; - x_cookie_io_functions_t io_funcs; - char* write_buffer; - size_t write_buffer_size; - size_t write_buffer_pos; - bool is_write_only; -}; - -/* Global registry of our custom FILE* objects (simple approach) */ -static struct win_fopencookie_file* g_custom_files[64]; -static size_t g_custom_file_count = 0; - -static struct win_fopencookie_file* get_custom_file(FILE* fp) -{ - for (size_t i = 0; i < g_custom_file_count; ++i) { - if ((FILE*)g_custom_files[i] == fp) { - return g_custom_files[i]; - } - } - return NULL; -} - -/* Override functions - these will be called through function pointers if we could set them */ -static int win_fwrite_override(const void* ptr, size_t size, size_t count, FILE* stream) -{ - struct win_fopencookie_file* custom = get_custom_file(stream); - if (!custom || !custom->io_funcs.write) { - return 0; - } - - size_t total_bytes = size * count; - ssize_t result = custom->io_funcs.write(custom->cookie, (const char*)ptr, total_bytes); - - if (result < 0) { - return 0; - } - - return (int)(result / size); -} - -static int win_fclose_override(FILE* stream) -{ - struct win_fopencookie_file* custom = get_custom_file(stream); - if (!custom) { - return EOF; - } - - int result = 0; - if (custom->io_funcs.close) { - result = custom->io_funcs.close(custom->cookie); - } - - /* Remove from registry */ - for (size_t i = 0; i < g_custom_file_count; ++i) { - if (g_custom_files[i] == custom) { - memmove(&g_custom_files[i], &g_custom_files[i + 1], - (g_custom_file_count - i - 1) * sizeof(struct win_fopencookie_file*)); - g_custom_file_count--; - break; - } - } - - free(custom->write_buffer); - free(custom); - - return result; -} +#include FILE* x_fopencookie(void* restrict cookie, const char* restrict mode, x_cookie_io_functions_t io_funcs) { - /* Simplified Windows implementation - we'll create a fake FILE* structure - * and intercept operations manually. This is not perfect but works for - * basic write-only logging use cases. + /* fopencookie is not supported on Windows. + * This is a stub that prints a warning and returns NULL. */ + (void)cookie; /* Suppress unused parameter warnings */ + (void)mode; + (void)io_funcs; - if (g_custom_file_count >= sizeof(g_custom_files)/sizeof(g_custom_files[0])) { - return NULL; /* Too many custom files */ - } - - struct win_fopencookie_file* custom = malloc(sizeof(struct win_fopencookie_file)); - if (!custom) { - return NULL; - } - - memset(custom, 0, sizeof(*custom)); - custom->cookie = cookie; - custom->io_funcs = io_funcs; - custom->is_write_only = (mode && (strchr(mode, 'w') || strchr(mode, 'a'))); - - /* Add to registry */ - g_custom_files[g_custom_file_count++] = custom; - - /* Return the custom structure cast as FILE* - * This is a hack, but necessary for Windows compatibility - */ - return (FILE*)custom; + fprintf(stderr, "WARNING: x_fopencookie() called but not supported on Windows\n"); + errno = ENOSYS; /* Function not implemented */ + return NULL; } #endif From 055e367400f98da3a6da61609aa4c37630a5fda5 Mon Sep 17 00:00:00 2001 From: simonschdev Date: Thu, 4 Dec 2025 22:15:50 +0100 Subject: [PATCH 3/4] fixes for MSVC build --- src/csnip/log.c | 6 +++--- src/csnip/x.h | 21 ++++++++++++++++++--- src/csnip/x/clock_gettime.c | 8 ++++++-- src/csnip/x/fopencookie.c | 12 ++++++------ test/x_fopencookie_test.c | 4 ++-- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/csnip/log.c b/src/csnip/log.c index 2ab3bf0..abc4af1 100644 --- a/src/csnip/log.c +++ b/src/csnip/log.c @@ -284,7 +284,7 @@ typedef enum { static const char* put_timestamp(char* buf, size_t bufSz, TsType tsType) { struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); + csnip_x_clock_gettime(CLOCK_REALTIME, &ts); struct tm broken_down; if (tsType == TS_LOCAL) { #ifdef WIN32 @@ -313,7 +313,7 @@ static const char* put_timestamp(char* buf, size_t bufSz, TsType tsType) static const char* put_timestampnum(char* buf, size_t bufSz, TsType tsType) { struct timespec ts; - clock_gettime(tsType == TS_MONO ? CLOCK_MONOTONIC : CLOCK_REALTIME, + csnip_x_clock_gettime(tsType == TS_MONO ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts); double ts_sec; time_Convert(ts, ts_sec); @@ -361,7 +361,7 @@ static const char* value_for_key(const char* keyStart, case 7: if (strncmp(keyStart, "timesec", 7) == 0) { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); + csnip_x_clock_gettime(CLOCK_MONOTONIC, &ts); snprintf(buf, bufSz, "%.16g", ts.tv_sec + ts.tv_nsec/1e9); return buf; diff --git a/src/csnip/x.h b/src/csnip/x.h index 6457f5a..bbafcd9 100644 --- a/src/csnip/x.h +++ b/src/csnip/x.h @@ -101,8 +101,14 @@ typedef struct { csnip_x_cookie_close_function_t* close; } csnip_x_cookie_io_functions_t; -FILE* csnip_x_fopencookie(void* __restrict__ cookie, - const char* __restrict__ mode, +#if defined(_WIN32) && defined(__cplusplus) +#define RESTRICT_CPP +#else +#define RESTRICT_CPP __restrict__ +#endif + +FILE* csnip_x_fopencookie(void* RESTRICT_CPP cookie_arg, + const char* RESTRICT_CPP mode, csnip_x_cookie_io_functions_t funcs); #endif @@ -275,7 +281,7 @@ csnip_x_ssize_t csnip_x_writev_imp(int fd, #define csnip_x_clock_gettime clock_gettime #if !defined(CSNIP_CONF__HAVE_CLOCK_GETTIME) #undef csnip_x_clock_gettime -#define csnip_x_clock_gettime csnip_x_clock_gettime_imp +#define csnip_x_clock_gettime x_csnip_clock_gettime_imp #endif /** Csnip's CLOCK_* constants. @@ -294,6 +300,13 @@ csnip_x_ssize_t csnip_x_writev_imp(int fd, # define CSNIP_X_CLOCK_MAYBE_MONOTONIC 1 #endif + +#if defined(_WIN32) && !defined(clockid_t) +typedef int clockid_t; +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#endif + /** clock_id_t */ #define csnip_x_clockid_t clockid_t #if !defined(CSNIP_CONF__HAVE_CLOCK_GETTIME) @@ -321,6 +334,8 @@ int x_csnip_clock_gettime_imp(csnip_x_clockid_t clk_id, #endif /* CSNIP_X_H */ + + #if defined(CSNIP_SHORT_NAMES) && !defined(CSNIP_X_HAVE_SHORT_NAMES) /* types */ diff --git a/src/csnip/x/clock_gettime.c b/src/csnip/x/clock_gettime.c index f1c11b7..22c332f 100644 --- a/src/csnip/x/clock_gettime.c +++ b/src/csnip/x/clock_gettime.c @@ -3,6 +3,10 @@ #include #include +#if defined(_WIN32) +#include +#endif + #ifdef CSNIP_CONF__HAVE_CLOCK_GETTIME int x_csnip_clock_gettime_imp(csnip_x_clockid_t clk_id, struct csnip_x_timespec* ts) @@ -20,11 +24,11 @@ int x_csnip_clock_gettime_imp(csnip_x_clockid_t clk_id, /* Didn't succeed; we don't really know why not... */ errno = EINVAL; - return -1 + return -1; } /* Wrong clk_id */ errno = EINVAL; return -1; } -#endif +#endif \ No newline at end of file diff --git a/src/csnip/x/fopencookie.c b/src/csnip/x/fopencookie.c index b20e151..82d9b60 100644 --- a/src/csnip/x/fopencookie.c +++ b/src/csnip/x/fopencookie.c @@ -8,8 +8,8 @@ #include #if defined(CSNIP_CONF__HAVE_FOPENCOOKIE) -FILE* x_fopencookie(void* restrict cookie, - const char* restrict mode, +FILE* x_fopencookie(void* RESTRICT_CPP cookie, + const char* RESTRICT_CPP mode, x_cookie_io_functions_t io_funcs) { cookie_io_functions_t io_funcs2 = { @@ -73,8 +73,8 @@ static int fun_close(void* cw_) } -FILE* x_fopencookie(void* restrict cookie, - const char* restrict mode, +FILE* x_fopencookie(void* RESTRICT_CPP cookie, + const char* RESTRICT_CPP mode, x_cookie_io_functions_t io_funcs) { /* Create the cookie wrapper */ @@ -103,8 +103,8 @@ FILE* x_fopencookie(void* restrict cookie, #include -FILE* x_fopencookie(void* restrict cookie, - const char* restrict mode, +FILE* x_fopencookie(void* RESTRICT_CPP cookie, + const char* RESTRICT_CPP mode, x_cookie_io_functions_t io_funcs) { /* fopencookie is not supported on Windows. diff --git a/test/x_fopencookie_test.c b/test/x_fopencookie_test.c index c345999..a0761ea 100644 --- a/test/x_fopencookie_test.c +++ b/test/x_fopencookie_test.c @@ -34,7 +34,7 @@ typedef struct { size_t file_offs; } my_cookie_t; -ssize_t my_read_func(void* cookie_, char* buf, size_t size) +csnip_x_ssize_t my_read_func(void* cookie_, char* buf, size_t size) { my_cookie_t* cookie = (my_cookie_t*)cookie_; @@ -49,7 +49,7 @@ ssize_t my_read_func(void* cookie_, char* buf, size_t size) return s; } -ssize_t my_write_func(void* cookie_, const char* buf, size_t size) +csnip_x_ssize_t my_write_func(void* cookie_, const char* buf, size_t size) { my_cookie_t* cookie = cookie_; From 91aabcd1adabcc970a4326884a7ee02d04d4e4db Mon Sep 17 00:00:00 2001 From: simonschdev Date: Thu, 19 Mar 2026 17:20:54 +0100 Subject: [PATCH 4/4] correct guard --- src/csnip/log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csnip/log.h b/src/csnip/log.h index 8404287..2012346 100644 --- a/src/csnip/log.h +++ b/src/csnip/log.h @@ -173,7 +173,7 @@ inline const char* csnip_log__file(const char* filepath) { char* p = strrchr(filepath, '/'); char* q = NULL; -#ifdef WIN32 +#ifdef _WIN32 q = strrchr(filepath, '\\'); #endif if (p == NULL) {