aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMosder <git@mosder.eu>2026-09-16 23:47:49 +0200
committerMosder <git@mosder.eu>2026-09-16 23:47:49 +0200
commit644130802a51d91b90e85a0769f642c3e0203aef (patch)
treead97ac1da8541a440a86c4c99402354bd94b06ca
parent4af9b2a86ad5f5b7e59ba882aa527ecead75be0e (diff)
feat: added a simple compatibbility layer for functions not from C99 standard
-rw-r--r--Makefile27
-rw-r--r--compat/compat.c31
-rw-r--r--compat/compat.h21
-rw-r--r--include/moslib/tester.h7
-rw-r--r--src/string.c3
-rw-r--r--src/tester.c46
-rw-r--r--tests/ds/hashmap_tests.c3
-rw-r--r--tests/string_tests.c5
8 files changed, 102 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index d9775c1..0739c71 100644
--- a/Makefile
+++ b/Makefile
@@ -13,17 +13,30 @@ LIB_SUDO:=$(shell test -w $(LIB_DIR) || echo sudo)
INC_DIR=$(TARGET_PREFIX)/include
INC_SUDO:=$(shell test -w $(INC_DIR) || echo sudo)
-CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -fPIC -I./include -O2 -c
-SRCS:=$(shell find src | grep "\.c$$")
-CLEANUP=$(MAKE) clean
+CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -fPIC -I./include -I./compat -O2 -c
+SRCS:=$(shell find src compat | grep "\.c$$")
+CLEANUP=$(MAKE) clean --no-print-directory
-TESTS_CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -I$(INC_DIR) -Og -ggdb -c
+TESTS_CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -I$(INC_DIR) -I./compat -Og -ggdb -c
TESTS_LDFLAGS=-L$(LIB_DIR) -Wl,-rpath,$(LIB_DIR) -lmoslib
-TESTS_SRCS:=$(shell find tests | grep "\.c$$")
+TESTS_SRCS:=$(shell find tests compat | grep "\.c$$")
+
+define probe_fun
+ $(shell printf '#define $(1)\n#include <$(2)>\nint main(void){$(3);}' \
+ | $(CC) $(CFLAGS) -x c - -o /dev/null 2>/dev/null \
+ || echo -DNO_$(shell echo $(3) | tr a-z A-Z))
+endef
+
+PROBED:= \
+ $(call probe_fun,_GNU_SOURCE,string.h,memmem) \
+ $(call probe_fun,_XOPEN_SOURCE 500,string.h,strdup)
+
+CFLAGS+=$(PROBED)
+TESTS_CFLAGS+=$(PROBED)
both: CLEANUP=true
both: clean shared static
- @$(MAKE) clean
+ @$(MAKE) clean --no-print-directory
shared: clean compile headers
$(LIB_SUDO) $(CC) -shared *.o -o $(LIB_DIR)/libmoslib.so
@@ -45,7 +58,7 @@ test: clean
$(CC) $(TESTS_CFLAGS) $(TESTS_SRCS)
$(CC) $(TESTS_LDFLAGS) *.o -o run_tests
./run_tests
- @$(MAKE) clean
+ @$(CLEANUP)
clean:
rm *.o run_tests 2>/dev/null || true
diff --git a/compat/compat.c b/compat/compat.c
new file mode 100644
index 0000000..1112146
--- /dev/null
+++ b/compat/compat.c
@@ -0,0 +1,31 @@
+#include "compat.h"
+
+#ifdef NO_STRDUP
+#include "moslib/safe.h"
+#include <string.h>
+char *strdup(const char *s) {
+ char *s2 = mos_safe_malloc(strlen(s) + 1);
+ strcpy(s2, s);
+ return s2;
+}
+#endif // NO_STRDUP
+
+#ifdef NO_MEMMEM
+void *memmem(const void *h, size_t h_size, const void *n, size_t n_size) {
+ if (n_size == 0)
+ return (void *)h;
+ if (n_size > h_size)
+ return NULL;
+
+ const unsigned char *p = h;
+ const unsigned char *end = p + h_size - n_size + 1;
+ unsigned char c = *(unsigned char *)n;
+ while ((p = memchr(p, c, end - p))) {
+ if (memcmp(p, n, n_size) == 0)
+ return (void *)p;
+ p++;
+ }
+
+ return NULL;
+}
+#endif // NO_MEMMEM
diff --git a/compat/compat.h b/compat/compat.h
new file mode 100644
index 0000000..b36b17f
--- /dev/null
+++ b/compat/compat.h
@@ -0,0 +1,21 @@
+// compat.h
+// Compatibility layer for functions not in standard C99
+
+#ifndef MOSLIB_COMPAT_H
+#define MOSLIB_COMPAT_H
+
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE
+
+typedef void declaration;
+
+#ifdef NO_STRDUP
+extern char *strdup(const char *s);
+#endif // NO_STRDUP
+
+#ifdef NO_MEMMEM
+#include <stddef.h>
+extern void *memmem(const void *h, size_t h_size, const void *n, size_t n_size);
+#endif // NO_MEMMEM
+
+#endif // MOSLIB_COMPAT_H
diff --git a/include/moslib/tester.h b/include/moslib/tester.h
index 9f3b482..4c77d73 100644
--- a/include/moslib/tester.h
+++ b/include/moslib/tester.h
@@ -174,14 +174,14 @@ extern void mos_test_assert(int expression, const char *fail_message);
// output
// expected output of the function
#define mos_test_assert_out(function, stream, output) \
- mos_test_assert_out_fn(function, stream, output, #function, #stream)
+ mos_test_assert_out_fn(function, &(stream), output, #function, #stream)
// Suppress given output
//
// Arguments:
// out
// outpout to suppress
-extern void mos_suppress_output(FILE *out);
+#define mos_suppress_output(out) mos_suppress_output_fn(&(out))
// Unuppress previously suppressed outputs
// Will unsupress all of the outputs that were suppressed
@@ -219,11 +219,12 @@ extern MosTestGroup *mos_add_test_group_fn(MosTester *tester, const char *group_
extern void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name);
extern void mos_test_assert_out_fn(
MosTestFn function,
- FILE *stream,
+ FILE **stream,
const char *output,
const char *fn_name,
const char *stream_name
);
+extern void mos_suppress_output_fn(FILE **out);
extern void mos_add_test_fn(MosTestGroup *group, MosTestFn test, const char *name);
#endif // MOSLIB_TESTER_H
diff --git a/src/string.c b/src/string.c
index c744578..6625d8f 100644
--- a/src/string.c
+++ b/src/string.c
@@ -1,4 +1,5 @@
-#define _GNU_SOURCE
+#include "compat.h"
+
#define MOS_FORCE_PREFIXES
#include "moslib/string.h"
diff --git a/src/tester.c b/src/tester.c
index 42f0486..9c1c27c 100644
--- a/src/tester.c
+++ b/src/tester.c
@@ -1,4 +1,3 @@
-#define _XOPEN_SOURCE 600
#define MOS_FORCE_PREFIXES
#include "moslib/tester.h"
@@ -24,8 +23,8 @@ static int failed = 0;
static FILE *dev_null = NULL;
typedef struct {
- int *outs;
- int *ogs;
+ FILE ***outs;
+ FILE **ogs;
size_t n_outs;
size_t out_cap;
} Outputs;
@@ -132,7 +131,7 @@ void mos_test_assert_exit_fn(MosTestFn function, int code, const char *name) {
void mos_test_assert_out_fn(
MosTestFn function,
- FILE *stream,
+ FILE **stream,
const char *output,
const char *fn_name,
const char *stream_name
@@ -140,21 +139,16 @@ void mos_test_assert_out_fn(
size_t n = strlen(output);
char *out = mos_safe_calloc(n + 2, 1);
- FILE *tmp = mos_safe_tmpfile();
-
- int fd = fileno(stream);
- int og = mos_safe_dup(fd);
- fflush(stream);
- mos_safe_dup2(fileno(tmp), fd);
+ FILE *og = *stream;
+ fflush(*stream);
+ *stream = mos_safe_tmpfile();
function();
- fflush(stream);
- rewind(tmp);
- fread(out, 1, n + 1, tmp);
- fclose(tmp);
-
- mos_safe_dup2(og, fd);
- close(og);
+ fflush(*stream);
+ rewind(*stream);
+ fread(out, 1, n + 1, *stream);
+ fclose(*stream);
+ *stream = og;
if (strcmp(out, output)) {
failed = 1;
@@ -166,21 +160,21 @@ void mos_test_assert_out_fn(
free(out);
}
-void mos_suppress_output(FILE *out) {
+void mos_suppress_output_fn(FILE **out) {
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));
}
- suppressed.outs[suppressed.n_outs] = fileno(out);
- suppressed.ogs[suppressed.n_outs++] = dup(fileno(out));
+ suppressed.outs[suppressed.n_outs] = out;
+ suppressed.ogs[suppressed.n_outs++] = *out;
if (!dev_null)
- dev_null = mos_safe_fopen("/dev/null", "w");
+ dev_null = mos_safe_tmpfile();
- fflush(out);
- dup2(fileno(dev_null), fileno(out));
+ fflush(*out);
+ *out = dev_null;
}
void mos_unsuppress_outputs(void) {
@@ -190,10 +184,8 @@ void mos_unsuppress_outputs(void) {
if (dev_null)
fflush(dev_null);
- for (size_t i = suppressed.n_outs; i-- > 0;) {
- dup2(suppressed.ogs[i], suppressed.outs[i]);
- close(suppressed.ogs[i]);
- }
+ for (size_t i = suppressed.n_outs; i-- > 0;)
+ *suppressed.outs = suppressed.ogs;
suppressed.n_outs = 0;
}
diff --git a/tests/ds/hashmap_tests.c b/tests/ds/hashmap_tests.c
index 268bc29..822ee2a 100644
--- a/tests/ds/hashmap_tests.c
+++ b/tests/ds/hashmap_tests.c
@@ -1,4 +1,5 @@
-#define _GNU_SOURCE
+#include "compat.h"
+
#define MOS_HM_LOAD_FACTOR 100
#include "hashmap_tests.h"
#include "moslib/ds/hashmap.h"
diff --git a/tests/string_tests.c b/tests/string_tests.c
index f600400..eaa9498 100644
--- a/tests/string_tests.c
+++ b/tests/string_tests.c
@@ -1,6 +1,7 @@
-#define _XOPEN_SOURCE 600
-#include "string_tests.h"
+#include "compat.h"
+
#include "moslib/string.h"
+#include "string_tests.h"
#include <stdlib.h>
#include <string.h>