summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortheraven <theraven@FreeBSD.org>2014-04-02 16:07:48 +0000
committertheraven <theraven@FreeBSD.org>2014-04-02 16:07:48 +0000
commit0127b103f27578fc7f9cc3389b299f221deb1d4c (patch)
tree6b79951e49825ea224053fd3b29a53481afa5e00
parent2b2f1d5e5ca561f2d22a5740eb522aba203a4bd9 (diff)
downloadFreeBSD-src-0127b103f27578fc7f9cc3389b299f221deb1d4c.zip
FreeBSD-src-0127b103f27578fc7f9cc3389b299f221deb1d4c.tar.gz
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
-rw-r--r--include/dirent.h5
-rw-r--r--include/stdlib.h13
-rw-r--r--lib/libc/gen/Symbol.map1
-rw-r--r--lib/libc/gen/scandir.311
-rw-r--r--lib/libc/gen/scandir.c23
-rw-r--r--lib/libc/gen/scandir_b.c29
-rw-r--r--lib/libc/include/block_abi.h63
-rw-r--r--lib/libc/stdlib/Makefile.inc5
-rw-r--r--lib/libc/stdlib/Symbol.map4
-rw-r--r--lib/libc/stdlib/atexit.314
-rw-r--r--lib/libc/stdlib/atexit.c37
-rw-r--r--lib/libc/stdlib/bsearch.c19
-rw-r--r--lib/libc/stdlib/bsearch_b.c29
-rw-r--r--lib/libc/stdlib/heapsort.c25
-rw-r--r--lib/libc/stdlib/heapsort_b.c29
-rw-r--r--lib/libc/stdlib/merge.c50
-rw-r--r--lib/libc/stdlib/mergesort_b.c29
-rw-r--r--lib/libc/stdlib/qsort.342
-rw-r--r--lib/libc/stdlib/qsort_r.c10
19 files changed, 408 insertions, 30 deletions
diff --git a/include/dirent.h b/include/dirent.h
index d0b0a9a..f43210c 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -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);
diff --git a/include/stdlib.h b/include/stdlib.h
index 3ed07f3..4aa372b 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -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 *,
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 5885420..ff5162a 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -349,6 +349,7 @@ FBSD_1.1 {
posix_spawnattr_setsigdefault;
posix_spawnattr_setsigmask;
posix_spawnp;
+ scandir_b;
semctl;
tcgetsid;
tcsetsid;
diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3
index b3e0a7e..eaba754 100644
--- a/lib/libc/gen/scandir.3
+++ b/lib/libc/gen/scandir.3
@@ -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
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index 93bc852..d81acc8 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -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);
diff --git a/lib/libc/gen/scandir_b.c b/lib/libc/gen/scandir_b.c
new file mode 100644
index 0000000..6310a91
--- /dev/null
+++ b/lib/libc/gen/scandir_b.c
@@ -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"
diff --git a/lib/libc/include/block_abi.h b/lib/libc/include/block_abi.h
new file mode 100644
index 0000000..7d1e728
--- /dev/null
+++ b/lib/libc/include/block_abi.h
@@ -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)
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index b1a5ff0..68dda94 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -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
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 6a1798f..9734b49 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -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;
diff --git a/lib/libc/stdlib/atexit.3 b/lib/libc/stdlib/atexit.3
index d6dab56..68f4e8f 100644
--- a/lib/libc/stdlib/atexit.3
+++ b/lib/libc/stdlib/atexit.3
@@ -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
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index 01d09fe..43b6aa1 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -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);
}
diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c
index 4bcaaf3..4a1dd52 100644
--- a/lib/libc/stdlib/bsearch.c
+++ b/lib/libc/stdlib/bsearch.c
@@ -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 */
diff --git a/lib/libc/stdlib/bsearch_b.c b/lib/libc/stdlib/bsearch_b.c
new file mode 100644
index 0000000..393feba
--- /dev/null
+++ b/lib/libc/stdlib/bsearch_b.c
@@ -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"
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
index 4bad8a7..9286d6d 100644
--- a/lib/libc/stdlib/heapsort.c
+++ b/lib/libc/stdlib/heapsort.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;
diff --git a/lib/libc/stdlib/heapsort_b.c b/lib/libc/stdlib/heapsort_b.c
new file mode 100644
index 0000000..b1814bc
--- /dev/null
+++ b/lib/libc/stdlib/heapsort_b.c
@@ -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"
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
index 01a9028..6b368c3 100644
--- a/lib/libc/stdlib/merge.c
+++ b/lib/libc/stdlib/merge.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);
}
diff --git a/lib/libc/stdlib/mergesort_b.c b/lib/libc/stdlib/mergesort_b.c
new file mode 100644
index 0000000..acf5987
--- /dev/null
+++ b/lib/libc/stdlib/mergesort_b.c
@@ -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"
diff --git a/lib/libc/stdlib/qsort.3 b/lib/libc/stdlib/qsort.3
index ac01912..a0610d9 100644
--- a/lib/libc/stdlib/qsort.3
+++ b/lib/libc/stdlib/qsort.3
@@ -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.
diff --git a/lib/libc/stdlib/qsort_r.c b/lib/libc/stdlib/qsort_r.c
index d868736..02469db 100644
--- a/lib/libc/stdlib/qsort_r.c
+++ b/lib/libc/stdlib/qsort_r.c
@@ -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));
+}
OpenPOWER on IntegriCloud