summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAriadne Conill <ariadne@dereferenced.org>2022-04-04 08:21:05 -0500
committerTimo Teräs <timo.teras@iki.fi>2022-04-11 09:35:47 +0300
commit44994a46d4a353bf4596b40a8720e22afe12699e (patch)
tree1c08177c0705ec71d93c0e2244611092bb18c0e2
parent191e2d412dfdfd5ac0c49be3752494e0708fa060 (diff)
downloadapk-tools-44994a46d4a353bf4596b40a8720e22afe12699e.tar.gz
apk-tools-44994a46d4a353bf4596b40a8720e22afe12699e.tar.bz2
apk-tools-44994a46d4a353bf4596b40a8720e22afe12699e.tar.xz
apk-tools-44994a46d4a353bf4596b40a8720e22afe12699e.zip
portability: check for qsort_r which does not match POSIX-next definition
FreeBSD (and also Darwin) introduced its own qsort_r, which has different semantics than the one slated for inclusion in POSIX. Add a portability thunk to deal with translating between implementations. [TT: minor stylistic fixes]
-rw-r--r--portability/meson.build14
-rw-r--r--portability/stdlib.h26
2 files changed, 40 insertions, 0 deletions
diff --git a/portability/meson.build b/portability/meson.build
index d077345..1a5361e 100644
--- a/portability/meson.build
+++ b/portability/meson.build
@@ -21,6 +21,20 @@ foreach f : check_functions
endforeach
+# Check for wrong (non-POSIX) qsort_r prototype
+qsort_r_test = '''
+ #define _GNU_SOURCE
+ #include <stdlib.h>
+ _Static_assert(_Generic((qsort_r),
+ void (*)(void *, size_t, size_t, void *,
+ int (*)(void *, const void *, const void *)) : 1, default: 0),
+ "Bad prototype not matched");
+'''
+if cc.compiles(qsort_r_test, name: 'Test qsort_r non-POSIX prototype')
+ add_project_arguments('-DHAVE_BROKEN_QSORT_R', language: 'c')
+endif
+
+
if libportability_src.length() > 0
libportability = static_library(
'portability',
diff --git a/portability/stdlib.h b/portability/stdlib.h
index 6254c7c..25bd8ef 100644
--- a/portability/stdlib.h
+++ b/portability/stdlib.h
@@ -1,3 +1,4 @@
+#pragma once
#include_next <stdlib.h>
#ifdef NEED_QSORT_R
@@ -5,3 +6,28 @@ void qsort_r(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg);
#endif
+
+#ifdef HAVE_BROKEN_QSORT_R
+struct __portable_qsort_r_compat_arg {
+ int (*compar)(const void *, const void *, void *);
+ void *arg;
+};
+
+static inline int __portable_qsort_r_compar_compat(void *arg, const void *a, const void *b)
+{
+ struct __portable_qsort_r_compat_arg *compat_arg = arg;
+ return compat_arg->compar(a, b, compat_arg->arg);
+}
+
+static inline void __portable_qsort_r(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *, void *),
+ void *arg)
+{
+ struct __portable_qsort_r_compat_arg compat_arg = {
+ .compar = compar,
+ .arg = arg,
+ };
+ qsort_r(base, nmemb, size, &compat_arg, __portable_qsort_r_compar_compat);
+}
+#define qsort_r(...) __portable_qsort_r(__VA_ARGS__)
+#endif