diff options
| author | Mosder <git@mosder.eu> | 2026-10-20 14:44:33 +0200 |
|---|---|---|
| committer | Mosder <git@mosder.eu> | 2026-10-20 14:44:33 +0200 |
| commit | fc5f5f1f58542500734841822768267d0ece2456 (patch) | |
| tree | 0501e3d718338094f58f5e6af1232ee4900372b2 | |
| parent | ec315985c9f51c932b1177539c43a024bf58207d (diff) | |
feat: improved support for windows. added gating behind _WIN32 to use _ prefixed versions of functions and made it work (with limited functionality) on machines without fileno
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | compat/compat.h | 6 | ||||
| -rw-r--r-- | include/moslib/safe.h | 16 | ||||
| -rw-r--r-- | src/safe.c | 15 | ||||
| -rw-r--r-- | src/tester.c | 41 | ||||
| -rw-r--r-- | tests/safe_tests.c | 43 | ||||
| -rw-r--r-- | tests/string_tests.c | 3 |
7 files changed, 104 insertions, 30 deletions
@@ -29,12 +29,18 @@ endef PROBED:= \ $(call probe_fun,string.h,memmem) \ - $(call probe_fun,string.h,strdup) \ - $(call probe_fun,stdio.h,fileno) + $(call probe_fun,string.h,strdup) CFLAGS+=$(PROBED) TESTS_CFLAGS+=$(PROBED) +FS_FLAG:=$(shell printf '#include "compat.h"\n#include <stdio.h>\nint main(void){\n#ifdef _WIN32\n_fileno;\n#else\nfileno;\n#endif\nreturn 0;}' \ + | $(CC) $(CFLAGS) -x c - -o /dev/null 2>/dev/null \ + || echo -DNO_FS) + +CFLAGS+=$(FS_FLAG) +TESTS_CFLAGS+=$(FS_FLAG) + both: CLEANUP=true both: clean shared static @$(MAKE) clean --no-print-directory diff --git a/compat/compat.h b/compat/compat.h index 314ffcf..367ec47 100644 --- a/compat/compat.h +++ b/compat/compat.h @@ -27,10 +27,4 @@ extern char *mos_strdup(const char *s); extern void *mos_memmem(const void *h, size_t h_size, const void *n, size_t n_size); #endif // NO_MEMMEM -#ifndef NO_FILENO -#define mos_fileno fileno -#else -#error fileno fallback not implemented -#endif // NO_MEMMEM - #endif // MOSLIB_COMPAT_H diff --git a/include/moslib/safe.h b/include/moslib/safe.h index a606f17..e9fb7bb 100644 --- a/include/moslib/safe.h +++ b/include/moslib/safe.h @@ -4,9 +4,14 @@ #include <stddef.h> #include <stdio.h> -#include <unistd.h> #include <sys/types.h> +#ifndef _WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif + #ifndef MOSLIB_SAFE_H #define MOSLIB_SAFE_H @@ -19,8 +24,11 @@ #define safe_tmpfile mos_safe_tmpfile #define safe_dup mos_safe_dup #define safe_dup2 mos_safe_dup2 + +#ifndef _WIN32 #define safe_fork mos_safe_fork #define safe_pipe mos_safe_pipe +#endif #endif // MOS_FORCE_PREFIXES @@ -41,8 +49,11 @@ typedef struct { #define mos_safe_tmpfile() mos_safe_tmpfile_fn(mos_err_info) #define mos_safe_dup(fd) mos_safe_dup_fn(fd, mos_err_info) #define mos_safe_dup2(fd, fd2) mos_safe_dup2_fn(fd, fd2, mos_err_info) + +#ifndef _WIN32 #define mos_safe_fork() mos_safe_fork_fn(mos_err_info) #define mos_safe_pipe(fd) mos_safe_pipe_fn(fd, mos_err_info) +#endif // Function prototypes for macros extern void *mos_safe_malloc_fn(size_t size, MosSafeErrInfo info); @@ -52,7 +63,10 @@ extern FILE *mos_safe_fopen_fn(const char *path, const char *mode, MosSafeErrInf extern FILE *mos_safe_tmpfile_fn(MosSafeErrInfo info); extern int mos_safe_dup_fn(int fd, MosSafeErrInfo info); extern int mos_safe_dup2_fn(int fd, int fd2, MosSafeErrInfo info); + +#ifndef _WIN32 extern pid_t mos_safe_fork_fn(MosSafeErrInfo info); extern int mos_safe_pipe_fn(int fd[2], MosSafeErrInfo info); +#endif #endif // MOSLIB_SAFE_H @@ -4,7 +4,12 @@ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> + +#ifndef _WIN32 #include <unistd.h> +#else +#include <io.h> +#endif #define ERR_MESS(...) err_mess(info, __VA_ARGS__) @@ -58,7 +63,11 @@ FILE *mos_safe_tmpfile_fn(MosSafeErrInfo info) { } int mos_safe_dup_fn(int fd, MosSafeErrInfo info) { +#ifndef _WIN32 int res = dup(fd); +#else + int res = _dup(fd); +#endif if (res != -1) return res; ERR_MESS("failed to dup %d", fd); @@ -66,13 +75,18 @@ int mos_safe_dup_fn(int fd, MosSafeErrInfo info) { } int mos_safe_dup2_fn(int fd, int fd2, MosSafeErrInfo info) { +#ifndef _WIN32 int res = dup2(fd, fd2); +#else + int res = _dup2(fd, fd2); +#endif if (res != -1) return res; ERR_MESS("failed to dup %d 2 %d", fd, fd2); exit(EXIT_FAILURE); } +#ifndef _WIN32 pid_t mos_safe_fork_fn(MosSafeErrInfo info) { pid_t pid = fork(); if (pid != -1) @@ -88,3 +102,4 @@ int mos_safe_pipe_fn(int fd[2], MosSafeErrInfo info) { ERR_MESS("failed to pipe"); exit(EXIT_FAILURE); } +#endif diff --git a/src/tester.c b/src/tester.c index 05bc3d1..f6df372 100644 --- a/src/tester.c +++ b/src/tester.c @@ -8,7 +8,16 @@ #include <stdlib.h> #include <string.h> #include <sys/wait.h> + +#ifndef _WIN32 #include <unistd.h> +#define mos_close close +#define mos_isatty isatty +#else +#include <io.h> +#define mos_close _close +#define mos_isatty _isatty +#endif #include "moslib/safe.h" @@ -39,8 +48,9 @@ static Outputs suppressed = { }; #define print_color(color, ...) \ - (isatty(STDOUT_FILENO) ? (printf("\033[%dm", color), printf(__VA_ARGS__), printf("\033[0m")) \ - : printf(__VA_ARGS__)) + (mos_isatty(STDOUT_FILENO) \ + ? (printf("\033[%dm", color), printf(__VA_ARGS__), printf("\033[0m")) \ + : printf(__VA_ARGS__)) #define nl printf("\n") static void print_center(const char *text, int color, char padding_char) { @@ -111,6 +121,10 @@ void mos_test_assert(int expression, const char *fail_message) { } void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name) { +#ifdef _WIN32 + fprintf(stderr, "test_assert_exit is not supported on windows\n"); + exit(1); +#else int fd[2]; mos_safe_pipe(fd); pid_t pid = mos_safe_fork(); @@ -145,6 +159,7 @@ void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name) { print_color(RED, "ASSERT FAILED: "); printf("exit code was %d, expected %d (in function %s)\n", exit_code, code, name); } +#endif } void mos_test_assert_out_fn( @@ -154,15 +169,19 @@ void mos_test_assert_out_fn( const char *fn_name, const char *stream_name ) { +#ifdef NO_FS + fprintf(stderr, "FATAL: test_assert_out is not supported on your system\n"); + exit(1); +#else size_t n = strlen(output); char *out = mos_safe_calloc(n + 2, 1); FILE *tmp = mos_safe_tmpfile(); - int fd = mos_fileno(stream); + int fd = fileno(stream); int og = mos_safe_dup(fd); fflush(stream); - mos_safe_dup2(mos_fileno(tmp), fd); + mos_safe_dup2(fileno(tmp), fd); function(); fflush(stream); @@ -171,7 +190,7 @@ void mos_test_assert_out_fn( fclose(tmp); mos_safe_dup2(og, fd); - close(og); + mos_close(og); if (strcmp(out, output)) { failed = 1; @@ -181,16 +200,21 @@ void mos_test_assert_out_fn( printf(" expected: %s\n", output); } free(out); +#endif } void mos_suppress_output_fn(FILE *stream) { +#ifdef NO_FS + fprintf(stderr, "FATAL: suppress_output is not supported on your system\n"); + exit(1); +#else if (!suppressed.outs || suppressed.n_outs >= suppressed.out_cap) { while (suppressed.n_outs >= suppressed.out_cap) suppressed.out_cap *= 2; suppressed.outs = mos_safe_realloc(suppressed.outs, suppressed.out_cap * sizeof(int)); suppressed.ogs = mos_safe_realloc(suppressed.ogs, suppressed.out_cap * sizeof(int)); } - int fd = mos_fileno(stream); + int fd = fileno(stream); suppressed.outs[suppressed.n_outs] = fd; suppressed.ogs[suppressed.n_outs++] = mos_safe_dup(fd); @@ -198,7 +222,8 @@ void mos_suppress_output_fn(FILE *stream) { dev_null = mos_safe_tmpfile(); fflush(stream); - mos_safe_dup2(mos_fileno(dev_null), fd); + mos_safe_dup2(fileno(dev_null), fd); +#endif } void mos_unsuppress_outputs(void) { @@ -210,7 +235,7 @@ void mos_unsuppress_outputs(void) { for (size_t i = suppressed.n_outs; i-- > 0;) { mos_safe_dup2(suppressed.ogs[i], suppressed.outs[i]); - close(suppressed.ogs[i]); + mos_close(suppressed.ogs[i]); } suppressed.n_outs = 0; diff --git a/tests/safe_tests.c b/tests/safe_tests.c index 0915550..fd45603 100644 --- a/tests/safe_tests.c +++ b/tests/safe_tests.c @@ -4,7 +4,12 @@ #include <limits.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> + +#ifndef _WIN32 +#define mos_close close +#else +#define mos_close _close +#endif TEST_HELPER(malloc_exit) { safe_malloc(ULLONG_MAX); @@ -14,7 +19,9 @@ TEST(test_safe_malloc) { void *p = safe_malloc(1024); test_assert(p != NULL, "Failed to malloc 1KiB"); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(malloc_exit, EXIT_FAILURE); unsuppress_outputs(); } @@ -27,7 +34,9 @@ TEST(test_safe_calloc) { void *p = safe_calloc(16, 16); test_assert(p != NULL, "Failed to calloc 16 items of 16 bytes"); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(calloc_exit, EXIT_FAILURE); unsuppress_outputs(); } @@ -45,7 +54,9 @@ TEST(test_safe_realloc) { p = safe_realloc(p, 4096); test_assert(p != NULL, "Failed to realloc 1KiB to 4KiB"); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(realloc_exit, EXIT_FAILURE); unsuppress_outputs(); } @@ -58,7 +69,9 @@ TEST(test_safe_fopen) { FILE *fp = safe_fopen(__FILE__, "r"); test_assert(fp != NULL, "Failed to fopen current file"); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(fopen_exit, EXIT_FAILURE); unsuppress_outputs(); } @@ -75,9 +88,11 @@ TEST_HELPER(dup_exit) { TEST(test_safe_dup) { int fd = safe_dup(STDOUT_FILENO); test_assert(fd != -1, "Failed to dup stdout"); - close(fd); + mos_close(fd); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(dup_exit, EXIT_FAILURE); unsuppress_outputs(); } @@ -87,21 +102,24 @@ TEST_HELPER(dup2_exit) { } TEST(test_safe_dup2) { - int res = dup2(STDOUT_FILENO, STDOUT_FILENO); + int res = safe_dup2(STDOUT_FILENO, STDOUT_FILENO); test_assert(res != -1, "Failed to dup stdout 2 itself"); - int fd = dup(STDOUT_FILENO); - res = dup2(STDERR_FILENO, STDOUT_FILENO); + int fd = safe_dup(STDOUT_FILENO); + res = safe_dup2(STDERR_FILENO, STDOUT_FILENO); test_assert(res != -1, "Failed to dup stderr 2 stdout"); - res = dup2(fd, STDOUT_FILENO); + res = safe_dup2(fd, STDOUT_FILENO); test_assert(res != -1, "Failed to restore stdout"); - close(fd); + mos_close(fd); +#ifndef NO_FS suppress_output(stderr); +#endif test_assert_exit(dup2_exit, EXIT_FAILURE); unsuppress_outputs(); } +#ifndef _WIN32 TEST(test_safe_fork) { pid_t pid = safe_fork(); test_assert(pid != -1, "Failed to create a child process"); @@ -113,12 +131,10 @@ TEST(test_safe_pipe) { int fd[2]; int res = safe_pipe(fd); test_assert(res != -1, "Failed to create a pipe"); - close(fd[0]); - close(fd[1]); + mos_close(fd[0]); + mos_close(fd[1]); } - -#define mos_safe_fork() mos_safe_fork_fn(mos_err_info) -#define mos_safe_pipe(fd) mos_safe_pipe_fn(fd, mos_err_info) +#endif void safe_tests(Tester *tester) { TestGroup *group = add_test_group(tester, "moslib/safe.h"); @@ -129,6 +145,9 @@ void safe_tests(Tester *tester) { add_test(group, test_safe_tmpfile); add_test(group, test_safe_dup); add_test(group, test_safe_dup2); + +#ifndef _WIN32 add_test(group, test_safe_fork); add_test(group, test_safe_pipe); +#endif } diff --git a/tests/string_tests.c b/tests/string_tests.c index 7638f9b..41c6cd8 100644 --- a/tests/string_tests.c +++ b/tests/string_tests.c @@ -6,7 +6,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> #include "moslib/ds/array.h" @@ -43,7 +42,9 @@ TEST(ss_print_helper) { } TEST(printing) { +#ifndef NO_FS test_assert_out(ss_print_helper, stdout, "test"); +#endif StringSlice ss = ss_from_str("slice"); char buf[16]; |
