libroot/stdlib: Add qsort_r.
It's in POSIX-2024. Remove the libgnu implementation and just import the changes from latest FreeBSD (dc36d6f9bb1753f3) instead. While at it, put the non-standard sort functions behind _DEFAULT_SOURCE.
This commit is contained in:
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Haiku, Inc. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Isaac Turner, [email protected]
|
|
||||||
* Jacob Secunda, [email protected]
|
|
||||||
*/
|
|
||||||
#ifndef _GNU_STDLIB_H_
|
|
||||||
#define _GNU_STDLIB_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include_next <stdlib.h>
|
|
||||||
#include <features.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _DEFAULT_SOURCE
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int (*_compare_function_qsort_r)(const void*, const void*, void*);
|
|
||||||
|
|
||||||
extern void qsort_r(void* base, size_t numElements, size_t sizeOfElement,
|
|
||||||
_compare_function_qsort_r, void* cookie);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _DEFAULT_SOURCE */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _GNU_STDLIB_H_ */
|
|
||||||
@@ -120,19 +120,25 @@ extern void lcong48(unsigned short int param[7]);
|
|||||||
|
|
||||||
/* search and sort functions */
|
/* search and sort functions */
|
||||||
typedef int (*_compare_function)(const void *, const void *);
|
typedef int (*_compare_function)(const void *, const void *);
|
||||||
|
typedef int (*_compare_function_qsort_r)(const void*, const void*, void*);
|
||||||
|
|
||||||
extern void *bsearch(const void *key, const void *base, size_t numElements,
|
extern void *bsearch(const void *key, const void *base, size_t numElements,
|
||||||
size_t sizeOfElement, _compare_function);
|
size_t sizeOfElement, _compare_function);
|
||||||
|
extern void qsort(void *base, size_t numElements, size_t sizeOfElement,
|
||||||
|
_compare_function);
|
||||||
|
extern void qsort_r(void* base, size_t numElements, size_t sizeOfElement,
|
||||||
|
_compare_function_qsort_r, void* cookie);
|
||||||
|
|
||||||
|
#ifdef _DEFAULT_SOURCE
|
||||||
extern int heapsort(void *base, size_t numElements, size_t sizeOfElement,
|
extern int heapsort(void *base, size_t numElements, size_t sizeOfElement,
|
||||||
_compare_function);
|
_compare_function);
|
||||||
extern int mergesort(void *base, size_t numElements, size_t sizeOfElement,
|
extern int mergesort(void *base, size_t numElements, size_t sizeOfElement,
|
||||||
_compare_function);
|
_compare_function);
|
||||||
extern void qsort(void *base, size_t numElements, size_t sizeOfElement,
|
|
||||||
_compare_function);
|
|
||||||
extern int radixsort(u_char const **base, int numElements,
|
extern int radixsort(u_char const **base, int numElements,
|
||||||
u_char const *table, u_int endByte);
|
u_char const *table, u_int endByte);
|
||||||
extern int sradixsort(u_char const **base, int numElements,
|
extern int sradixsort(u_char const **base, int numElements,
|
||||||
u_char const *table, u_int endByte);
|
u_char const *table, u_int endByte);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* misc math functions */
|
/* misc math functions */
|
||||||
extern int abs(int number);
|
extern int abs(int number);
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
|
|
||||||
SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] :
|
SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] :
|
||||||
crypt.cpp
|
crypt.cpp
|
||||||
qsort.c
|
|
||||||
sched_affinity.cpp
|
sched_affinity.cpp
|
||||||
sched_getcpu.cpp
|
sched_getcpu.cpp
|
||||||
xattr.cpp
|
xattr.cpp
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 Haiku, Inc. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Isaac Turner, [email protected]
|
|
||||||
* Jacob Secunda, [email protected]
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define SORT_R_SWAP(a, b, tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
|
|
||||||
|
|
||||||
|
|
||||||
/* swap itemA and itemB */
|
|
||||||
/* itemA and itemB must not be equal! */
|
|
||||||
static inline void
|
|
||||||
sort_r_swap(char* __restrict itemA, char* __restrict itemB,
|
|
||||||
size_t sizeOfElement)
|
|
||||||
{
|
|
||||||
char tmp;
|
|
||||||
char* end = itemA + sizeOfElement;
|
|
||||||
for (; itemA < end; itemA++, itemB++)
|
|
||||||
SORT_R_SWAP(* itemA, * itemB, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* swap itemA and itemB if itemA > itemB */
|
|
||||||
/* itemA and itemB must not be equal! */
|
|
||||||
static inline int
|
|
||||||
sort_r_cmpswap(char* __restrict itemA, char* __restrict itemB,
|
|
||||||
size_t sizeOfElement, _compare_function_qsort_r cmpFunc, void* cookie)
|
|
||||||
{
|
|
||||||
if (cmpFunc(itemA, itemB, cookie) > 0) {
|
|
||||||
sort_r_swap(itemA, itemB, sizeOfElement);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Swap consecutive blocks of bytes of size na and nb starting at memory addr
|
|
||||||
ptr, with the smallest swap so that the blocks are in the opposite order.
|
|
||||||
Blocks may be internally re-ordered e.g.
|
|
||||||
|
|
||||||
12345ab -> ab34512
|
|
||||||
123abc -> abc123
|
|
||||||
12abcde -> deabc12
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
sort_r_swap_blocks(char* ptr, size_t numBytesA, size_t numBytesB)
|
|
||||||
{
|
|
||||||
if (numBytesA > 0 && numBytesB > 0) {
|
|
||||||
if (numBytesA > numBytesB)
|
|
||||||
sort_r_swap(ptr, ptr + numBytesA, numBytesB);
|
|
||||||
else
|
|
||||||
sort_r_swap(ptr, ptr + numBytesB, numBytesA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Note: quicksort is not stable, equivalent values may be swapped */
|
|
||||||
static inline void
|
|
||||||
sort_r_simple(char* base, size_t numElements, size_t sizeOfElement,
|
|
||||||
_compare_function_qsort_r cmpFunc, void* cookie)
|
|
||||||
{
|
|
||||||
char* end = base + (numElements * sizeOfElement);
|
|
||||||
|
|
||||||
if (numElements < 10) {
|
|
||||||
// Insertion sort for arbitrarily small inputs
|
|
||||||
|
|
||||||
char* pivIndexA;
|
|
||||||
char* pivIndexB;
|
|
||||||
for (pivIndexA = base + sizeOfElement; pivIndexA < end;
|
|
||||||
pivIndexA += sizeOfElement) {
|
|
||||||
pivIndexB = pivIndexA;
|
|
||||||
while (pivIndexB > base
|
|
||||||
&& sort_r_cmpswap(pivIndexB - sizeOfElement , pivIndexB,
|
|
||||||
sizeOfElement, cmpFunc, cookie)) {
|
|
||||||
pivIndexB -= sizeOfElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Quicksort when numElements >= 10
|
|
||||||
|
|
||||||
int cmp;
|
|
||||||
char* nextPivCmpItem; // pl
|
|
||||||
char* nextPivEqualsPos; // ple
|
|
||||||
char* lastPivCmpItem; // pr
|
|
||||||
char* lastPivEqualsPos; // pre
|
|
||||||
char* pivot;
|
|
||||||
char* last = base + sizeOfElement * (numElements - 1);
|
|
||||||
char* tmp;
|
|
||||||
|
|
||||||
// Use median of second, middle and second-last items as pivot.
|
|
||||||
// First and last may have been swapped with pivot and therefore be
|
|
||||||
// extreme.
|
|
||||||
char* pivList[3];
|
|
||||||
pivList[0] = base + sizeOfElement;
|
|
||||||
pivList[1] = base + sizeOfElement * (numElements / 2);
|
|
||||||
pivList[2] = last - sizeOfElement;
|
|
||||||
|
|
||||||
if (cmpFunc(pivList[0], pivList[1], cookie) > 0)
|
|
||||||
SORT_R_SWAP(pivList[0], pivList[1], tmp);
|
|
||||||
if (cmpFunc(pivList[1], pivList[2], cookie) > 0) {
|
|
||||||
SORT_R_SWAP(pivList[1], pivList[2], tmp);
|
|
||||||
if (cmpFunc(pivList[0], pivList[1], cookie) > 0)
|
|
||||||
SORT_R_SWAP(pivList[0], pivList[1], tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap mid value (pivList[1]), and last element to put pivot as last
|
|
||||||
// element.
|
|
||||||
if (pivList[1] != last)
|
|
||||||
sort_r_swap(pivList[1], last, sizeOfElement);
|
|
||||||
|
|
||||||
// v- end (beyond the array)
|
|
||||||
// EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
|
|
||||||
// ^- base ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is)
|
|
||||||
|
|
||||||
// Pivot comparison key:
|
|
||||||
// E = equal, L = less than, u = unknown, G = greater than, E = equal
|
|
||||||
pivot = last;
|
|
||||||
nextPivEqualsPos = nextPivCmpItem = base;
|
|
||||||
lastPivEqualsPos = lastPivCmpItem = last;
|
|
||||||
|
|
||||||
// Strategy:
|
|
||||||
// Loop into the list from the left and right at the same time to find:
|
|
||||||
// - an item on the left that is greater than the pivot
|
|
||||||
// - an item on the right that is less than the pivot
|
|
||||||
// Once found, they are swapped and the loop continues.
|
|
||||||
// Meanwhile items that are equal to the pivot are moved to the edges
|
|
||||||
// of the array.
|
|
||||||
while (nextPivCmpItem < lastPivCmpItem) {
|
|
||||||
// Move left hand items which are equal to the pivot to the far
|
|
||||||
// left. Break when we find an item that is greater than the pivot.
|
|
||||||
for (; nextPivCmpItem < lastPivCmpItem;
|
|
||||||
nextPivCmpItem += sizeOfElement) {
|
|
||||||
cmp = cmpFunc(nextPivCmpItem, pivot, cookie);
|
|
||||||
if (cmp > 0)
|
|
||||||
break;
|
|
||||||
else if (cmp == 0) {
|
|
||||||
if (nextPivEqualsPos < nextPivCmpItem) {
|
|
||||||
sort_r_swap(nextPivEqualsPos, nextPivCmpItem,
|
|
||||||
sizeOfElement);
|
|
||||||
}
|
|
||||||
nextPivEqualsPos += sizeOfElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// break if last batch of left hand items were equal to pivot
|
|
||||||
if (nextPivCmpItem >= lastPivCmpItem)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Move right hand items which are equal to the pivot to the far
|
|
||||||
// right. Break when we find an item that is less than the pivot.
|
|
||||||
for (; nextPivCmpItem < lastPivCmpItem;) {
|
|
||||||
lastPivCmpItem -= sizeOfElement;
|
|
||||||
// Move right pointer onto an unprocessed item
|
|
||||||
cmp = cmpFunc(lastPivCmpItem, pivot, cookie);
|
|
||||||
if (cmp == 0) {
|
|
||||||
lastPivEqualsPos -= sizeOfElement;
|
|
||||||
if (lastPivCmpItem < lastPivEqualsPos) {
|
|
||||||
sort_r_swap(lastPivCmpItem, lastPivEqualsPos,
|
|
||||||
sizeOfElement);
|
|
||||||
}
|
|
||||||
} else if (cmp < 0) {
|
|
||||||
if (nextPivCmpItem < lastPivCmpItem) {
|
|
||||||
sort_r_swap(nextPivCmpItem, lastPivCmpItem,
|
|
||||||
sizeOfElement);
|
|
||||||
}
|
|
||||||
nextPivCmpItem += sizeOfElement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPivCmpItem = lastPivCmpItem;
|
|
||||||
// lastPivCmpItem may have gone below nextPivCmpItem
|
|
||||||
|
|
||||||
// Now we need to go from: EEELLLGGGGEEEE
|
|
||||||
// to: LLLEEEEEEEGGGG
|
|
||||||
|
|
||||||
// Pivot comparison key:
|
|
||||||
// E = equal, L = less than, u = unknown, G = greater than, E = equal
|
|
||||||
sort_r_swap_blocks(base, nextPivEqualsPos - base,
|
|
||||||
nextPivCmpItem - nextPivEqualsPos);
|
|
||||||
sort_r_swap_blocks(lastPivCmpItem, lastPivEqualsPos - lastPivCmpItem,
|
|
||||||
end - lastPivEqualsPos);
|
|
||||||
|
|
||||||
sort_r_simple(base, (nextPivCmpItem - nextPivEqualsPos) / sizeOfElement,
|
|
||||||
sizeOfElement, cmpFunc, cookie);
|
|
||||||
sort_r_simple(end - (lastPivEqualsPos - lastPivCmpItem),
|
|
||||||
(lastPivEqualsPos - lastPivCmpItem) / sizeOfElement, sizeOfElement,
|
|
||||||
cmpFunc, cookie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
qsort_r(void* base, size_t numElements, size_t sizeOfElement,
|
|
||||||
_compare_function_qsort_r cmpFunc, void* cookie)
|
|
||||||
{
|
|
||||||
sort_r_simple((char*)base, numElements, sizeOfElement,
|
|
||||||
cmpFunc, cookie);
|
|
||||||
}
|
|
||||||
@@ -26,6 +26,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
mktemp.c
|
mktemp.c
|
||||||
pty.cpp
|
pty.cpp
|
||||||
qsort.c
|
qsort.c
|
||||||
|
qsort_r.c
|
||||||
radixsort.c
|
radixsort.c
|
||||||
random.c
|
random.c
|
||||||
reallocarray.cpp
|
reallocarray.cpp
|
||||||
|
|||||||
@@ -29,16 +29,22 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
|
|
||||||
#endif /* LIBC_SCCS and not lint */
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define __unused
|
||||||
|
|
||||||
|
#if defined(I_AM_QSORT_R)
|
||||||
|
typedef int cmp_t(const void *, const void *, void *);
|
||||||
|
#elif defined(I_AM_QSORT_R_COMPAT)
|
||||||
|
typedef int cmp_t(void *, const void *, const void *);
|
||||||
|
#elif defined(I_AM_QSORT_S)
|
||||||
|
typedef int cmp_t(const void *, const void *, void *);
|
||||||
|
#else
|
||||||
typedef int cmp_t(const void *, const void *);
|
typedef int cmp_t(const void *, const void *);
|
||||||
|
#endif
|
||||||
static inline char *med3(char *, char *, char *, cmp_t *, void *);
|
static inline char *med3(char *, char *, char *, cmp_t *, void *);
|
||||||
|
|
||||||
#define MIN(a, b) ((a) < (b) ? a : b)
|
#define MIN(a, b) ((a) < (b) ? a : b)
|
||||||
@@ -62,20 +68,39 @@ swapfunc(char *a, char *b, size_t es)
|
|||||||
#define vecswap(a, b, n) \
|
#define vecswap(a, b, n) \
|
||||||
if ((n) > 0) swapfunc(a, b, n)
|
if ((n) > 0) swapfunc(a, b, n)
|
||||||
|
|
||||||
|
#if defined(I_AM_QSORT_R)
|
||||||
|
#define CMP(t, x, y) (cmp((x), (y), (t)))
|
||||||
|
#elif defined(I_AM_QSORT_R_COMPAT)
|
||||||
|
#define CMP(t, x, y) (cmp((t), (x), (y)))
|
||||||
|
#elif defined(I_AM_QSORT_S)
|
||||||
|
#define CMP(t, x, y) (cmp((x), (y), (t)))
|
||||||
|
#else
|
||||||
#define CMP(t, x, y) (cmp((x), (y)))
|
#define CMP(t, x, y) (cmp((x), (y)))
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline char *
|
static inline char *
|
||||||
med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk)
|
med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
|
||||||
|
#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) && !defined(I_AM_QSORT_S)
|
||||||
|
__unused
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return CMP(thunk, a, b) < 0 ?
|
return CMP(thunk, a, b) < 0 ?
|
||||||
(CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
|
(CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
|
||||||
:(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
|
:(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The actual qsort() implementation is static to avoid preemptible calls when
|
* The actual qsort() implementation is static to avoid preemptible calls when
|
||||||
* recursing. Also give them different names for improved debugging.
|
* recursing. Also give them different names for improved debugging.
|
||||||
*/
|
*/
|
||||||
|
#if defined(I_AM_QSORT_R)
|
||||||
|
#define local_qsort local_qsort_r
|
||||||
|
#elif defined(I_AM_QSORT_R_COMPAT)
|
||||||
|
#define local_qsort local_qsort_r_compat
|
||||||
|
#elif defined(I_AM_QSORT_S)
|
||||||
|
#define local_qsort local_qsort_s
|
||||||
|
#endif
|
||||||
static void
|
static void
|
||||||
local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
|
local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
|
||||||
{
|
{
|
||||||
@@ -92,8 +117,8 @@ loop:
|
|||||||
if (n < 7) {
|
if (n < 7) {
|
||||||
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
||||||
for (pl = pm;
|
for (pl = pm;
|
||||||
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
|
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
|
||||||
pl -= es)
|
pl -= es)
|
||||||
swapfunc(pl, pl - es, es);
|
swapfunc(pl, pl - es, es);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -141,8 +166,8 @@ loop:
|
|||||||
if (swap_cnt == 0) { /* Switch to insertion sort */
|
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||||
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
||||||
for (pl = pm;
|
for (pl = pm;
|
||||||
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
|
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
|
||||||
pl -= es)
|
pl -= es)
|
||||||
swapfunc(pl, pl - es, es);
|
swapfunc(pl, pl - es, es);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -186,8 +211,52 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(I_AM_QSORT_R)
|
||||||
|
void
|
||||||
|
(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
|
||||||
|
{
|
||||||
|
local_qsort_r(a, n, es, cmp, thunk);
|
||||||
|
}
|
||||||
|
#elif defined(I_AM_QSORT_R_COMPAT)
|
||||||
|
void
|
||||||
|
__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
|
||||||
|
{
|
||||||
|
local_qsort_r_compat(a, n, es, cmp, thunk);
|
||||||
|
}
|
||||||
|
#elif defined(I_AM_QSORT_S)
|
||||||
|
errno_t
|
||||||
|
qsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk)
|
||||||
|
{
|
||||||
|
if (n > RSIZE_MAX) {
|
||||||
|
__throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL);
|
||||||
|
return (EINVAL);
|
||||||
|
} else if (es > RSIZE_MAX) {
|
||||||
|
__throw_constraint_handler_s("qsort_s : es > RSIZE_MAX",
|
||||||
|
EINVAL);
|
||||||
|
return (EINVAL);
|
||||||
|
} else if (n != 0) {
|
||||||
|
if (a == NULL) {
|
||||||
|
__throw_constraint_handler_s("qsort_s : a == NULL",
|
||||||
|
EINVAL);
|
||||||
|
return (EINVAL);
|
||||||
|
} else if (cmp == NULL) {
|
||||||
|
__throw_constraint_handler_s("qsort_s : cmp == NULL",
|
||||||
|
EINVAL);
|
||||||
|
return (EINVAL);
|
||||||
|
} else if (es <= 0) {
|
||||||
|
__throw_constraint_handler_s("qsort_s : es <= 0",
|
||||||
|
EINVAL);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local_qsort_s(a, n, es, cmp, thunk);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
void
|
void
|
||||||
qsort(void *a, size_t n, size_t es, cmp_t *cmp)
|
qsort(void *a, size_t n, size_t es, cmp_t *cmp)
|
||||||
{
|
{
|
||||||
local_qsort(a, n, es, cmp, NULL);
|
local_qsort(a, n, es, cmp, NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* This file is in the public domain. Originally written by Garrett
|
||||||
|
* A. Wollman.
|
||||||
|
*/
|
||||||
|
#define I_AM_QSORT_R
|
||||||
|
#include "qsort.c"
|
||||||
Reference in New Issue
Block a user