From 44994a46d4a353bf4596b40a8720e22afe12699e Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 4 Apr 2022 08:21:05 -0500 Subject: [PATCH] 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] --- portability/meson.build | 14 ++++++++++++++ portability/stdlib.h | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) 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 + _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 #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