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]
cute-signatures
Ariadne Conill 2022-04-04 08:21:05 -05:00 committed by Timo Teräs
parent 191e2d412d
commit 44994a46d4
2 changed files with 40 additions and 0 deletions

View File

@ -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',

View File

@ -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