mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-28 20:11:00 +01:00
Add support for some block functions that come from OS X. These are
intended to build with any C compiler. Reviewed by: pfg MFC after: 3 weeks
This commit is contained in:
parent
cfc4b56b57
commit
46cdc14062
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264042
@ -95,6 +95,11 @@ void rewinddir(DIR *);
|
||||
int scandir(const char *, struct dirent ***,
|
||||
int (*)(const struct dirent *), int (*)(const struct dirent **,
|
||||
const struct dirent **));
|
||||
#ifdef __BLOCKS__
|
||||
int scandir_b(const char *, struct dirent ***,
|
||||
int (^)(const struct dirent *),
|
||||
int (^)(const struct dirent **, const struct dirent **));
|
||||
#endif
|
||||
#endif
|
||||
#if __XSI_VISIBLE
|
||||
void seekdir(DIR *, long);
|
||||
|
@ -82,6 +82,9 @@ extern int ___mb_cur_max(void);
|
||||
_Noreturn void abort(void);
|
||||
int abs(int) __pure2;
|
||||
int atexit(void (*)(void));
|
||||
#ifdef __BLOCKS__
|
||||
int atexit_b(void (^)(void));
|
||||
#endif
|
||||
double atof(const char *);
|
||||
int atoi(const char *);
|
||||
long atol(const char *);
|
||||
@ -100,6 +103,10 @@ size_t mbstowcs(wchar_t * __restrict , const char * __restrict, size_t);
|
||||
int mbtowc(wchar_t * __restrict, const char * __restrict, size_t);
|
||||
void qsort(void *, size_t, size_t,
|
||||
int (*)(const void *, const void *));
|
||||
#ifdef __BLOCKS__
|
||||
void qsort_b(void *, size_t, size_t,
|
||||
int (^)(const void *, const void *));
|
||||
#endif
|
||||
int rand(void);
|
||||
void *realloc(void *, size_t);
|
||||
void srand(unsigned);
|
||||
@ -280,8 +287,14 @@ const char *
|
||||
getprogname(void);
|
||||
|
||||
int heapsort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
#ifdef __BLOCKS__
|
||||
int heapsort_b(void *, size_t, size_t, int (^)(const void *, const void *));
|
||||
#endif
|
||||
int l64a_r(long, char *, int);
|
||||
int mergesort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
#ifdef __BLOCKS__
|
||||
int mergesort_b(void *, size_t, size_t, int (^)(const void *, const void *));
|
||||
#endif
|
||||
int mkostemp(char *, int);
|
||||
int mkostemps(char *, int, int);
|
||||
void qsort_r(void *, size_t, size_t, void *,
|
||||
|
@ -349,6 +349,7 @@ FBSD_1.1 {
|
||||
posix_spawnattr_setsigdefault;
|
||||
posix_spawnattr_setsigmask;
|
||||
posix_spawnp;
|
||||
scandir_b;
|
||||
semctl;
|
||||
tcgetsid;
|
||||
tcsetsid;
|
||||
|
@ -42,6 +42,8 @@
|
||||
.Ft int
|
||||
.Fn scandir "const char *dirname" "struct dirent ***namelist" "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp" "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||
.Ft int
|
||||
.Fn scandir_b "const char *dirname" "struct dirent ***namelist" "int \*(lp*select\^(rp\*(lpconst struct dirent *\*(rp" "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
|
||||
.Ft int
|
||||
.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
@ -87,6 +89,15 @@ argument to sort the array alphabetically using
|
||||
The memory allocated for the array can be deallocated with
|
||||
.Xr free 3 ,
|
||||
by freeing each pointer in the array and then the array itself.
|
||||
.Pp
|
||||
The
|
||||
.Fn scandir_b
|
||||
function behaves in the same way as
|
||||
.Fn scandir ,
|
||||
but takes blocks as arguments instead of function pointers and calls
|
||||
.Fn qsort_b
|
||||
rather than
|
||||
.Fn qsort .
|
||||
.Sh DIAGNOSTICS
|
||||
Returns \-1 if the directory cannot be opened for reading or if
|
||||
.Xr malloc 3
|
||||
|
@ -46,6 +46,17 @@ __FBSDID("$FreeBSD$");
|
||||
#include <string.h>
|
||||
#include "un-namespace.h"
|
||||
|
||||
#ifdef I_AM_SCANDIR_B
|
||||
#include "block_abi.h"
|
||||
#define SELECT(x) CALL_BLOCK(select, x)
|
||||
#ifndef __BLOCKS__
|
||||
void
|
||||
qsort_b(void *, size_t, size_t, void*);
|
||||
#endif
|
||||
#else
|
||||
#define SELECT(x) select(x)
|
||||
#endif
|
||||
|
||||
static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
|
||||
|
||||
/*
|
||||
@ -60,9 +71,15 @@ static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
|
||||
(((dp)->d_namlen + 1 + 3) &~ 3))
|
||||
|
||||
int
|
||||
#ifdef I_AM_SCANDIR_B
|
||||
scandir_b(const char *dirname, struct dirent ***namelist,
|
||||
DECLARE_BLOCK(int, select, const struct dirent *),
|
||||
DECLARE_BLOCK(int, dcomp, const struct dirent **, const struct dirent **))
|
||||
#else
|
||||
scandir(const char *dirname, struct dirent ***namelist,
|
||||
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
|
||||
const struct dirent **))
|
||||
#endif
|
||||
{
|
||||
struct dirent *d, *p, **names = NULL;
|
||||
size_t nitems = 0;
|
||||
@ -78,7 +95,7 @@ scandir(const char *dirname, struct dirent ***namelist,
|
||||
goto fail;
|
||||
|
||||
while ((d = readdir(dirp)) != NULL) {
|
||||
if (select != NULL && !(*select)(d))
|
||||
if (select != NULL && !SELECT(d))
|
||||
continue; /* just selected names */
|
||||
/*
|
||||
* Make a minimum size copy of the data
|
||||
@ -111,8 +128,12 @@ scandir(const char *dirname, struct dirent ***namelist,
|
||||
}
|
||||
closedir(dirp);
|
||||
if (nitems && dcomp != NULL)
|
||||
#ifdef I_AM_SCANDIR_B
|
||||
qsort_b(names, nitems, sizeof(struct dirent *), (void*)dcomp);
|
||||
#else
|
||||
qsort_r(names, nitems, sizeof(struct dirent *),
|
||||
&dcomp, alphasort_thunk);
|
||||
#endif
|
||||
*namelist = names;
|
||||
return (nitems);
|
||||
|
||||
|
29
lib/libc/gen/scandir_b.c
Normal file
29
lib/libc/gen/scandir_b.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 David Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#define I_AM_SCANDIR_B
|
||||
#include "scandir.c"
|
63
lib/libc/include/block_abi.h
Normal file
63
lib/libc/include/block_abi.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 David T Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __BLOCKS__
|
||||
/**
|
||||
* Declares a block variable. This macro is defined in the trivial way for
|
||||
* compilers that support blocks and exposing the ABI in the source for other
|
||||
* compilers.
|
||||
*/
|
||||
#define DECLARE_BLOCK(retTy, name, argTys, ...)\
|
||||
retTy(^name)(argTys, ## __VA_ARGS__)
|
||||
/**
|
||||
* Calls a block variable. This macro is defined in the trivial way for
|
||||
* compilers that support blocks and exposing the ABI in the source for other
|
||||
* compilers.
|
||||
*/
|
||||
#define CALL_BLOCK(name, ...) name(__VA_ARGS__)
|
||||
#else // !__BLOCKS__
|
||||
#define DECLARE_BLOCK(retTy, name, argTys, ...)\
|
||||
struct {\
|
||||
void *isa;\
|
||||
int flags;\
|
||||
int reserved;\
|
||||
retTy (*invoke)(void *, ...);\
|
||||
} *name
|
||||
#define CALL_BLOCK(name, ...) (name)->invoke(name, __VA_ARGS__)
|
||||
#endif // __BLOCKS__
|
||||
/**
|
||||
* Returns the pointer to the block-invoke function. This is used for passing
|
||||
* blocks to functions that want a function pointer and a data pointer.
|
||||
*/
|
||||
#define GET_BLOCK_FUNCTION(x) \
|
||||
(((struct {\
|
||||
void *isa;\
|
||||
int flags;\
|
||||
int reserved;\
|
||||
void (*invoke)(void *, ...);\
|
||||
}*)x)->invoke)
|
@ -6,9 +6,10 @@
|
||||
|
||||
MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
|
||||
bsearch.c div.c exit.c getenv.c getopt.c getopt_long.c \
|
||||
getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
|
||||
getsubopt.c hcreate.c heapsort.c heapsort_b.c imaxabs.c imaxdiv.c \
|
||||
insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
|
||||
merge.c ptsname.c qsort.c qsort_r.c quick_exit.c radixsort.c rand.c \
|
||||
merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c quick_exit.c \
|
||||
radixsort.c rand.c \
|
||||
random.c reallocf.c realpath.c remque.c strfmon.c strtoimax.c \
|
||||
strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
|
||||
strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
|
||||
|
@ -86,10 +86,14 @@ FBSD_1.0 {
|
||||
|
||||
FBSD_1.3 {
|
||||
at_quick_exit;
|
||||
atexit_b;
|
||||
atof_l;
|
||||
atoi_l;
|
||||
atol_l;
|
||||
atoll_l;
|
||||
heapsort_b;
|
||||
mergesort_b;
|
||||
qsort_b;
|
||||
quick_exit;
|
||||
strtod_l;
|
||||
strtof_l;
|
||||
|
@ -44,6 +44,8 @@
|
||||
.In stdlib.h
|
||||
.Ft int
|
||||
.Fn atexit "void (*function)(void)"
|
||||
.Ft int
|
||||
.Fn atexit_b "void (^function)(void)"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn atexit
|
||||
@ -69,6 +71,12 @@ process termination, for example by calling
|
||||
.Pp
|
||||
At least 32 functions can always be registered,
|
||||
and more are allowed as long as sufficient memory can be allocated.
|
||||
.Pp
|
||||
The
|
||||
.Fn atexit_b
|
||||
function behaves identically to
|
||||
.Fn atexit ,
|
||||
except that it takes a block, rather than a function pointer.
|
||||
.\" XXX {ATEXIT_MAX} is not implemented yet
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std atexit
|
||||
@ -77,6 +85,12 @@ and more are allowed as long as sufficient memory can be allocated.
|
||||
.It Bq Er ENOMEM
|
||||
No memory was available to add the function to the list.
|
||||
The existing list of functions is unmodified.
|
||||
.It Bq Er ENOSYS
|
||||
The
|
||||
.Fn atexit_b
|
||||
function was called by a program that did not supply a
|
||||
.Fn _Block_copy
|
||||
implementation.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr at_quick_exit 3
|
||||
|
@ -37,6 +37,7 @@ static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94";
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "namespace.h"
|
||||
#include <errno.h>
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
@ -44,9 +45,16 @@ __FBSDID("$FreeBSD$");
|
||||
#include <pthread.h>
|
||||
#include "atexit.h"
|
||||
#include "un-namespace.h"
|
||||
#include "block_abi.h"
|
||||
|
||||
#include "libc_private.h"
|
||||
|
||||
/**
|
||||
* The _Block_copy() function is provided by the block runtime.
|
||||
*/
|
||||
__attribute__((weak)) void*
|
||||
_Block_copy(void*);
|
||||
|
||||
#define ATEXIT_FN_EMPTY 0
|
||||
#define ATEXIT_FN_STD 1
|
||||
#define ATEXIT_FN_CXA 2
|
||||
@ -125,7 +133,32 @@ atexit(void (*func)(void))
|
||||
fn.fn_arg = NULL;
|
||||
fn.fn_dso = NULL;
|
||||
|
||||
error = atexit_register(&fn);
|
||||
error = atexit_register(&fn);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a block to be performed at exit.
|
||||
*/
|
||||
int
|
||||
atexit_b(DECLARE_BLOCK(void, func, void))
|
||||
{
|
||||
struct atexit_fn fn;
|
||||
int error;
|
||||
if (_Block_copy == 0) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
func = _Block_copy(func);
|
||||
|
||||
// Blocks are not C++ destructors, but they have the same signature (a
|
||||
// single void* parameter), so we can pretend that they are.
|
||||
fn.fn_type = ATEXIT_FN_CXA;
|
||||
fn.fn_ptr.cxa_func = (void(*)(void*))GET_BLOCK_FUNCTION(func);
|
||||
fn.fn_arg = func;
|
||||
fn.fn_dso = NULL;
|
||||
|
||||
error = atexit_register(&fn);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -144,7 +177,7 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso)
|
||||
fn.fn_arg = arg;
|
||||
fn.fn_dso = dso;
|
||||
|
||||
error = atexit_register(&fn);
|
||||
error = atexit_register(&fn);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef I_AM_BSEARCH_B
|
||||
#include "block_abi.h"
|
||||
#define COMPAR(x,y) CALL_BLOCK(compar, x, y)
|
||||
#else
|
||||
#define COMPAR(x,y) compar(x, y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Perform a binary search.
|
||||
*
|
||||
@ -52,6 +59,15 @@ __FBSDID("$FreeBSD$");
|
||||
* have to make lim 3, then halve, obtaining 1, so that we will only
|
||||
* look at item 3.
|
||||
*/
|
||||
#ifdef I_AM_BSEARCH_B
|
||||
void *
|
||||
bsearch_b(key, base0, nmemb, size, compar)
|
||||
const void *key;
|
||||
const void *base0;
|
||||
size_t nmemb;
|
||||
size_t size;
|
||||
DECLARE_BLOCK(int, compar, const void *, const void *);
|
||||
#else
|
||||
void *
|
||||
bsearch(key, base0, nmemb, size, compar)
|
||||
const void *key;
|
||||
@ -59,6 +75,7 @@ bsearch(key, base0, nmemb, size, compar)
|
||||
size_t nmemb;
|
||||
size_t size;
|
||||
int (*compar)(const void *, const void *);
|
||||
#endif
|
||||
{
|
||||
const char *base = base0;
|
||||
size_t lim;
|
||||
@ -67,7 +84,7 @@ bsearch(key, base0, nmemb, size, compar)
|
||||
|
||||
for (lim = nmemb; lim != 0; lim >>= 1) {
|
||||
p = base + (lim >> 1) * size;
|
||||
cmp = (*compar)(key, p);
|
||||
cmp = COMPAR(key, p);
|
||||
if (cmp == 0)
|
||||
return ((void *)p);
|
||||
if (cmp > 0) { /* key > p: move right */
|
||||
|
29
lib/libc/stdlib/bsearch_b.c
Normal file
29
lib/libc/stdlib/bsearch_b.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 David Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#define I_AM_BSEARCH_B
|
||||
#include "bsearch.c"
|
@ -1,6 +1,8 @@
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2014 David T. Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
|
||||
@ -40,6 +42,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef I_AM_HEAPSORT_B
|
||||
#include "block_abi.h"
|
||||
#define COMPAR(x, y) CALL_BLOCK(compar, x, y)
|
||||
#else
|
||||
#define COMPAR(x, y) compar(x, y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Swap two areas of size number of bytes. Although qsort(3) permits random
|
||||
* blocks of memory to be sorted, sorting pointers is almost certainly the
|
||||
@ -77,12 +86,12 @@ __FBSDID("$FreeBSD$");
|
||||
for (par_i = initval; (child_i = par_i * 2) <= nmemb; \
|
||||
par_i = child_i) { \
|
||||
child = base + child_i * size; \
|
||||
if (child_i < nmemb && compar(child, child + size) < 0) { \
|
||||
if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
|
||||
child += size; \
|
||||
++child_i; \
|
||||
} \
|
||||
par = base + par_i * size; \
|
||||
if (compar(child, par) <= 0) \
|
||||
if (COMPAR(child, par) <= 0) \
|
||||
break; \
|
||||
SWAP(par, child, count, size, tmp); \
|
||||
} \
|
||||
@ -108,7 +117,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \
|
||||
for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \
|
||||
child = base + child_i * size; \
|
||||
if (child_i < nmemb && compar(child, child + size) < 0) { \
|
||||
if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
|
||||
child += size; \
|
||||
++child_i; \
|
||||
} \
|
||||
@ -120,7 +129,7 @@ __FBSDID("$FreeBSD$");
|
||||
par_i = child_i / 2; \
|
||||
child = base + child_i * size; \
|
||||
par = base + par_i * size; \
|
||||
if (child_i == 1 || compar(k, par) < 0) { \
|
||||
if (child_i == 1 || COMPAR(k, par) < 0) { \
|
||||
COPY(child, k, count, size, tmp1, tmp2); \
|
||||
break; \
|
||||
} \
|
||||
@ -135,11 +144,19 @@ __FBSDID("$FreeBSD$");
|
||||
* a data set that will trigger the worst case is nonexistent. Heapsort's
|
||||
* only advantage over quicksort is that it requires little additional memory.
|
||||
*/
|
||||
#ifdef I_AM_HEAPSORT_B
|
||||
int
|
||||
heapsort_b(vbase, nmemb, size, compar)
|
||||
void *vbase;
|
||||
size_t nmemb, size;
|
||||
DECLARE_BLOCK(int, compar, const void *, const void *);
|
||||
#else
|
||||
int
|
||||
heapsort(vbase, nmemb, size, compar)
|
||||
void *vbase;
|
||||
size_t nmemb, size;
|
||||
int (*compar)(const void *, const void *);
|
||||
#endif
|
||||
{
|
||||
size_t cnt, i, j, l;
|
||||
char tmp, *tmp1, *tmp2;
|
||||
|
29
lib/libc/stdlib/heapsort_b.c
Normal file
29
lib/libc/stdlib/heapsort_b.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 David Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#define I_AM_HEAPSORT_B
|
||||
#include "heapsort.c"
|
@ -56,10 +56,18 @@ __FBSDID("$FreeBSD$");
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void setup(u_char *, u_char *, size_t, size_t,
|
||||
int (*)(const void *, const void *));
|
||||
static void insertionsort(u_char *, size_t, size_t,
|
||||
int (*)(const void *, const void *));
|
||||
#ifdef I_AM_MERGESORT_B
|
||||
#include "block_abi.h"
|
||||
#define DECLARE_CMP DECLARE_BLOCK(int, cmp, const void *, const void *)
|
||||
typedef DECLARE_BLOCK(int, cmp_t, const void *, const void *);
|
||||
#define CMP(x, y) CALL_BLOCK(cmp, x, y)
|
||||
#else
|
||||
typedef int (*cmp_t)(const void *, const void *);
|
||||
#define CMP(x, y) cmp(x, y)
|
||||
#endif
|
||||
|
||||
static void setup(u_char *, u_char *, size_t, size_t, cmp_t);
|
||||
static void insertionsort(u_char *, size_t, size_t, cmp_t);
|
||||
|
||||
#define ISIZE sizeof(int)
|
||||
#define PSIZE sizeof(u_char *)
|
||||
@ -95,11 +103,15 @@ static void insertionsort(u_char *, size_t, size_t,
|
||||
* Arguments are as for qsort.
|
||||
*/
|
||||
int
|
||||
#ifdef I_AM_MERGESORT_B
|
||||
mergesort_b(base, nmemb, size, cmp)
|
||||
#else
|
||||
mergesort(base, nmemb, size, cmp)
|
||||
#endif
|
||||
void *base;
|
||||
size_t nmemb;
|
||||
size_t size;
|
||||
int (*cmp)(const void *, const void *);
|
||||
cmp_t cmp;
|
||||
{
|
||||
size_t i;
|
||||
int sense;
|
||||
@ -141,7 +153,7 @@ mergesort(base, nmemb, size, cmp)
|
||||
p2 = *EVAL(p2);
|
||||
l2 = list1 + (p2 - list2);
|
||||
while (f1 < l1 && f2 < l2) {
|
||||
if ((*cmp)(f1, f2) <= 0) {
|
||||
if (CMP(f1, f2) <= 0) {
|
||||
q = f2;
|
||||
b = f1, t = l1;
|
||||
sense = -1;
|
||||
@ -151,7 +163,7 @@ mergesort(base, nmemb, size, cmp)
|
||||
sense = 0;
|
||||
}
|
||||
if (!big) { /* here i = 0 */
|
||||
while ((b += size) < t && cmp(q, b) >sense)
|
||||
while ((b += size) < t && CMP(q, b) >sense)
|
||||
if (++i == 6) {
|
||||
big = 1;
|
||||
goto EXPONENTIAL;
|
||||
@ -160,12 +172,12 @@ mergesort(base, nmemb, size, cmp)
|
||||
EXPONENTIAL: for (i = size; ; i <<= 1)
|
||||
if ((p = (b + i)) >= t) {
|
||||
if ((p = t - size) > b &&
|
||||
(*cmp)(q, p) <= sense)
|
||||
CMP(q, p) <= sense)
|
||||
t = p;
|
||||
else
|
||||
b = p;
|
||||
break;
|
||||
} else if ((*cmp)(q, p) <= sense) {
|
||||
} else if (CMP(q, p) <= sense) {
|
||||
t = p;
|
||||
if (i == size)
|
||||
big = 0;
|
||||
@ -174,14 +186,14 @@ EXPONENTIAL: for (i = size; ; i <<= 1)
|
||||
b = p;
|
||||
while (t > b+size) {
|
||||
i = (((t - b) / size) >> 1) * size;
|
||||
if ((*cmp)(q, p = b + i) <= sense)
|
||||
if (CMP(q, p = b + i) <= sense)
|
||||
t = p;
|
||||
else
|
||||
b = p;
|
||||
}
|
||||
goto COPY;
|
||||
FASTCASE: while (i > size)
|
||||
if ((*cmp)(q,
|
||||
if (CMP(q,
|
||||
p = b + (i >>= 1)) <= sense)
|
||||
t = p;
|
||||
else
|
||||
@ -261,8 +273,8 @@ COPY: b = t;
|
||||
void
|
||||
setup(list1, list2, n, size, cmp)
|
||||
size_t n, size;
|
||||
int (*cmp)(const void *, const void *);
|
||||
u_char *list1, *list2;
|
||||
cmp_t cmp;
|
||||
{
|
||||
int i, length, size2, tmp, sense;
|
||||
u_char *f1, *f2, *s, *l2, *last, *p2;
|
||||
@ -285,12 +297,12 @@ setup(list1, list2, n, size, cmp)
|
||||
#ifdef NATURAL
|
||||
p2 = list2;
|
||||
f1 = list1;
|
||||
sense = (cmp(f1, f1 + size) > 0);
|
||||
sense = (CMP(f1, f1 + size) > 0);
|
||||
for (; f1 < last; sense = !sense) {
|
||||
length = 2;
|
||||
/* Find pairs with same sense. */
|
||||
for (f2 = f1 + size2; f2 < last; f2 += size2) {
|
||||
if ((cmp(f2, f2+ size) > 0) != sense)
|
||||
if ((CMP(f2, f2+ size) > 0) != sense)
|
||||
break;
|
||||
length += 2;
|
||||
}
|
||||
@ -303,7 +315,7 @@ setup(list1, list2, n, size, cmp)
|
||||
} else { /* Natural merge */
|
||||
l2 = f2;
|
||||
for (f2 = f1 + size2; f2 < l2; f2 += size2) {
|
||||
if ((cmp(f2-size, f2) > 0) != sense) {
|
||||
if ((CMP(f2-size, f2) > 0) != sense) {
|
||||
p2 = *EVAL(p2) = f2 - list1 + list2;
|
||||
if (sense > 0)
|
||||
reverse(f1, f2-size);
|
||||
@ -313,7 +325,7 @@ setup(list1, list2, n, size, cmp)
|
||||
if (sense > 0)
|
||||
reverse (f1, f2-size);
|
||||
f1 = f2;
|
||||
if (f2 < last || cmp(f2 - size, f2) > 0)
|
||||
if (f2 < last || CMP(f2 - size, f2) > 0)
|
||||
p2 = *EVAL(p2) = f2 - list1 + list2;
|
||||
else
|
||||
p2 = *EVAL(p2) = list2 + n*size;
|
||||
@ -322,7 +334,7 @@ setup(list1, list2, n, size, cmp)
|
||||
#else /* pairwise merge only. */
|
||||
for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
|
||||
p2 = *EVAL(p2) = p2 + size2;
|
||||
if (cmp (f1, f1 + size) > 0)
|
||||
if (CMP (f1, f1 + size) > 0)
|
||||
swap(f1, f1 + size);
|
||||
}
|
||||
#endif /* NATURAL */
|
||||
@ -336,7 +348,7 @@ static void
|
||||
insertionsort(a, n, size, cmp)
|
||||
u_char *a;
|
||||
size_t n, size;
|
||||
int (*cmp)(const void *, const void *);
|
||||
cmp_t cmp;
|
||||
{
|
||||
u_char *ai, *s, *t, *u, tmp;
|
||||
int i;
|
||||
@ -344,7 +356,7 @@ insertionsort(a, n, size, cmp)
|
||||
for (ai = a+size; --n >= 1; ai += size)
|
||||
for (t = ai; t > a; t -= size) {
|
||||
u = t - size;
|
||||
if (cmp(u, t) <= 0)
|
||||
if (CMP(u, t) <= 0)
|
||||
break;
|
||||
swap(u, t);
|
||||
}
|
||||
|
29
lib/libc/stdlib/mergesort_b.c
Normal file
29
lib/libc/stdlib/mergesort_b.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 David Chisnall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#define I_AM_MERGESORT_B
|
||||
#include "merge.c"
|
@ -36,7 +36,7 @@
|
||||
.Dt QSORT 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm qsort , qsort_r , heapsort , mergesort
|
||||
.Nm qsort , qsort_b , qsort_r , heapsort , heapsort_b , mergesort, mergesort_b
|
||||
.Nd sort functions
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
@ -50,6 +50,13 @@
|
||||
.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo qsort_b
|
||||
.Fa "void *base"
|
||||
.Fa "size_t nmemb"
|
||||
.Fa "size_t size"
|
||||
.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo qsort_r
|
||||
.Fa "void *base"
|
||||
.Fa "size_t nmemb"
|
||||
@ -65,12 +72,26 @@
|
||||
.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo heapsort_b
|
||||
.Fa "void *base"
|
||||
.Fa "size_t nmemb"
|
||||
.Fa "size_t size"
|
||||
.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo mergesort
|
||||
.Fa "void *base"
|
||||
.Fa "size_t nmemb"
|
||||
.Fa "size_t size"
|
||||
.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo mergesort_b
|
||||
.Fa "void *base"
|
||||
.Fa "size_t nmemb"
|
||||
.Fa "size_t size"
|
||||
.Fa "int \*[lp]^compar\*[rp]\*[lp]const void *, const void *\*[rp]"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn qsort
|
||||
@ -127,6 +148,11 @@ This allows the comparison function to access additional
|
||||
data without using global variables, and thus
|
||||
.Fn qsort_r
|
||||
is suitable for use in functions which must be reentrant.
|
||||
The
|
||||
.Fn qsort_b
|
||||
function behaves identically to
|
||||
.Fn qsort ,
|
||||
except that it takes a block, rather than a function pointer.
|
||||
.Pp
|
||||
The algorithms implemented by
|
||||
.Fn qsort ,
|
||||
@ -138,8 +164,18 @@ are
|
||||
stable, that is, if two members compare as equal, their order in
|
||||
the sorted array is undefined.
|
||||
The
|
||||
.Fn heapsort_b
|
||||
function behaves identically to
|
||||
.Fn heapsort ,
|
||||
except that it takes a block, rather than a function pointer.
|
||||
The
|
||||
.Fn mergesort
|
||||
algorithm is stable.
|
||||
The
|
||||
.Fn mergesort_b
|
||||
function behaves identically to
|
||||
.Fn mergesort ,
|
||||
except that it takes a block, rather than a function pointer.
|
||||
.Pp
|
||||
The
|
||||
.Fn qsort
|
||||
@ -324,3 +360,7 @@ The
|
||||
function
|
||||
conforms to
|
||||
.St -isoC .
|
||||
.Sh HISTORY
|
||||
The variants of these functions that take blocks as arguments first appeared in
|
||||
Mac OS X.
|
||||
This implementation was created by David Chisnall.
|
||||
|
@ -4,5 +4,15 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "block_abi.h"
|
||||
#define I_AM_QSORT_R
|
||||
#include "qsort.c"
|
||||
|
||||
void
|
||||
qsort_b(void *base, size_t nel, size_t width,
|
||||
DECLARE_BLOCK(int, compar, const void *, const void *))
|
||||
{
|
||||
qsort_r(base, nel, width, compar,
|
||||
(int (*)(void *, const void *, const void *))
|
||||
GET_BLOCK_FUNCTION(compar));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user