diff options
author | Ariadne Conill <ariadne@dereferenced.org> | 2022-04-04 08:21:05 -0500 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2022-04-11 09:35:47 +0300 |
commit | 44994a46d4a353bf4596b40a8720e22afe12699e (patch) | |
tree | 1c08177c0705ec71d93c0e2244611092bb18c0e2 | |
parent | 191e2d412dfdfd5ac0c49be3752494e0708fa060 (diff) | |
download | apk-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.build | 14 | ||||
-rw-r--r-- | portability/stdlib.h | 26 |
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 |