summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r--lib/libc/stdlib/Makefile.inc50
-rw-r--r--lib/libc/stdlib/Symbol.map102
-rw-r--r--lib/libc/stdlib/_Exit.c22
-rw-r--r--lib/libc/stdlib/a64l.3187
-rw-r--r--lib/libc/stdlib/a64l.c46
-rw-r--r--lib/libc/stdlib/abort.379
-rw-r--r--lib/libc/stdlib/abort.c79
-rw-r--r--lib/libc/stdlib/abs.375
-rw-r--r--lib/libc/stdlib/abs.c43
-rw-r--r--lib/libc/stdlib/alloca.388
-rw-r--r--lib/libc/stdlib/atexit.388
-rw-r--r--lib/libc/stdlib/atexit.c185
-rw-r--r--lib/libc/stdlib/atexit.h36
-rw-r--r--lib/libc/stdlib/atof.395
-rw-r--r--lib/libc/stdlib/atof.c43
-rw-r--r--lib/libc/stdlib/atoi.391
-rw-r--r--lib/libc/stdlib/atoi.c43
-rw-r--r--lib/libc/stdlib/atol.3106
-rw-r--r--lib/libc/stdlib/atol.c43
-rw-r--r--lib/libc/stdlib/atoll.c40
-rw-r--r--lib/libc/stdlib/bsearch.389
-rw-r--r--lib/libc/stdlib/bsearch.c79
-rw-r--r--lib/libc/stdlib/div.368
-rw-r--r--lib/libc/stdlib/div.c77
-rw-r--r--lib/libc/stdlib/exit.3130
-rw-r--r--lib/libc/stdlib/exit.c71
-rw-r--r--lib/libc/stdlib/getenv.3173
-rw-r--r--lib/libc/stdlib/getenv.c89
-rw-r--r--lib/libc/stdlib/getopt.3306
-rw-r--r--lib/libc/stdlib/getopt.c135
-rw-r--r--lib/libc/stdlib/getopt_long.3506
-rw-r--r--lib/libc/stdlib/getopt_long.c625
-rw-r--r--lib/libc/stdlib/getsubopt.3145
-rw-r--r--lib/libc/stdlib/getsubopt.c97
-rw-r--r--lib/libc/stdlib/grantpt.3225
-rw-r--r--lib/libc/stdlib/grantpt.c302
-rw-r--r--lib/libc/stdlib/hcreate.3226
-rw-r--r--lib/libc/stdlib/hcreate.c185
-rw-r--r--lib/libc/stdlib/heapsort.c181
-rw-r--r--lib/libc/stdlib/imaxabs.362
-rw-r--r--lib/libc/stdlib/imaxabs.c36
-rw-r--r--lib/libc/stdlib/imaxdiv.373
-rw-r--r--lib/libc/stdlib/imaxdiv.c45
-rw-r--r--lib/libc/stdlib/insque.361
-rw-r--r--lib/libc/stdlib/insque.c47
-rw-r--r--lib/libc/stdlib/l64a.c52
-rw-r--r--lib/libc/stdlib/labs.367
-rw-r--r--lib/libc/stdlib/labs.c43
-rw-r--r--lib/libc/stdlib/ldiv.371
-rw-r--r--lib/libc/stdlib/ldiv.c56
-rw-r--r--lib/libc/stdlib/llabs.362
-rw-r--r--lib/libc/stdlib/llabs.c36
-rw-r--r--lib/libc/stdlib/lldiv.373
-rw-r--r--lib/libc/stdlib/lldiv.c45
-rw-r--r--lib/libc/stdlib/lsearch.3105
-rw-r--r--lib/libc/stdlib/lsearch.c64
-rw-r--r--lib/libc/stdlib/malloc.3490
-rw-r--r--lib/libc/stdlib/malloc.c3806
-rw-r--r--lib/libc/stdlib/memory.377
-rw-r--r--lib/libc/stdlib/merge.c351
-rw-r--r--lib/libc/stdlib/posix_memalign.396
-rw-r--r--lib/libc/stdlib/putenv.c56
-rw-r--r--lib/libc/stdlib/qsort.3286
-rw-r--r--lib/libc/stdlib/qsort.c193
-rw-r--r--lib/libc/stdlib/qsort_r.c8
-rw-r--r--lib/libc/stdlib/radixsort.3160
-rw-r--r--lib/libc/stdlib/radixsort.c327
-rw-r--r--lib/libc/stdlib/rand.3117
-rw-r--r--lib/libc/stdlib/rand.c168
-rw-r--r--lib/libc/stdlib/random.3195
-rw-r--r--lib/libc/stdlib/random.c502
-rw-r--r--lib/libc/stdlib/reallocf.c41
-rw-r--r--lib/libc/stdlib/realpath.3120
-rw-r--r--lib/libc/stdlib/realpath.c197
-rw-r--r--lib/libc/stdlib/remque.c30
-rw-r--r--lib/libc/stdlib/setenv.c116
-rw-r--r--lib/libc/stdlib/strfmon.3167
-rw-r--r--lib/libc/stdlib/strfmon.c604
-rw-r--r--lib/libc/stdlib/strtod.3181
-rw-r--r--lib/libc/stdlib/strtoimax.c140
-rw-r--r--lib/libc/stdlib/strtol.3222
-rw-r--r--lib/libc/stdlib/strtol.c140
-rw-r--r--lib/libc/stdlib/strtoll.c140
-rw-r--r--lib/libc/stdlib/strtonum.3156
-rw-r--r--lib/libc/stdlib/strtonum.c68
-rw-r--r--lib/libc/stdlib/strtoq.c48
-rw-r--r--lib/libc/stdlib/strtoul.3224
-rw-r--r--lib/libc/stdlib/strtoul.c118
-rw-r--r--lib/libc/stdlib/strtoull.c118
-rw-r--r--lib/libc/stdlib/strtoumax.c118
-rw-r--r--lib/libc/stdlib/strtouq.c48
-rw-r--r--lib/libc/stdlib/system.399
-rw-r--r--lib/libc/stdlib/system.c98
-rw-r--r--lib/libc/stdlib/tdelete.c71
-rw-r--r--lib/libc/stdlib/tfind.c48
-rw-r--r--lib/libc/stdlib/tsearch.3132
-rw-r--r--lib/libc/stdlib/tsearch.c58
-rw-r--r--lib/libc/stdlib/twalk.c58
98 files changed, 16640 insertions, 0 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
new file mode 100644
index 0000000..99ea7fb
--- /dev/null
+++ b/lib/libc/stdlib/Makefile.inc
@@ -0,0 +1,50 @@
+# from @(#)Makefile.inc 8.3 (Berkeley) 2/4/95
+# $FreeBSD$
+
+# machine-independent stdlib sources
+.PATH: ${.CURDIR}/${MACHINE_ARCH}/stdlib ${.CURDIR}/stdlib
+
+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 grantpt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
+ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \
+ merge.c putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c \
+ reallocf.c realpath.c remque.c setenv.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
+
+SYM_MAPS+= ${.CURDIR}/stdlib/Symbol.map
+
+# machine-dependent stdlib sources
+.if exists(${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc)
+.include "${.CURDIR}/${MACHINE_ARCH}/stdlib/Makefile.inc"
+.endif
+
+MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
+ div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 grantpt.3 \
+ hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
+ lsearch.3 malloc.3 memory.3 posix_memalign.3 qsort.3 radixsort.3 \
+ rand.3 random.3 \
+ realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
+ tsearch.3
+
+MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3
+MLINKS+=atol.3 atoll.3
+MLINKS+=exit.3 _Exit.3
+MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
+MLINKS+=getopt_long.3 getopt_long_only.3
+MLINKS+=grantpt.3 posix_openpt.3 grantpt.3 ptsname.3 grantpt.3 unlockpt.3
+MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
+MLINKS+=insque.3 remque.3
+MLINKS+=lsearch.3 lfind.3
+MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3 qsort.3 qsort_r.3
+MLINKS+=rand.3 rand_r.3 rand.3 srand.3 rand.3 sranddev.3
+MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
+ random.3 srandomdev.3
+MLINKS+=radixsort.3 sradixsort.3
+MLINKS+=strtod.3 strtof.3 strtod.3 strtold.3
+MLINKS+=strtol.3 strtoll.3 strtol.3 strtoq.3 strtol.3 strtoimax.3
+MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.3 strtoul.3 strtoumax.3
+MLINKS+=malloc.3 calloc.3 malloc.3 free.3 malloc.3 malloc.conf.5 \
+ malloc.3 realloc.3 malloc.3 reallocf.3 malloc.3 malloc_usable_size.3
+MLINKS+=tsearch.3 tdelete.3 tsearch.3 tfind.3 tsearch.3 twalk.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
new file mode 100644
index 0000000..cbb9fb1
--- /dev/null
+++ b/lib/libc/stdlib/Symbol.map
@@ -0,0 +1,102 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ _Exit;
+ a64l;
+ abort;
+ abs;
+ atexit;
+ __cxa_atexit;
+ __cxa_finalize;
+ atof;
+ atoi;
+ atol;
+ atoll;
+ bsearch;
+ div;
+ __isthreaded;
+ exit;
+ getenv;
+ opterr;
+ optind;
+ optopt;
+ optreset;
+ optarg;
+ getopt;
+ getopt_long;
+ getopt_long_only;
+ suboptarg;
+ getsubopt;
+ grantpt;
+ posix_openpt;
+ ptsname;
+ unlockpt;
+ hcreate;
+ hdestroy;
+ hsearch;
+ heapsort;
+ imaxabs;
+ imaxdiv;
+ insque;
+ l64a;
+ l64a_r;
+ labs;
+ ldiv;
+ llabs;
+ lldiv;
+ lsearch;
+ lfind;
+ _malloc_options;
+ _malloc_message;
+ malloc;
+ posix_memalign;
+ calloc;
+ realloc;
+ free;
+ malloc_usable_size;
+ mergesort;
+ putenv;
+ qsort_r;
+ qsort;
+ radixsort;
+ sradixsort;
+ rand_r;
+ rand;
+ srand;
+ sranddev;
+ srandom;
+ srandomdev;
+ initstate;
+ setstate;
+ random;
+ reallocf;
+ realpath;
+ remque;
+ setenv;
+ unsetenv;
+ strfmon;
+ strtoimax;
+ strtol;
+ strtoll;
+ strtonum;
+ strtoq;
+ strtoul;
+ strtoull;
+ strtoumax;
+ strtouq;
+ system;
+ tdelete;
+ tfind;
+ tsearch;
+ twalk;
+};
+
+FBSDprivate_1.0 {
+ __use_pts;
+ _malloc_prefork;
+ _malloc_postfork;
+ __system;
+ _system;
+};
diff --git a/lib/libc/stdlib/_Exit.c b/lib/libc/stdlib/_Exit.c
new file mode 100644
index 0000000..e7f0f51
--- /dev/null
+++ b/lib/libc/stdlib/_Exit.c
@@ -0,0 +1,22 @@
+/*
+ * This file is in the public domain. Written by Garrett A. Wollman,
+ * 2002-09-07.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * ISO C99 added this function to provide for Standard C applications
+ * which needed something like POSIX _exit(). A new interface was created
+ * in case it turned out that _exit() was insufficient to meet the
+ * requirements of ISO C. (That's probably not the case, but here
+ * is where you would put the extra code if it were.)
+ */
+void
+_Exit(int code)
+{
+ _exit(code);
+}
diff --git a/lib/libc/stdlib/a64l.3 b/lib/libc/stdlib/a64l.3
new file mode 100644
index 0000000..61fbffd
--- /dev/null
+++ b/lib/libc/stdlib/a64l.3
@@ -0,0 +1,187 @@
+.\" Copyright (c) 2005 Tom Rhodes
+.\" 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.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 20, 2005
+.Dt A64L 3
+.Os
+.Sh NAME
+.Nm a64l ,
+.Nm l64a ,
+.Nm l64a_r
+.Nd "convert between a long integer and a base-64 ASCII string"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn a64l "const char *s"
+.Ft char *
+.Fn l64a "long int l"
+.Ft int
+.Fn l64a_r "long int l" "char *buffer" "int buflen"
+.Sh DESCRIPTION
+These functions are used to maintain numbers stored in radix-64
+.Tn ASCII
+characters.
+This is a notation by which 32-bit integers can be represented by
+up to six characters; each character represents a digit in
+radix-64 notation.
+If the type long contains more than 32 bits, only the low-order
+32 bits are used for these operations.
+.Pp
+The characters used to represent
+.Dq digits
+are
+.Ql .\&
+for 0,
+.Ql /
+for 1,
+.Ql 0
+-
+.Ql 9
+for 2 - 11,
+.Ql A
+-
+.Ql Z
+for 12 - 37, and
+.Ql a
+-
+.Ql z
+for 38 - 63.
+.Pp
+The
+.Fn a64l
+function takes a pointer to a radix-64 representation, in which the first
+digit is the least significant, and returns a corresponding
+.Vt long
+value.
+If the string pointed to by
+.Fa s
+contains more than six characters,
+.Fn a64l
+uses the first six.
+If the first six characters of the string contain a null terminator,
+.Fn a64l
+uses only characters preceding the null terminator.
+The
+.Fn a64l
+function scans the character string from left to right with the least
+significant digit on the left, decoding each character as a 6-bit
+radix-64 number.
+If the type long contains more than 32 bits, the resulting value is
+sign-extended.
+The behavior of
+.Fn a64l
+is unspecified if
+.Fa s
+is a null pointer or the string pointed to by
+.Fa s
+was not generated by a previous call to
+.Fn l64a .
+.Pp
+The
+.Fn l64a
+function takes a
+.Vt long
+argument and returns a pointer to the corresponding
+radix-64 representation.
+The behavior of
+.Fn l64a
+is unspecified if value is negative.
+.Pp
+The value returned by
+.Fn l64a
+is a pointer into a static buffer.
+Subsequent calls to
+.Fn l64a
+may overwrite the buffer.
+.Pp
+The
+.Fn l64a_r
+function performs a conversion identical to that of
+.Fn l64a
+and stores the resulting representation in the memory area pointed to by
+.Fa buffer ,
+consuming at most
+.Fa buflen
+characters including the terminating
+.Dv NUL
+character.
+.Sh RETURN VALUES
+On successful completion,
+.Fn a64l
+returns the
+.Vt long
+value resulting from conversion of the input string.
+If a string pointed to by
+.Fa s
+is an empty string,
+.Fn a64l
+returns 0.
+.Pp
+The
+.Fn l64a
+function returns a pointer to the radix-64 representation.
+If value is 0,
+.Fn l64a
+returns a pointer to an empty string.
+.Sh SEE ALSO
+.Xr strtoul 3
+.Sh HISTORY
+The
+.Fn a64l ,
+.Fn l64a ,
+and
+.Fn l64a_r
+functions are derived from
+.Nx
+with modifications.
+They appeared in
+.Fx 6.1 .
+.Sh AUTHORS
+The
+.Fn a64l ,
+.Fn l64a ,
+and
+.Fn l64a_r
+functions
+were added to
+.Fx
+by
+.An Tom Rhodes Aq trhodes@FreeBSD.org .
+Almost all of this manual page came from the
+.Tn POSIX
+standard.
diff --git a/lib/libc/stdlib/a64l.c b/lib/libc/stdlib/a64l.c
new file mode 100644
index 0000000..a130dcb
--- /dev/null
+++ b/lib/libc/stdlib/a64l.c
@@ -0,0 +1,46 @@
+/*-
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Public domain.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: a64l.c,v 1.8 2000/01/22 22:19:19 mycroft Exp $");
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#define ADOT 46 /* ASCII '.' */
+#define ASLASH 47 /* ASCII '/' */
+#define A0 48 /* ASCII '0' */
+#define AA 65 /* ASCII 'A' */
+#define Aa 97 /* ASCII 'a' */
+
+long
+a64l(const char *s)
+{
+ long shift;
+ int digit, i, value;
+
+ value = 0;
+ shift = 0;
+ for (i = 0; *s != '\0' && i < 6; i++, s++) {
+ if (*s <= ASLASH)
+ digit = *s - ASLASH + 1;
+ else if (*s <= A0 + 9)
+ digit = *s - A0 + 2;
+ else if (*s <= AA + 25)
+ digit = *s - AA + 12;
+ else
+ digit = *s - Aa + 38;
+
+ value |= digit << shift;
+ shift += 6;
+ }
+ return (value);
+}
diff --git a/lib/libc/stdlib/abort.3 b/lib/libc/stdlib/abort.3
new file mode 100644
index 0000000..b939e9c2
--- /dev/null
+++ b/lib/libc/stdlib/abort.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)abort.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ABORT 3
+.Os
+.Sh NAME
+.Nm abort
+.Nd cause abnormal program termination
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn abort void
+.Sh DESCRIPTION
+The
+.Fn abort
+function causes abnormal program termination to occur, unless the
+signal
+.Dv SIGABRT
+is being caught and the signal handler does not return.
+.Pp
+Any open streams are flushed and closed.
+.Sh IMPLEMENTATION NOTES
+The
+.Fn abort
+function is thread-safe.
+It is unknown if it is async-cancel-safe.
+.Sh RETURN VALUES
+The
+.Fn abort
+function
+never returns.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr exit 3
+.Sh STANDARDS
+The
+.Fn abort
+function
+conforms to
+.St -p1003.1-90 .
+The
+.Fn abort
+function also conforms to
+.St -isoC-99
+with the implementation specific details as noted above.
diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c
new file mode 100644
index 0000000..eba53e5
--- /dev/null
+++ b/lib/libc/stdlib/abort.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)abort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+void
+abort()
+{
+ struct sigaction act;
+
+ /*
+ * POSIX requires we flush stdio buffers on abort.
+ * XXX ISO C requires that abort() be async-signal-safe.
+ */
+ if (__cleanup)
+ (*__cleanup)();
+
+ sigfillset(&act.sa_mask);
+ /*
+ * Don't block SIGABRT to give any handler a chance; we ignore
+ * any errors -- ISO C doesn't allow abort to return anyway.
+ */
+ sigdelset(&act.sa_mask, SIGABRT);
+ (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
+ (void)raise(SIGABRT);
+
+ /*
+ * If SIGABRT was ignored, or caught and the handler returns, do
+ * it again, only harder.
+ */
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigfillset(&act.sa_mask);
+ (void)_sigaction(SIGABRT, &act, NULL);
+ sigdelset(&act.sa_mask, SIGABRT);
+ (void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
+ (void)raise(SIGABRT);
+ exit(1);
+}
diff --git a/lib/libc/stdlib/abs.3 b/lib/libc/stdlib/abs.3
new file mode 100644
index 0000000..4f02122
--- /dev/null
+++ b/lib/libc/stdlib/abs.3
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)abs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt ABS 3
+.Os
+.Sh NAME
+.Nm abs
+.Nd integer absolute value function
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn abs "int j"
+.Sh DESCRIPTION
+The
+.Fn abs
+function
+computes
+the absolute value of the integer
+.Fa j .
+.Sh RETURN VALUES
+The
+.Fn abs
+function
+returns
+the absolute value.
+.Sh SEE ALSO
+.Xr cabs 3 ,
+.Xr fabs 3 ,
+.Xr floor 3 ,
+.Xr hypot 3 ,
+.Xr imaxabs 3 ,
+.Xr labs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn abs
+function conforms to
+.St -isoC-99 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/abs.c b/lib/libc/stdlib/abs.c
new file mode 100644
index 0000000..5ca9596
--- /dev/null
+++ b/lib/libc/stdlib/abs.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)abs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+int
+abs(j)
+ int j;
+{
+ return(j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/alloca.3 b/lib/libc/stdlib/alloca.3
new file mode 100644
index 0000000..9559444
--- /dev/null
+++ b/lib/libc/stdlib/alloca.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)alloca.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 5, 2006
+.Dt ALLOCA 3
+.Os
+.Sh NAME
+.Nm alloca
+.Nd memory allocator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn alloca "size_t size"
+.Sh DESCRIPTION
+The
+.Fn alloca
+function
+allocates
+.Fa size
+bytes of space in the stack frame of the caller.
+This temporary space is automatically freed on
+return.
+.Sh RETURN VALUES
+The
+.Fn alloca
+function returns a pointer to the beginning of the allocated space.
+.Sh SEE ALSO
+.Xr brk 2 ,
+.Xr calloc 3 ,
+.Xr getpagesize 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3
+.Sh HISTORY
+The
+.Fn alloca
+function appeared in
+.At 32v .
+.\" .Bx ?? .
+.\" The function appeared in 32v, pwb and pwb.2 and in 3bsd 4bsd
+.\" The first man page (or link to a man page that I can find at the
+.\" moment is 4.3...
+.Sh BUGS
+The
+.Fn alloca
+function
+is machine and compiler dependent;
+its use is discouraged.
+.Pp
+The
+.Fn alloca
+function is slightly unsafe because it cannot ensure that the pointer
+returned points to a valid and usable block of memory.
+The allocation made may exceed the bounds of the stack, or even go
+further into other objects in memory, and
+.Fn alloca
+cannot determine such an error.
+Avoid
+.Fn alloca
+with large unbounded allocations.
diff --git a/lib/libc/stdlib/atexit.3 b/lib/libc/stdlib/atexit.3
new file mode 100644
index 0000000..3c44b8d
--- /dev/null
+++ b/lib/libc/stdlib/atexit.3
@@ -0,0 +1,88 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)atexit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 6, 2002
+.Dt ATEXIT 3
+.Os
+.Sh NAME
+.Nm atexit
+.Nd register a function to be called on exit
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn atexit "void (*function)(void)"
+.Sh DESCRIPTION
+The
+.Fn atexit
+function
+registers the given
+.Fa function
+to be called at program exit, whether via
+.Xr exit 3
+or via return from the program's
+.Fn main .
+Functions so registered are called in reverse order;
+no arguments are passed.
+.Pp
+These functions must not call
+.Fn exit ;
+if it should be necessary to terminate the process while in such a
+function, the
+.Xr _exit 2
+function should be used.
+(Alternatively, the function may cause abnormal
+process termination, for example by calling
+.Xr abort 3 . )
+.Pp
+At least 32 functions can always be registered,
+and more are allowed as long as sufficient memory can be allocated.
+.\" XXX {ATEXIT_MAX} is not implemented yet
+.Sh RETURN VALUES
+.Rv -std atexit
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+No memory was available to add the function to the list.
+The existing list of functions is unmodified.
+.El
+.Sh SEE ALSO
+.Xr exit 3
+.Sh STANDARDS
+The
+.Fn atexit
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
new file mode 100644
index 0000000..efd1264
--- /dev/null
+++ b/lib/libc/stdlib/atexit.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "atexit.h"
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+#define ATEXIT_FN_EMPTY 0
+#define ATEXIT_FN_STD 1
+#define ATEXIT_FN_CXA 2
+
+static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
+#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
+
+struct atexit {
+ struct atexit *next; /* next in list */
+ int ind; /* next index in this table */
+ struct atexit_fn {
+ int fn_type; /* ATEXIT_? from above */
+ union {
+ void (*std_func)(void);
+ void (*cxa_func)(void *);
+ } fn_ptr; /* function pointer */
+ void *fn_arg; /* argument for CXA callback */
+ void *fn_dso; /* shared module handle */
+ } fns[ATEXIT_SIZE]; /* the table itself */
+};
+
+static struct atexit *__atexit; /* points to head of LIFO stack */
+
+/*
+ * Register the function described by 'fptr' to be called at application
+ * exit or owning shared object unload time. This is a helper function
+ * for atexit and __cxa_atexit.
+ */
+static int
+atexit_register(struct atexit_fn *fptr)
+{
+ static struct atexit __atexit0; /* one guaranteed table */
+ struct atexit *p;
+
+ _MUTEX_LOCK(&atexit_mutex);
+ if ((p = __atexit) == NULL)
+ __atexit = p = &__atexit0;
+ else while (p->ind >= ATEXIT_SIZE) {
+ struct atexit *old__atexit;
+ old__atexit = __atexit;
+ _MUTEX_UNLOCK(&atexit_mutex);
+ if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
+ return (-1);
+ _MUTEX_LOCK(&atexit_mutex);
+ if (old__atexit != __atexit) {
+ /* Lost race, retry operation */
+ _MUTEX_UNLOCK(&atexit_mutex);
+ free(p);
+ _MUTEX_LOCK(&atexit_mutex);
+ p = __atexit;
+ continue;
+ }
+ p->ind = 0;
+ p->next = __atexit;
+ __atexit = p;
+ }
+ p->fns[p->ind++] = *fptr;
+ _MUTEX_UNLOCK(&atexit_mutex);
+ return 0;
+}
+
+/*
+ * Register a function to be performed at exit.
+ */
+int
+atexit(void (*func)(void))
+{
+ struct atexit_fn fn;
+ int error;
+
+ fn.fn_type = ATEXIT_FN_STD;
+ fn.fn_ptr.std_func = func;;
+ fn.fn_arg = NULL;
+ fn.fn_dso = NULL;
+
+ error = atexit_register(&fn);
+ return (error);
+}
+
+/*
+ * Register a function to be performed at exit or when an shared object
+ * with given dso handle is unloaded dynamically.
+ */
+int
+__cxa_atexit(void (*func)(void *), void *arg, void *dso)
+{
+ struct atexit_fn fn;
+ int error;
+
+ fn.fn_type = ATEXIT_FN_CXA;
+ fn.fn_ptr.cxa_func = func;;
+ fn.fn_arg = arg;
+ fn.fn_dso = dso;
+
+ error = atexit_register(&fn);
+ return (error);
+}
+
+/*
+ * Call all handlers registered with __cxa_atexit for the shared
+ * object owning 'dso'. Note: if 'dso' is NULL, then all remaining
+ * handlers are called.
+ */
+void
+__cxa_finalize(void *dso)
+{
+ struct atexit *p;
+ struct atexit_fn fn;
+ int n;
+
+ _MUTEX_LOCK(&atexit_mutex);
+ for (p = __atexit; p; p = p->next) {
+ for (n = p->ind; --n >= 0;) {
+ if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
+ continue; /* already been called */
+ if (dso != NULL && dso != p->fns[n].fn_dso)
+ continue; /* wrong DSO */
+ fn = p->fns[n];
+ /*
+ Mark entry to indicate that this particular handler
+ has already been called.
+ */
+ p->fns[n].fn_type = ATEXIT_FN_EMPTY;
+ _MUTEX_UNLOCK(&atexit_mutex);
+
+ /* Call the function of correct type. */
+ if (fn.fn_type == ATEXIT_FN_CXA)
+ fn.fn_ptr.cxa_func(fn.fn_arg);
+ else if (fn.fn_type == ATEXIT_FN_STD)
+ fn.fn_ptr.std_func();
+ _MUTEX_LOCK(&atexit_mutex);
+ }
+ }
+ _MUTEX_UNLOCK(&atexit_mutex);
+}
diff --git a/lib/libc/stdlib/atexit.h b/lib/libc/stdlib/atexit.h
new file mode 100644
index 0000000..f34194f
--- /dev/null
+++ b/lib/libc/stdlib/atexit.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)atexit.h 8.2 (Berkeley) 7/3/94
+ * $FreeBSD$
+ */
+
+/* must be at least 32 to guarantee ANSI conformance */
+#define ATEXIT_SIZE 32
+
+void __cxa_finalize(void *dso);
diff --git a/lib/libc/stdlib/atof.3 b/lib/libc/stdlib/atof.3
new file mode 100644
index 0000000..abf5b7c
--- /dev/null
+++ b/lib/libc/stdlib/atof.3
@@ -0,0 +1,95 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)atof.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ATOF 3
+.Os
+.Sh NAME
+.Nm atof
+.Nd convert
+.Tn ASCII
+string to double
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft double
+.Fn atof "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atof
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt double
+representation.
+.Pp
+It is equivalent to:
+.Bd -literal -offset indent
+strtod(nptr, (char **)NULL);
+.Ed
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Sh IMPLEMENTATION NOTES
+The
+.Fn atof
+function is not thread-safe and also not async-cancel-safe.
+.Pp
+The
+.Fn atof
+function has been deprecated by
+.Fn strtod
+and should not be used in new code.
+.Sh ERRORS
+The function
+.Fn atof
+need not affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atof
+function conforms to
+.St -p1003.1-90 ,
+.St -isoC ,
+and
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c
new file mode 100644
index 0000000..51e482e
--- /dev/null
+++ b/lib/libc/stdlib/atof.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+double
+atof(ascii)
+ const char *ascii;
+{
+ return strtod(ascii, (char **)NULL);
+}
diff --git a/lib/libc/stdlib/atoi.3 b/lib/libc/stdlib/atoi.3
new file mode 100644
index 0000000..5d2d754
--- /dev/null
+++ b/lib/libc/stdlib/atoi.3
@@ -0,0 +1,91 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)atoi.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt ATOI 3
+.Os
+.Sh NAME
+.Nm atoi
+.Nd convert
+.Tn ASCII
+string to integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn atoi "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atoi
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt int
+representation.
+.Pp
+It is equivalent to:
+.Bd -literal -offset indent
+(int)strtol(nptr, (char **)NULL, 10);
+.Ed
+.Sh IMPLEMENTATION NOTES
+The
+.Fn atoi
+function is not thread-safe and also not async-cancel safe.
+.Pp
+The
+.Fn atoi
+function has been deprecated by
+.Fn strtol
+and should not be used in new code.
+.Sh ERRORS
+The function
+.Fn atoi
+need not affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atoi
+function conforms to
+.St -p1003.1-90 ,
+.St -isoC ,
+and
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
new file mode 100644
index 0000000..0ffcd03
--- /dev/null
+++ b/lib/libc/stdlib/atoi.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+int
+atoi(str)
+ const char *str;
+{
+ return (int)strtol(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atol.3 b/lib/libc/stdlib/atol.3
new file mode 100644
index 0000000..b9cf9e9
--- /dev/null
+++ b/lib/libc/stdlib/atol.3
@@ -0,0 +1,106 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)atol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.Dt ATOL 3
+.Os
+.Sh NAME
+.Nm atol , atoll
+.Nd convert
+.Tn ASCII
+string to
+.Vt long
+or
+.Vt "long long"
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn atol "const char *nptr"
+.Ft "long long"
+.Fn atoll "const char *nptr"
+.Sh DESCRIPTION
+The
+.Fn atol
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt long
+integer
+representation.
+.Pp
+It is equivalent to:
+.Pp
+.Dl "strtol(nptr, (char **)NULL, 10);"
+.Pp
+The
+.Fn atoll
+function converts the initial portion of the string pointed to by
+.Fa nptr
+to
+.Vt "long long"
+integer
+representation.
+.Pp
+It is equivalent to:
+.Pp
+.Dl "strtoll(nptr, (char **)NULL, 10);"
+.Sh ERRORS
+The functions
+.Fn atol
+and
+.Fn atoll
+need not
+affect the value of
+.Va errno
+on an error.
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn atol
+function
+conforms to
+.St -isoC .
+The
+.Fn atoll
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c
new file mode 100644
index 0000000..c9cf2e8
--- /dev/null
+++ b/lib/libc/stdlib/atol.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long
+atol(str)
+ const char *str;
+{
+ return strtol(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
new file mode 100644
index 0000000..203c174
--- /dev/null
+++ b/lib/libc/stdlib/atoll.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long long
+atoll(str)
+ const char *str;
+{
+ return strtoll(str, (char **)NULL, 10);
+}
diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3
new file mode 100644
index 0000000..b3591f8e
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.3
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)bsearch.3 8.3 (Berkeley) 4/19/94
+.\" $FreeBSD$
+.\"
+.Dd April 19, 1994
+.Dt BSEARCH 3
+.Os
+.Sh NAME
+.Nm bsearch
+.Nd binary search of a sorted table
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn bsearch "const void *key" "const void *base" "size_t nmemb" "size_t size" "int (*compar) (const void *, const void *)"
+.Sh DESCRIPTION
+The
+.Fn bsearch
+function searches an array of
+.Fa nmemb
+objects, the initial member of which is
+pointed to by
+.Fa base ,
+for a member that matches the object pointed to by
+.Fa key .
+The size of each member of the array is specified by
+.Fa size .
+.Pp
+The contents of the array should be in ascending sorted order according
+to the comparison function referenced by
+.Fa compar .
+The
+.Fa compar
+routine
+is expected to have
+two arguments which point to the
+.Fa key
+object and to an array member, in that order, and should return an integer
+less than, equal to, or greater than zero if the
+.Fa key
+object is found, respectively, to be less than, to match, or be
+greater than the array member.
+.Sh RETURN VALUES
+The
+.Fn bsearch
+function returns a pointer to a matching member of the array, or a null
+pointer if no match is found.
+If two members compare as equal, which member is matched is unspecified.
+.Sh SEE ALSO
+.Xr db 3 ,
+.Xr lsearch 3 ,
+.Xr qsort 3
+.\" .Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn bsearch
+function conforms to
+.St -isoC .
diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c
new file mode 100644
index 0000000..ff02168
--- /dev/null
+++ b/lib/libc/stdlib/bsearch.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Perform a binary search.
+ *
+ * The code below is a bit sneaky. After a comparison fails, we
+ * divide the work in half by moving either left or right. If lim
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1. If lim is even, the same applies. If lim
+ * is odd, moving right again involes halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+ * halving: e.g., when lim is 4, we still looked at item 2, so we
+ * have to make lim 3, then halve, obtaining 1, so that we will only
+ * look at item 3.
+ */
+void *
+bsearch(key, base0, nmemb, size, compar)
+ const void *key;
+ const void *base0;
+ size_t nmemb;
+ size_t size;
+ int (*compar)(const void *, const void *);
+{
+ const char *base = base0;
+ size_t lim;
+ int cmp;
+ const void *p;
+
+ for (lim = nmemb; lim != 0; lim >>= 1) {
+ p = base + (lim >> 1) * size;
+ cmp = (*compar)(key, p);
+ if (cmp == 0)
+ return ((void *)p);
+ if (cmp > 0) { /* key > p: move right */
+ base = (char *)p + size;
+ lim--;
+ } /* else move left */
+ }
+ return (NULL);
+}
diff --git a/lib/libc/stdlib/div.3 b/lib/libc/stdlib/div.3
new file mode 100644
index 0000000..46a145f
--- /dev/null
+++ b/lib/libc/stdlib/div.3
@@ -0,0 +1,68 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek.
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)div.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt DIV 3
+.Os
+.Sh NAME
+.Nm div
+.Nd return quotient and remainder from division
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft div_t
+.Fn div "int num" "int denom"
+.Sh DESCRIPTION
+The
+.Fn div
+function
+computes the value
+.Fa num/denom
+and returns the quotient and remainder in a structure named
+.Fa div_t
+that contains two
+.Vt int
+members named
+.Va quot
+and
+.Va rem .
+.Sh SEE ALSO
+.Xr imaxdiv 3 ,
+.Xr ldiv 3 ,
+.Xr lldiv 3
+.Sh STANDARDS
+The
+.Fn div
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/div.c b/lib/libc/stdlib/div.c
new file mode 100644
index 0000000..ef93d73
--- /dev/null
+++ b/lib/libc/stdlib/div.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* div_t */
+
+div_t
+div(num, denom)
+ int num, denom;
+{
+ div_t r;
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ /*
+ * The ANSI standard says that |r.quot| <= |n/d|, where
+ * n/d is to be computed in infinite precision. In other
+ * words, we should always truncate the quotient towards
+ * 0, never -infinity.
+ *
+ * Machine division and remainer may work either way when
+ * one or both of n or d is negative. If only one is
+ * negative and r.quot has been truncated towards -inf,
+ * r.rem will have the same sign as denom and the opposite
+ * sign of num; if both are negative and r.quot has been
+ * truncated towards -inf, r.rem will be positive (will
+ * have the opposite sign of num). These are considered
+ * `wrong'.
+ *
+ * If both are num and denom are positive, r will always
+ * be positive.
+ *
+ * This all boils down to:
+ * if num >= 0, but r.rem < 0, we got the wrong answer.
+ * In that case, to get the right answer, add 1 to r.quot and
+ * subtract denom from r.rem.
+ */
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+ return (r);
+}
diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3
new file mode 100644
index 0000000..a864ccb
--- /dev/null
+++ b/lib/libc/stdlib/exit.3
@@ -0,0 +1,130 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)exit.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 9, 2002
+.Dt EXIT 3
+.Os
+.Sh NAME
+.Nm exit , _Exit
+.Nd perform normal program termination
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn exit "int status"
+.Ft void
+.Fn _Exit "int status"
+.Sh DESCRIPTION
+The
+.Fn exit
+and
+.Fn _Exit
+functions terminate a process.
+.Pp
+Before termination,
+.Fn exit
+performs the following functions in the order listed:
+.Bl -enum -offset indent
+.It
+Call the functions registered with the
+.Xr atexit 3
+function, in the reverse order of their registration.
+.It
+Flush all open output streams.
+.It
+Close all open streams.
+.It
+Unlink all files created with the
+.Xr tmpfile 3
+function.
+.El
+.Pp
+The
+.Fn _Exit
+function terminates without calling the functions registered with the
+.Xr atexit 3
+function, and may or may not perform the other actions listed.
+Both functions make the low-order eight bits of the
+.Fa status
+argument available to a parent process which has called a
+.Xr wait 2 Ns -family
+function.
+.Pp
+The C Standard
+.Pq St -isoC-99
+defines the values
+.Li 0 ,
+.Dv EXIT_SUCCESS ,
+and
+.Dv EXIT_FAILURE
+as possible values of
+.Fa status .
+Cooperating processes may use other values;
+in a program which might be called by a mail transfer agent, the
+values described in
+.Xr sysexits 3
+may be used to provide more information to the parent process.
+.Pp
+Note that
+.Fn exit
+does nothing to prevent bottomless recursion should a function registered
+using
+.Xr atexit 3
+itself call
+.Fn exit .
+Such functions must call
+.Fn _Exit
+instead (although this has other effects as well which may not be desired).
+.Sh RETURN VALUES
+The
+.Fn exit
+and
+.Fn _Exit
+functions
+never return.
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr wait 2 ,
+.Xr atexit 3 ,
+.Xr intro 3 ,
+.Xr sysexits 3 ,
+.Xr tmpfile 3
+.Sh STANDARDS
+The
+.Fn exit
+and
+.Fn _Exit
+functions conform to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c
new file mode 100644
index 0000000..26c346a
--- /dev/null
+++ b/lib/libc/stdlib/exit.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)exit.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "atexit.h"
+#include "libc_private.h"
+
+void (*__cleanup)(void);
+
+/*
+ * This variable is zero until a process has created a thread.
+ * It is used to avoid calling locking functions in libc when they
+ * are not required. By default, libc is intended to be(come)
+ * thread-safe, but without a (significant) penalty to non-threaded
+ * processes.
+ */
+int __isthreaded = 0;
+
+/*
+ * Exit, flushing stdio buffers if necessary.
+ */
+void
+exit(status)
+ int status;
+{
+ /* Ensure that the auto-initialization routine is linked in: */
+ extern int _thread_autoinit_dummy_decl;
+
+ _thread_autoinit_dummy_decl = 1;
+
+ __cxa_finalize(NULL);
+ if (__cleanup)
+ (*__cleanup)();
+ _exit(status);
+}
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
new file mode 100644
index 0000000..3d365f1
--- /dev/null
+++ b/lib/libc/stdlib/getenv.3
@@ -0,0 +1,173 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)getenv.3 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD$
+.\"
+.Dd October 12, 2006
+.Dt GETENV 3
+.Os
+.Sh NAME
+.Nm getenv ,
+.Nm putenv ,
+.Nm setenv ,
+.Nm unsetenv
+.Nd environment variable functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fn getenv "const char *name"
+.Ft int
+.Fn setenv "const char *name" "const char *value" "int overwrite"
+.Ft int
+.Fn putenv "const char *string"
+.Ft void
+.Fn unsetenv "const char *name"
+.Sh DESCRIPTION
+These functions set, unset and fetch environment variables from the
+host
+.Em environment list .
+For compatibility with differing environment conventions,
+the given arguments
+.Fa name
+and
+.Fa value
+may be appended and prepended,
+respectively,
+with an equal sign
+.Dq Li \&= .
+.Pp
+The
+.Fn getenv
+function obtains the current value of the environment variable,
+.Fa name .
+The application should not modify the string pointed
+to by the
+.Fn getenv
+function.
+.Pp
+The
+.Fn setenv
+function inserts or resets the environment variable
+.Fa name
+in the current environment list.
+If the variable
+.Fa name
+does not exist in the list,
+it is inserted with the given
+.Fa value .
+If the variable does exist, the argument
+.Fa overwrite
+is tested; if
+.Fa overwrite
+is zero, the
+variable is not reset, otherwise it is reset
+to the given
+.Fa value .
+.Pp
+The
+.Fn putenv
+function takes an argument of the form ``name=value'' and is
+equivalent to:
+.Bd -literal -offset indent
+setenv(name, value, 1);
+.Ed
+.Pp
+The
+.Fn unsetenv
+function
+deletes all instances of the variable name pointed to by
+.Fa name
+from the list.
+.Sh RETURN VALUES
+The
+.Fn getenv
+function returns the value of the environment variable as a
+.Dv NUL Ns
+-terminated string.
+If the variable
+.Fa name
+is not in the current environment,
+.Dv NULL
+is returned.
+.Pp
+.Rv -std setenv putenv
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The function
+.Fn setenv
+or
+.Fn putenv
+failed because they were unable to allocate memory for the environment.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr execve 2 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Fn getenv
+function conforms to
+.St -isoC .
+.Sh HISTORY
+The functions
+.Fn setenv
+and
+.Fn unsetenv
+appeared in
+.At v7 .
+The
+.Fn putenv
+function appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+Successive calls to
+.Fn setenv
+or
+.Fn putenv
+assigning a differently sized
+.Fa value
+to the same
+.Fa name
+will result in a memory leak.
+The
+.Fx
+semantics for these functions
+(namely, that the contents of
+.Fa value
+are copied and that old values remain accessible indefinitely) make this
+bug unavoidable.
+Future versions may eliminate one or both of these
+semantic guarantees in order to fix the bug.
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
new file mode 100644
index 0000000..306b6a1
--- /dev/null
+++ b/lib/libc/stdlib/getenv.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+inline char *__findenv(const char *, int *);
+
+/*
+ * __findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ *
+ * This routine *should* be a static; don't use it.
+ */
+inline char *
+__findenv(name, offset)
+ const char *name;
+ int *offset;
+{
+ extern char **environ;
+ int len, i;
+ const char *np;
+ char **p, *cp;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (cp = *p) != NULL; ++p) {
+ for (np = name, i = len; i && *cp; i--)
+ if (*cp++ != *np++)
+ break;
+ if (i == 0 && *cp++ == '=') {
+ *offset = p - environ;
+ return (cp);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
diff --git a/lib/libc/stdlib/getopt.3 b/lib/libc/stdlib/getopt.3
new file mode 100644
index 0000000..a966624
--- /dev/null
+++ b/lib/libc/stdlib/getopt.3
@@ -0,0 +1,306 @@
+.\" $NetBSD: getopt.3,v 1.31 2003/09/23 10:26:54 wiz Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
+.\" $FreeBSD$
+.\"
+.Dd April 27, 1995
+.Dt GETOPT 3
+.Os
+.Sh NAME
+.Nm getopt
+.Nd get option character from command line argument list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In unistd.h
+.Vt extern char *optarg ;
+.Vt extern int optind ;
+.Vt extern int optopt ;
+.Vt extern int opterr ;
+.Vt extern int optreset ;
+.Ft int
+.Fn getopt "int argc" "char * const argv[]" "const char *optstring"
+.Sh DESCRIPTION
+The
+.Fn getopt
+function incrementally parses a command line argument list
+.Fa argv
+and returns the next
+.Em known
+option character.
+An option character is
+.Em known
+if it has been specified in the string of accepted option characters,
+.Fa optstring .
+.Pp
+The option string
+.Fa optstring
+may contain the following elements: individual characters, and
+characters followed by a colon to indicate an option argument
+is to follow.
+For example, an option string
+.Li "\&""x""
+recognizes an option
+.Dq Fl x ,
+and an option string
+.Li "\&""x:""
+recognizes an option and argument
+.Dq Fl x Ar argument .
+It does not matter to
+.Fn getopt
+if a following argument has leading white space.
+.Pp
+On return from
+.Fn getopt ,
+.Va optarg
+points to an option argument, if it is anticipated,
+and the variable
+.Va optind
+contains the index to the next
+.Fa argv
+argument for a subsequent call
+to
+.Fn getopt .
+The variable
+.Va optopt
+saves the last
+.Em known
+option character returned by
+.Fn getopt .
+.Pp
+The variables
+.Va opterr
+and
+.Va optind
+are both initialized to 1.
+The
+.Va optind
+variable may be set to another value before a set of calls to
+.Fn getopt
+in order to skip over more or less argv entries.
+.Pp
+In order to use
+.Fn getopt
+to evaluate multiple sets of arguments, or to evaluate a single set of
+arguments multiple times,
+the variable
+.Va optreset
+must be set to 1 before the second and each additional set of calls to
+.Fn getopt ,
+and the variable
+.Va optind
+must be reinitialized.
+.Pp
+The
+.Fn getopt
+function returns \-1 when the argument list is exhausted.
+The interpretation of options in the argument list may be cancelled
+by the option
+.Ql --
+(double dash) which causes
+.Fn getopt
+to signal the end of argument processing and return \-1.
+When all options have been processed (i.e., up to the first non-option
+argument),
+.Fn getopt
+returns \-1.
+.Sh RETURN VALUES
+The
+.Fn getopt
+function returns the next known option character in
+.Fa optstring .
+If
+.Fn getopt
+encounters a character not found in
+.Fa optstring
+or if it detects a missing option argument,
+it returns
+.Ql \&?
+(question mark).
+If
+.Fa optstring
+has a leading
+.Ql \&:
+then a missing option argument causes
+.Ql \&:
+to be returned instead of
+.Ql \&? .
+In either case, the variable
+.Va optopt
+is set to the character that caused the error.
+The
+.Fn getopt
+function returns \-1 when the argument list is exhausted.
+.Sh EXAMPLES
+.Bd -literal -compact
+#include <unistd.h>
+int bflag, ch, fd;
+
+bflag = 0;
+while ((ch = getopt(argc, argv, "bf:")) != -1) {
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'f':
+ if ((fd = open(optarg, O_RDONLY, 0)) \*[Lt] 0) {
+ (void)fprintf(stderr,
+ "myname: %s: %s\en", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+ case '?':
+ default:
+ usage();
+ }
+}
+argc -= optind;
+argv += optind;
+.Ed
+.Sh DIAGNOSTICS
+If the
+.Fn getopt
+function encounters a character not found in the string
+.Fa optstring
+or detects
+a missing option argument it writes an error message to the
+.Dv stderr
+and returns
+.Ql \&? .
+Setting
+.Va opterr
+to a zero will disable these error messages.
+If
+.Fa optstring
+has a leading
+.Ql \&:
+then a missing option argument causes a
+.Ql \&:
+to be returned in addition to suppressing any error messages.
+.Pp
+Option arguments are allowed to begin with
+.Dq Li \- ;
+this is reasonable but reduces the amount of error checking possible.
+.Sh SEE ALSO
+.Xr getopt 1 ,
+.Xr getopt_long 3 ,
+.Xr getsubopt 3
+.Sh STANDARDS
+The
+.Va optreset
+variable was added to make it possible to call the
+.Fn getopt
+function multiple times.
+This is an extension to the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Fn getopt
+function appeared in
+.Bx 4.3 .
+.Sh BUGS
+The
+.Fn getopt
+function was once specified to return
+.Dv EOF
+instead of \-1.
+This was changed by
+.St -p1003.2-92
+to decouple
+.Fn getopt
+from
+.In stdio.h .
+.Pp
+A single dash
+.Dq Li -
+may be specified as a character in
+.Fa optstring ,
+however it should
+.Em never
+have an argument associated with it.
+This allows
+.Fn getopt
+to be used with programs that expect
+.Dq Li -
+as an option flag.
+This practice is wrong, and should not be used in any current development.
+It is provided for backward compatibility
+.Em only .
+Care should be taken not to use
+.Ql \&-
+as the first character in
+.Fa optstring
+to avoid a semantic conflict with
+.Tn GNU
+.Fn getopt ,
+which assigns different meaning to an
+.Fa optstring
+that begins with a
+.Ql \&- .
+By default, a single dash causes
+.Fn getopt
+to return \-1.
+.Pp
+It is also possible to handle digits as option letters.
+This allows
+.Fn getopt
+to be used with programs that expect a number
+.Pq Dq Li \&-\&3
+as an option.
+This practice is wrong, and should not be used in any current development.
+It is provided for backward compatibility
+.Em only .
+The following code fragment works in most cases.
+.Bd -literal -offset indent
+int ch;
+long length;
+char *p, *ep;
+
+while ((ch = getopt(argc, argv, "0123456789")) != -1)
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ p = argv[optind - 1];
+ if (p[0] == '-' \*[Am]\*[Am] p[1] == ch \*[Am]\*[Am] !p[2]) {
+ length = ch - '0';
+ ep = "";
+ } else if (argv[optind] \*[Am]\*[Am] argv[optind][1] == ch) {
+ length = strtol((p = argv[optind] + 1),
+ \*[Am]ep, 10);
+ optind++;
+ optreset = 1;
+ } else
+ usage();
+ if (*ep != '\e0')
+ errx(EX_USAGE, "illegal number -- %s", p);
+ break;
+ }
+.Ed
diff --git a/lib/libc/stdlib/getopt.c b/lib/libc/stdlib/getopt.c
new file mode 100644
index 0000000..4d319a4
--- /dev/null
+++ b/lib/libc/stdlib/getopt.c
@@ -0,0 +1,135 @@
+/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == NULL)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(),
+ optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
diff --git a/lib/libc/stdlib/getopt_long.3 b/lib/libc/stdlib/getopt_long.3
new file mode 100644
index 0000000..352af08
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.3
@@ -0,0 +1,506 @@
+.\" $OpenBSD: getopt_long.3,v 1.10 2004/01/06 23:44:28 fgsch Exp $
+.\" $NetBSD: getopt_long.3,v 1.14 2003/08/07 16:43:40 agc Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)getopt.3 8.5 (Berkeley) 4/27/95
+.\" $FreeBSD$
+.\"
+.Dd April 1, 2000
+.Dt GETOPT_LONG 3
+.Os
+.Sh NAME
+.Nm getopt_long ,
+.Nm getopt_long_only
+.Nd get long options from command line argument list
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In getopt.h
+.Vt extern char *optarg ;
+.Vt extern int optind ;
+.Vt extern int optopt ;
+.Vt extern int opterr ;
+.Vt extern int optreset ;
+.Ft int
+.Fo getopt_long
+.Fa "int argc" "char * const *argv" "const char *optstring"
+.Fa "const struct option *longopts" "int *longindex"
+.Fc
+.Ft int
+.Fo getopt_long_only
+.Fa "int argc" "char * const *argv" "const char *optstring"
+.Fa "const struct option *longopts" "int *longindex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn getopt_long
+function is similar to
+.Xr getopt 3
+but it accepts options in two forms: words and characters.
+The
+.Fn getopt_long
+function provides a superset of the functionality of
+.Xr getopt 3 .
+The
+.Fn getopt_long
+function
+can be used in two ways.
+In the first way, every long option understood
+by the program has a corresponding short option, and the option
+structure is only used to translate from long options to short
+options.
+When used in this fashion,
+.Fn getopt_long
+behaves identically to
+.Xr getopt 3 .
+This is a good way to add long option processing to an existing program
+with the minimum of rewriting.
+.Pp
+In the second mechanism, a long option sets a flag in the
+.Vt option
+structure passed, or will store a pointer to the command line argument
+in the
+.Vt option
+structure passed to it for options that take arguments.
+Additionally,
+the long option's argument may be specified as a single argument with
+an equal sign, e.g.,
+.Pp
+.Dl "myprogram --myoption=somevalue"
+.Pp
+When a long option is processed, the call to
+.Fn getopt_long
+will return 0.
+For this reason, long option processing without
+shortcuts is not backwards compatible with
+.Xr getopt 3 .
+.Pp
+It is possible to combine these methods, providing for long options
+processing with short option equivalents for some options.
+Less
+frequently used options would be processed as long options only.
+.Pp
+The
+.Fn getopt_long
+call requires a structure to be initialized describing the long
+options.
+The structure is:
+.Bd -literal -offset indent
+struct option {
+ char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+.Ed
+.Pp
+The
+.Va name
+field should contain the option name without the leading double dash.
+.Pp
+The
+.Va has_arg
+field should be one of:
+.Pp
+.Bl -tag -width ".Dv optional_argument" -offset indent -compact
+.It Dv no_argument
+no argument to the option is expect
+.It Dv required_argument
+an argument to the option is required
+.It Dv optional_argument
+an argument to the option may be presented.
+.El
+.Pp
+If
+.Va flag
+is not
+.Dv NULL ,
+then the integer pointed to by it will be set to the
+value in the
+.Va val
+field.
+If the
+.Va flag
+field is
+.Dv NULL ,
+then the
+.Va val
+field will be returned.
+Setting
+.Va flag
+to
+.Dv NULL
+and setting
+.Va val
+to the corresponding short option will make this function act just
+like
+.Xr getopt 3 .
+.Pp
+If the
+.Fa longindex
+field is not
+.Dv NULL ,
+then the integer pointed to by it will be set to the index of the long
+option relative to
+.Fa longopts .
+.Pp
+The last element of the
+.Fa longopts
+array has to be filled with zeroes.
+.Pp
+The
+.Fn getopt_long_only
+function behaves identically to
+.Fn getopt_long
+with the exception that long options may start with
+.Ql -
+in addition to
+.Ql -- .
+If an option starting with
+.Ql -
+does not match a long option but does match a single-character option,
+the single-character option is returned.
+.Sh RETURN VALUES
+If the
+.Fa flag
+field in
+.Vt "struct option"
+is
+.Dv NULL ,
+.Fn getopt_long
+and
+.Fn getopt_long_only
+return the value specified in the
+.Fa val
+field, which is usually just the corresponding short option.
+If
+.Fa flag
+is not
+.Dv NULL ,
+these functions return 0 and store
+.Fa val
+in the location pointed to by
+.Fa flag .
+These functions return
+.Ql \&:
+if there was a missing option argument,
+.Ql \&?
+if the user specified an unknown or ambiguous option, and
+\-1 when the argument list has been exhausted.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev POSIXLY_CORRECT"
+.It Ev POSIXLY_CORRECT
+If set, option processing stops when the first non-option is found and
+a leading
+.Ql -
+or
+.Ql +
+in the
+.Fa optstring
+is ignored.
+.El
+.Sh EXAMPLES
+.Bd -literal -compact
+int bflag, ch, fd;
+int daggerset;
+
+/* options descriptor */
+static struct option longopts[] = {
+ { "buffy", no_argument, NULL, 'b' },
+ { "fluoride", required_argument, NULL, 'f' },
+ { "daggerset", no_argument, \*[Am]daggerset, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+bflag = 0;
+while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1)
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'f':
+ if ((fd = open(optarg, O_RDONLY, 0)) == -1)
+ err(1, "unable to open %s", optarg);
+ break;
+ case 0:
+ if (daggerset) {
+ fprintf(stderr,"Buffy will use her dagger to "
+ "apply fluoride to dracula's teeth\en");
+ }
+ break;
+ default:
+ usage();
+}
+argc -= optind;
+argv += optind;
+.Ed
+.Sh IMPLEMENTATION DIFFERENCES
+This section describes differences to the
+.Tn GNU
+implementation
+found in glibc-2.1.3:
+.Bl -bullet
+.\" .It
+.\" Handling of
+.\" .Ql -
+.\" as first char of option string in presence of
+.\" environment variable
+.\" .Ev POSIXLY_CORRECT :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" ignores
+.\" .Ev POSIXLY_CORRECT
+.\" and returns non-options as
+.\" arguments to option '\e1'.
+.\" .It Bx
+.\" honors
+.\" .Ev POSIXLY_CORRECT
+.\" and stops at the first non-option.
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql -
+.\" within the option string (not the first character):
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" treats a
+.\" .Ql -
+.\" on the command line as a non-argument.
+.\" .It Bx
+.\" a
+.\" .Ql -
+.\" within the option string matches a
+.\" .Ql -
+.\" (single dash) on the command line.
+.\" This functionality is provided for backward compatibility with
+.\" programs, such as
+.\" .Xr su 1 ,
+.\" that use
+.\" .Ql -
+.\" as an option flag.
+.\" This practice is wrong, and should not be used in any current development.
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql ::
+.\" in options string in presence of
+.\" .Ev POSIXLY_CORRECT :
+.\" .Bl -tag -width ".Bx"
+.\" .It Both
+.\" .Tn GNU
+.\" and
+.\" .Bx
+.\" ignore
+.\" .Ev POSIXLY_CORRECT
+.\" here and take
+.\" .Ql ::
+.\" to
+.\" mean the preceding option takes an optional argument.
+.\" .El
+.\" .It
+.\" Return value in case of missing argument if first character
+.\" (after
+.\" .Ql +
+.\" or
+.\" .Ql - )
+.\" in option string is not
+.\" .Ql \&: :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" returns
+.\" .Ql \&?
+.\" .It Bx
+.\" returns
+.\" .Ql \&:
+.\" (since
+.\" .Bx Ns 's
+.\" .Fn getopt
+.\" does).
+.\" .El
+.\" .It
+.\" Handling of
+.\" .Ql --a
+.\" in getopt:
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" parses this as option
+.\" .Ql - ,
+.\" option
+.\" .Ql a .
+.\" .It Bx
+.\" parses this as
+.\" .Ql -- ,
+.\" and returns \-1 (ignoring the
+.\" .Ql a ) .
+.\" (Because the original
+.\" .Fn getopt
+.\" does.)
+.\" .El
+.It
+Setting of
+.Va optopt
+for long options with
+.Va flag
+!=
+.Dv NULL :
+.Bl -tag -width ".Bx"
+.It Tn GNU
+sets
+.Va optopt
+to
+.Va val .
+.It Bx
+sets
+.Va optopt
+to 0 (since
+.Va val
+would never be returned).
+.El
+.\" .It
+.\" Handling of
+.\" .Ql -W
+.\" with
+.\" .Ql W;
+.\" in option string in
+.\" .Fn getopt
+.\" (not
+.\" .Fn getopt_long ) :
+.\" .Bl -tag -width ".Bx"
+.\" .It Tn GNU
+.\" causes a segfault.
+.\" .It Bx
+.\" no special handling is done;
+.\" .Ql W;
+.\" is interpreted as two separate options, neither of which take an argument.
+.\" .El
+.It
+Setting of
+.Va optarg
+for long options without an argument that are
+invoked via
+.Ql -W
+.Ql ( W;
+in option string):
+.Bl -tag -width ".Bx"
+.It Tn GNU
+sets
+.Va optarg
+to the option name (the argument of
+.Ql -W ) .
+.It Bx
+sets
+.Va optarg
+to
+.Dv NULL
+(the argument of the long option).
+.El
+.It
+Handling of
+.Ql -W
+with an argument that is not (a prefix to) a known
+long option
+.Ql ( W;
+in option string):
+.Bl -tag -width ".Bx"
+.It Tn GNU
+returns
+.Ql -W
+with
+.Va optarg
+set to the unknown option.
+.It Bx
+treats this as an error (unknown option) and returns
+.Ql \&?
+with
+.Va optopt
+set to 0 and
+.Va optarg
+set to
+.Dv NULL
+(as
+.Tn GNU Ns 's
+man page documents).
+.El
+.\" .It
+.\" The error messages are different.
+.It
+.Bx
+does not permute the argument vector at the same points in
+the calling sequence as
+.Tn GNU
+does.
+The aspects normally used by
+the caller (ordering after \-1 is returned, value of
+.Va optind
+relative
+to current positions) are the same, though.
+(We do fewer variable swaps.)
+.El
+.Sh SEE ALSO
+.Xr getopt 3
+.Sh HISTORY
+The
+.Fn getopt_long
+and
+.Fn getopt_long_only
+functions first appeared in
+.Tn GNU
+libiberty.
+The first
+.Bx
+implementation of
+.Fn getopt_long
+appeared in
+.Nx 1.5 ,
+the first
+.Bx
+implementation of
+.Fn getopt_long_only
+in
+.Ox 3.3 .
+.Fx
+first included
+.Fn getopt_long
+in
+.Fx 5.0 ,
+.Fn getopt_long_only
+in
+.Fx 5.2 .
+.Sh BUGS
+The
+.Fa argv
+argument is not really
+.Vt const
+as its elements may be permuted (unless
+.Ev POSIXLY_CORRECT
+is set).
+.Pp
+The implementation can completely replace
+.Xr getopt 3 ,
+but right now we are using separate code.
diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c
new file mode 100644
index 0000000..bf7a04a
--- /dev/null
+++ b/lib/libc/stdlib/getopt_long.c
@@ -0,0 +1,625 @@
+/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
+
+#if 0 /* we prefer to keep our getopt(3) */
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+#endif
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+#ifdef GNU_COMPATIBLE
+#define NO_PREFIX (-1)
+#define D_PREFIX 0
+#define DD_PREFIX 1
+#define W_PREFIX 2
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
+#ifdef GNU_COMPATIBLE
+static int dash_prefix = NO_PREFIX;
+static const char gnuoptchar[] = "invalid option -- %c";
+
+static const char recargstring[] = "option `%s%s' requires an argument";
+static const char ambig[] = "option `%s%.*s' is ambiguous";
+static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
+static const char illoptstring[] = "unrecognized option `%s%s'";
+#else
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptstring[] = "unknown option -- %s";
+#endif
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too, int flags)
+{
+ char *current_argv, *has_equal;
+#ifdef GNU_COMPATIBLE
+ char *current_dash;
+#endif
+ size_t current_argv_len;
+ int i, match, exact_match, second_partial_match;
+
+ current_argv = place;
+#ifdef GNU_COMPATIBLE
+ switch (dash_prefix) {
+ case D_PREFIX:
+ current_dash = "-";
+ break;
+ case DD_PREFIX:
+ current_dash = "--";
+ break;
+ case W_PREFIX:
+ current_dash = "-W ";
+ break;
+ default:
+ current_dash = "";
+ break;
+ }
+#endif
+ match = -1;
+ exact_match = 0;
+ second_partial_match = 0;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ exact_match = 1;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* first partial match */
+ match = i;
+ else if ((flags & FLAG_LONGONLY) ||
+ long_options[i].has_arg !=
+ long_options[match].has_arg ||
+ long_options[i].flag != long_options[match].flag ||
+ long_options[i].val != long_options[match].val)
+ second_partial_match = 1;
+ }
+ if (!exact_match && second_partial_match) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+#ifdef GNU_COMPATIBLE
+ return (BADCH);
+#else
+ return (BADARG);
+#endif
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring,
+#ifdef GNU_COMPATIBLE
+ current_dash,
+#endif
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ char *oli; /* option letter list index */
+ int optchar, short_too;
+ int posixly_correct; /* no static, can be changed on the fly */
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+#ifdef GNU_COMPATIBLE
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+#else
+ if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ else if (*options == '-')
+ flags |= FLAG_ALLARGS;
+#endif
+ if (*options == '+' || *options == '-')
+ options++;
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+#ifdef GNU_COMPATIBLE
+ place[1] == '\0') {
+#else
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+#endif
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+#ifdef GNU_COMPATIBLE
+ dash_prefix = D_PREFIX;
+#endif
+ if (*place == '-') {
+ place++; /* --foo long option */
+#ifdef GNU_COMPATIBLE
+ dash_prefix = DD_PREFIX;
+#endif
+ } else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too, flags);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+#ifdef GNU_COMPATIBLE
+ if (PRINT_ERROR)
+ warnx(posixly_correct ? illoptchar : gnuoptchar,
+ optchar);
+#else
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+#endif
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+#ifdef GNU_COMPATIBLE
+ dash_prefix = W_PREFIX;
+#endif
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0, flags);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
diff --git a/lib/libc/stdlib/getsubopt.3 b/lib/libc/stdlib/getsubopt.3
new file mode 100644
index 0000000..b624eff
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.3
@@ -0,0 +1,145 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)getsubopt.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD$
+.\"
+.Dd June 9, 1993
+.Dt GETSUBOPT 3
+.Os
+.Sh NAME
+.Nm getsubopt
+.Nd get sub options from an argument
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Vt extern char *suboptarg ;
+.Ft int
+.Fn getsubopt "char **optionp" "char * const *tokens" "char **valuep"
+.Sh DESCRIPTION
+The
+.Fn getsubopt
+function
+parses a string containing tokens delimited by one or more tab, space or
+comma
+.Pq Ql \&,
+characters.
+It is intended for use in parsing groups of option arguments provided
+as part of a utility command line.
+.Pp
+The argument
+.Fa optionp
+is a pointer to a pointer to the string.
+The argument
+.Fa tokens
+is a pointer to a
+.Dv NULL Ns -terminated
+array of pointers to strings.
+.Pp
+The
+.Fn getsubopt
+function
+returns the zero-based offset of the pointer in the
+.Fa tokens
+array referencing a string which matches the first token
+in the string, or, \-1 if the string contains no tokens or
+.Fa tokens
+does not contain a matching string.
+.Pp
+If the token is of the form ``name=value'', the location referenced by
+.Fa valuep
+will be set to point to the start of the ``value'' portion of the token.
+.Pp
+On return from
+.Fn getsubopt ,
+.Fa optionp
+will be set to point to the start of the next token in the string,
+or the null at the end of the string if no more tokens are present.
+The external variable
+.Fa suboptarg
+will be set to point to the start of the current token, or
+.Dv NULL
+if no
+tokens were present.
+The argument
+.Fa valuep
+will be set to point to the ``value'' portion of the token, or
+.Dv NULL
+if no ``value'' portion was present.
+.Sh EXAMPLES
+.Bd -literal -compact
+char *tokens[] = {
+ #define ONE 0
+ "one",
+ #define TWO 1
+ "two",
+ NULL
+};
+
+\&...
+
+extern char *optarg, *suboptarg;
+char *options, *value;
+
+while ((ch = getopt(argc, argv, "ab:")) != \-1) {
+ switch(ch) {
+ case 'a':
+ /* process ``a'' option */
+ break;
+ case 'b':
+ options = optarg;
+ while (*options) {
+ switch(getsubopt(&options, tokens, &value)) {
+ case ONE:
+ /* process ``one'' sub option */
+ break;
+ case TWO:
+ /* process ``two'' sub option */
+ if (!value)
+ error("no value for two");
+ i = atoi(value);
+ break;
+ case \-1:
+ if (suboptarg)
+ error("illegal sub option %s",
+ suboptarg);
+ else
+ error("missing sub option");
+ break;
+ }
+ break;
+ }
+.Ed
+.Sh SEE ALSO
+.Xr getopt 3 ,
+.Xr strsep 3
+.Sh HISTORY
+The
+.Fn getsubopt
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c
new file mode 100644
index 0000000..6d0ab75
--- /dev/null
+++ b/lib/libc/stdlib/getsubopt.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getsubopt.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The SVID interface to getsubopt provides no way of figuring out which
+ * part of the suboptions list wasn't matched. This makes error messages
+ * tricky... The extern variable suboptarg is a pointer to the token
+ * which didn't match.
+ */
+char *suboptarg;
+
+int
+getsubopt(optionp, tokens, valuep)
+ char **optionp, **valuep;
+ char * const *tokens;
+{
+ int cnt;
+ char *p;
+
+ suboptarg = *valuep = NULL;
+
+ if (!optionp || !*optionp)
+ return(-1);
+
+ /* skip leading white-space, commas */
+ for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+
+ if (!*p) {
+ *optionp = p;
+ return(-1);
+ }
+
+ /* save the start of the token, and skip the rest of the token. */
+ for (suboptarg = p;
+ *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
+
+ if (*p) {
+ /*
+ * If there's an equals sign, set the value pointer, and
+ * skip over the value part of the token. Terminate the
+ * token.
+ */
+ if (*p == '=') {
+ *p = '\0';
+ for (*valuep = ++p;
+ *p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
+ if (*p)
+ *p++ = '\0';
+ } else
+ *p++ = '\0';
+ /* Skip any whitespace or commas after this token. */
+ for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
+ }
+
+ /* set optionp for next round. */
+ *optionp = p;
+
+ for (cnt = 0; *tokens; ++tokens, ++cnt)
+ if (!strcmp(suboptarg, *tokens))
+ return(cnt);
+ return(-1);
+}
diff --git a/lib/libc/stdlib/grantpt.3 b/lib/libc/stdlib/grantpt.3
new file mode 100644
index 0000000..b4ad8c4
--- /dev/null
+++ b/lib/libc/stdlib/grantpt.3
@@ -0,0 +1,225 @@
+.\"
+.\" Copyright (c) 2002 The FreeBSD Project, Inc.
+.\" All rights reserved.
+.\"
+.\" This software includes code contributed to the FreeBSD Project
+.\" by Ryan Younce of North Carolina State University.
+.\"
+.\" 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.
+.\" 3. Neither the name of the FreeBSD Project nor the names of its
+.\" contributors may be used to endorse or promote products derived from
+.\" this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT 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 FREEBSD PROJECT
+.\" OR ITS 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$
+.\"
+.Dd December 23, 2002
+.Os
+.Dt GRANTPT 3
+.Sh NAME
+.Nm grantpt ,
+.Nm ptsname ,
+.Nm unlockpt ,
+.Nm posix_openpt
+.Nd pseudo-terminal access functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn grantpt "int fildes"
+.Ft "char *"
+.Fn ptsname "int fildes"
+.Ft int
+.Fn unlockpt "int fildes"
+.In fcntl.h
+.Ft int
+.Fn posix_openpt "int mode"
+.Sh DESCRIPTION
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions allow access to pseudo-terminal devices.
+The first three functions accept a file descriptor
+that references the master half of a pseudo-terminal pair.
+This file descriptor is created with
+.Fn posix_openpt .
+.Pp
+The
+.Fn grantpt
+function is used to establish ownership and permissions
+of the slave device counterpart to the master device
+specified with
+.Fa fildes .
+The slave device's ownership is set to the real user ID
+of the calling process, and the permissions are set to
+user readable-writable and group writable.
+The group owner of the slave device is also set to the
+group
+.Dq Li tty
+if it exists on the system; otherwise, it
+is left untouched.
+.Pp
+The
+.Fn ptsname
+function returns the full pathname of the slave device
+counterpart to the master device specified with
+.Fa fildes .
+This value can be used
+to subsequently open the appropriate slave after
+.Fn posix_openpt
+and
+.Fn grantpt
+have been called.
+.Pp
+The
+.Fn unlockpt
+function clears the lock held on the pseudo-terminal pair
+for the master device specified with
+.Fa fildes .
+.Pp
+The
+.Fn posix_openpt
+function opens the first available master pseudo-terminal
+device and returns a descriptor to it.
+The
+.Fa mode
+argument
+specifies the flags used for opening the device:
+.Bl -tag -width ".Dv O_NOCTTY"
+.It Dv O_RDWR
+Open for reading and writing.
+.It Dv O_NOCTTY
+If set, do not allow the terminal to become
+the controlling terminal for the calling process.
+.El
+.Sh RETURN VALUES
+.Rv -std grantpt unlockpt
+.Pp
+The
+.Fn ptsname
+function returns a pointer to the name
+of the slave device on success; otherwise a
+.Dv NULL
+pointer is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Pp
+The
+.Fn posix_openpt
+function returns a file descriptor to the first
+available master pseudo-terminal device on success;
+otherwise \-1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn grantpt ,
+.Fn ptsname ,
+and
+.Fn unlockpt
+functions may fail and set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa fildes
+is not a master pseudo-terminal device.
+.El
+.Pp
+In addition, the
+.Fn grantpt
+function may set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EACCES
+The slave pseudo-terminal device could not be accessed.
+.El
+.Pp
+The
+.Fn posix_openpt
+function may fail and set
+.Va errno
+to:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa mode
+consists of an invalid mode bit.
+.It Bq Er EAGAIN
+The system has no available pseudo-terminal devices.
+.El
+.Pp
+The
+.Fn grantpt ,
+.Fn ptsname ,
+and
+.Fn unlockpt
+functions may also fail and set
+.Va errno
+for any of the errors specified for the
+.Xr fstat 2
+system call.
+.Pp
+The
+.Fn posix_openpt
+function may also fail and set
+.Va errno
+for any of the errors specified for the
+.Xr open 2
+system call.
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr pty 4 ,
+.Xr tty 4
+.Sh STANDARDS
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn grantpt ,
+.Fn ptsname ,
+.Fn unlockpt ,
+and
+.Fn posix_openpt
+functions appeared in
+.Fx 5.0 .
+.Sh NOTES
+The purpose of the
+.Fn unlockpt
+function has no meaning in
+.Fx .
+.Pp
+The flag
+.Dv O_NOCTTY
+is included for compatibility; in
+.Fx ,
+opening a terminal does not cause it to become
+a process's controlling terminal.
diff --git a/lib/libc/stdlib/grantpt.c b/lib/libc/stdlib/grantpt.c
new file mode 100644
index 0000000..f6f31b2
--- /dev/null
+++ b/lib/libc/stdlib/grantpt.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2002 The FreeBSD Project, Inc.
+ * All rights reserved.
+ *
+ * This software includes code contributed to the FreeBSD Project
+ * by Ryan Younce of North Carolina State University.
+ *
+ * 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.
+ * 3. Neither the name of the FreeBSD Project nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT 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 FREEBSD PROJECT OR ITS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__FBSDID("$FreeBSD$");
+#endif /* not lint */
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+#define PTM_PREFIX "pty" /* pseudo tty master naming convention */
+#define PTS_PREFIX "tty" /* pseudo tty slave naming convention */
+#define NEWPTS_PREFIX "pts"
+#define PTMX "ptmx"
+
+/*
+ * The following are range values for pseudo TTY devices. Pseudo TTYs have a
+ * name of /dev/[pt]ty[p-sP-S][0-9a-v], yielding 256 combinations per major.
+ */
+#define PT_MAX 256
+#define PT_DEV1 "pqrsPQRS"
+#define PT_DEV2 "0123456789abcdefghijklmnopqrstuv"
+
+/*
+ * grantpt(3) support utility.
+ */
+#define _PATH_PTCHOWN "/usr/libexec/pt_chown"
+
+/*
+ * ISPTM(x) returns 0 for struct stat x if x is not a pty master.
+ * The bounds checking may be unnecessary but it does eliminate doubt.
+ */
+#define ISPTM(x) (S_ISCHR((x).st_mode) && \
+ minor((x).st_rdev) >= 0 && \
+ minor((x).st_rdev) < PT_MAX)
+
+
+static int
+is_pts(int fd)
+{
+ int nb;
+
+ return (_ioctl(fd, TIOCGPTN, &nb) == 0);
+}
+
+int
+__use_pts(void)
+{
+ int use_pts;
+ size_t len;
+ int error;
+
+ len = sizeof(use_pts);
+ error = sysctlbyname("kern.pts.enable", &use_pts, &len, NULL, 0);
+ if (error) {
+ struct stat sb;
+
+ if (stat("/dev/ptmx", &sb) != 0)
+ return (0);
+ use_pts = 1;
+ }
+ return (use_pts);
+}
+
+/*
+ * grantpt(): grant ownership of a slave pseudo-terminal device to the
+ * current user.
+ */
+
+int
+grantpt(int fildes)
+{
+ int retval, serrno, status;
+ pid_t pid, spid;
+ gid_t gid;
+ char *slave;
+ sigset_t oblock, nblock;
+ struct group *grp;
+
+ retval = -1;
+ serrno = errno;
+
+ if ((slave = ptsname(fildes)) != NULL) {
+ /*
+ * Block SIGCHLD.
+ */
+ (void)sigemptyset(&nblock);
+ (void)sigaddset(&nblock, SIGCHLD);
+ (void)_sigprocmask(SIG_BLOCK, &nblock, &oblock);
+
+ switch (pid = fork()) {
+ case -1:
+ break;
+ case 0: /* child */
+ /*
+ * pt_chown expects the master pseudo TTY to be its
+ * standard input.
+ */
+ (void)_dup2(fildes, STDIN_FILENO);
+ (void)_sigprocmask(SIG_SETMASK, &oblock, NULL);
+ execl(_PATH_PTCHOWN, _PATH_PTCHOWN, (char *)NULL);
+ _exit(EX_UNAVAILABLE);
+ /* NOTREACHED */
+ default: /* parent */
+ /*
+ * Just wait for the process. Error checking is
+ * done below.
+ */
+ while ((spid = _waitpid(pid, &status, 0)) == -1 &&
+ (errno == EINTR))
+ ;
+ if (spid != -1 && WIFEXITED(status) &&
+ WEXITSTATUS(status) == EX_OK)
+ retval = 0;
+ else
+ errno = EACCES;
+ break;
+ }
+
+ /*
+ * Restore process's signal mask.
+ */
+ (void)_sigprocmask(SIG_SETMASK, &oblock, NULL);
+
+ if (retval) {
+ /*
+ * pt_chown failed. Try to manually change the
+ * permissions for the slave.
+ */
+ gid = (grp = getgrnam("tty")) ? grp->gr_gid : -1;
+ if (chown(slave, getuid(), gid) == -1 ||
+ chmod(slave, S_IRUSR | S_IWUSR | S_IWGRP) == -1)
+ errno = EACCES;
+ else
+ retval = 0;
+ }
+ }
+
+ if (!retval)
+ errno = serrno;
+
+ return (retval);
+}
+
+/*
+ * posix_openpt(): open the first available master pseudo-terminal device
+ * and return descriptor.
+ */
+int
+posix_openpt(int oflag)
+{
+ char *mc1, *mc2, master[] = _PATH_DEV PTM_PREFIX "XY";
+ const char *pc1, *pc2;
+ int fildes, bflag, serrno;
+
+ fildes = -1;
+ bflag = 0;
+ serrno = errno;
+
+ /*
+ * Check flag validity. POSIX doesn't require it,
+ * but we still do so.
+ */
+ if (oflag & ~(O_RDWR | O_NOCTTY))
+ errno = EINVAL;
+ else {
+ if (__use_pts()) {
+ fildes = _open(_PATH_DEV PTMX, oflag);
+ return (fildes);
+ }
+ mc1 = master + strlen(_PATH_DEV PTM_PREFIX);
+ mc2 = mc1 + 1;
+
+ /* Cycle through all possible master PTY devices. */
+ for (pc1 = PT_DEV1; !bflag && (*mc1 = *pc1); ++pc1)
+ for (pc2 = PT_DEV2; (*mc2 = *pc2) != '\0'; ++pc2) {
+ /*
+ * Break out if we successfully open a PTY,
+ * or if open() fails due to limits.
+ */
+ if ((fildes = _open(master, oflag)) != -1 ||
+ (errno == EMFILE || errno == ENFILE)) {
+ ++bflag;
+ break;
+ }
+ }
+
+ if (fildes != -1)
+ errno = serrno;
+ else if (!bflag)
+ errno = EAGAIN;
+ }
+
+ return (fildes);
+}
+
+/*
+ * ptsname(): return the pathname of the slave pseudo-terminal device
+ * associated with the specified master.
+ */
+char *
+ptsname(int fildes)
+{
+ static char slave[] = _PATH_DEV PTS_PREFIX "XY";
+ static char new_slave[] = _PATH_DEV NEWPTS_PREFIX "4294967295";
+ char *retval;
+ struct stat sbuf;
+
+ retval = NULL;
+
+ if (_fstat(fildes, &sbuf) == 0) {
+ if (!ISPTM(sbuf))
+ errno = EINVAL;
+ else {
+ if (!is_pts(fildes)) {
+ (void)snprintf(slave, sizeof(slave),
+ _PATH_DEV PTS_PREFIX "%s",
+ devname(sbuf.st_rdev, S_IFCHR) +
+ strlen(PTM_PREFIX));
+ retval = slave;
+ } else {
+ (void)snprintf(new_slave, sizeof(new_slave),
+ _PATH_DEV NEWPTS_PREFIX "%s",
+ devname(sbuf.st_rdev, S_IFCHR) +
+ strlen(PTM_PREFIX));
+ retval = new_slave;
+ }
+ }
+ }
+
+ return (retval);
+}
+
+/*
+ * unlockpt(): unlock a pseudo-terminal device pair.
+ */
+int
+unlockpt(int fildes)
+{
+ int retval;
+ struct stat sbuf;
+
+ /*
+ * Unlocking a master/slave pseudo-terminal pair has no meaning in a
+ * non-streams PTY environment. However, we do ensure fildes is a
+ * valid master pseudo-terminal device.
+ */
+ if ((retval = _fstat(fildes, &sbuf)) == 0 && !ISPTM(sbuf)) {
+ errno = EINVAL;
+ retval = -1;
+ }
+
+ return (retval);
+}
diff --git a/lib/libc/stdlib/hcreate.3 b/lib/libc/stdlib/hcreate.3
new file mode 100644
index 0000000..38743af
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.3
@@ -0,0 +1,226 @@
+.\" $FreeBSD$
+.\"
+.Dd May 8, 2001
+.Os
+.Dt HCREATE 3
+.Sh NAME
+.Nm hcreate , hdestroy , hsearch
+.Nd manage hash search table
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft int
+.Fn hcreate "size_t nel"
+.Ft void
+.Fn hdestroy void
+.Ft ENTRY *
+.Fn hsearch "ENTRY item" "ACTION action"
+.Sh DESCRIPTION
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+functions manage hash search tables.
+.Pp
+The
+.Fn hcreate
+function allocates sufficient space for the table, and the application should
+ensure it is called before
+.Fn hsearch
+is used.
+The
+.Fa nel
+argument is an estimate of the maximum
+number of entries that the table should contain.
+This number may be adjusted upward by the
+algorithm in order to obtain certain mathematically favorable circumstances.
+.Pp
+The
+.Fn hdestroy
+function disposes of the search table, and may be followed by another call to
+.Fn hcreate .
+After the call to
+.Fn hdestroy ,
+the data can no longer be considered accessible.
+The
+.Fn hdestroy
+function calls
+.Xr free 3
+for each comparison key in the search table
+but not the data item associated with the key.
+.Pp
+The
+.Fn hsearch
+function is a hash-table search routine.
+It returns a pointer into a hash table
+indicating the location at which an entry can be found.
+The
+.Fa item
+argument is a structure of type
+.Vt ENTRY
+(defined in the
+.In search.h
+header) containing two pointers:
+.Fa item.key
+points to the comparison key (a
+.Vt "char *" ) ,
+and
+.Fa item.data
+(a
+.Vt "void *" )
+points to any other data to be associated with
+that key.
+The comparison function used by
+.Fn hsearch
+is
+.Xr strcmp 3 .
+The
+.Fa action
+argument is a
+member of an enumeration type
+.Vt ACTION
+indicating the disposition of the entry if it cannot be
+found in the table.
+.Dv ENTER
+indicates that the
+.Fa item
+should be inserted in the table at an
+appropriate point.
+.Dv FIND
+indicates that no entry should be made.
+Unsuccessful resolution is
+indicated by the return of a
+.Dv NULL
+pointer.
+.Pp
+The comparison key (passed to
+.Fn hsearch
+as
+.Fa item.key )
+must be allocated using
+.Xr malloc 3
+if
+.Fa action
+is
+.Dv ENTER
+and
+.Fn hdestroy
+is called.
+.Sh RETURN VALUES
+The
+.Fn hcreate
+function returns 0 if it cannot allocate sufficient space for the table;
+otherwise, it returns non-zero.
+.Pp
+The
+.Fn hdestroy
+function does not return a value.
+.Pp
+The
+.Fn hsearch
+function returns a
+.Dv NULL
+pointer if either the
+.Fa action
+is
+.Dv FIND
+and the
+.Fa item
+could not be found or the
+.Fa action
+is
+.Dv ENTER
+and the table is full.
+.Sh EXAMPLES
+The following example reads in strings followed by two numbers
+and stores them in a hash table, discarding duplicates.
+It then reads in strings and finds the matching entry in the hash
+table and prints it out.
+.Bd -literal
+#include <stdio.h>
+#include <search.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct info { /* This is the info stored in the table */
+ int age, room; /* other than the key. */
+};
+
+#define NUM_EMPL 5000 /* # of elements in search table. */
+
+int
+main(void)
+{
+ char str[BUFSIZ]; /* Space to read string */
+ struct info info_space[NUM_EMPL]; /* Space to store employee info. */
+ struct info *info_ptr = info_space; /* Next space in info_space. */
+ ENTRY item;
+ ENTRY *found_item; /* Name to look for in table. */
+ char name_to_find[30];
+ int i = 0;
+
+ /* Create table; no error checking is performed. */
+ (void) hcreate(NUM_EMPL);
+
+ while (scanf("%s%d%d", str, &info_ptr->age,
+ &info_ptr->room) != EOF && i++ < NUM_EMPL) {
+ /* Put information in structure, and structure in item. */
+ item.key = strdup(str);
+ item.data = info_ptr;
+ info_ptr++;
+ /* Put item into table. */
+ (void) hsearch(item, ENTER);
+ }
+
+ /* Access table. */
+ item.key = name_to_find;
+ while (scanf("%s", item.key) != EOF) {
+ if ((found_item = hsearch(item, FIND)) != NULL) {
+ /* If item is in the table. */
+ (void)printf("found %s, age = %d, room = %d\en",
+ found_item->key,
+ ((struct info *)found_item->data)->age,
+ ((struct info *)found_item->data)->room);
+ } else
+ (void)printf("no such employee %s\en", name_to_find);
+ }
+ hdestroy();
+ return 0;
+}
+.Ed
+.Sh ERRORS
+The
+.Fn hcreate
+and
+.Fn hsearch
+functions may fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient storage space is available.
+.El
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr lsearch 3 ,
+.Xr malloc 3 ,
+.Xr strcmp 3 ,
+.Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+functions conform to
+.St -xpg4.2 .
+.Sh HISTORY
+The
+.Fn hcreate ,
+.Fn hdestroy ,
+and
+.Fn hsearch
+functions first appeared in
+.At V .
+.Sh BUGS
+The interface permits the use of only one hash table at a time.
diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c
new file mode 100644
index 0000000..5878085
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.c
@@ -0,0 +1,185 @@
+/* $NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $ */
+
+/*
+ * Copyright (c) 2001 Christopher G. Demetriou
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.netbsd.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+ */
+
+/*
+ * hcreate() / hsearch() / hdestroy()
+ *
+ * SysV/XPG4 hash table functions.
+ *
+ * Implementation done based on NetBSD manual page and Solaris manual page,
+ * plus my own personal experience about how they're supposed to work.
+ *
+ * I tried to look at Knuth (as cited by the Solaris manual page), but
+ * nobody had a copy in the office, so...
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
+ * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
+ */
+struct internal_entry {
+ SLIST_ENTRY(internal_entry) link;
+ ENTRY ent;
+};
+SLIST_HEAD(internal_head, internal_entry);
+
+#define MIN_BUCKETS_LG2 4
+#define MIN_BUCKETS (1 << MIN_BUCKETS_LG2)
+
+/*
+ * max * sizeof internal_entry must fit into size_t.
+ * assumes internal_entry is <= 32 (2^5) bytes.
+ */
+#define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
+#define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2)
+
+/* Default hash function, from db/hash/hash_func.c */
+extern u_int32_t (*__default_hash)(const void *, size_t);
+
+static struct internal_head *htable;
+static size_t htablesize;
+
+int
+hcreate(size_t nel)
+{
+ size_t idx;
+ unsigned int p2;
+
+ /* Make sure this this isn't called when a table already exists. */
+ if (htable != NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* If nel is too small, make it min sized. */
+ if (nel < MIN_BUCKETS)
+ nel = MIN_BUCKETS;
+
+ /* If it's too large, cap it. */
+ if (nel > MAX_BUCKETS)
+ nel = MAX_BUCKETS;
+
+ /* If it's is not a power of two in size, round up. */
+ if ((nel & (nel - 1)) != 0) {
+ for (p2 = 0; nel != 0; p2++)
+ nel >>= 1;
+ nel = 1 << p2;
+ }
+
+ /* Allocate the table. */
+ htablesize = nel;
+ htable = malloc(htablesize * sizeof htable[0]);
+ if (htable == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ /* Initialize it. */
+ for (idx = 0; idx < htablesize; idx++)
+ SLIST_INIT(&htable[idx]);
+
+ return 1;
+}
+
+void
+hdestroy(void)
+{
+ struct internal_entry *ie;
+ size_t idx;
+
+ if (htable == NULL)
+ return;
+
+ for (idx = 0; idx < htablesize; idx++) {
+ while (!SLIST_EMPTY(&htable[idx])) {
+ ie = SLIST_FIRST(&htable[idx]);
+ SLIST_REMOVE_HEAD(&htable[idx], link);
+ free(ie->ent.key);
+ free(ie);
+ }
+ }
+ free(htable);
+ htable = NULL;
+}
+
+ENTRY *
+hsearch(ENTRY item, ACTION action)
+{
+ struct internal_head *head;
+ struct internal_entry *ie;
+ uint32_t hashval;
+ size_t len;
+
+ len = strlen(item.key);
+ hashval = (*__default_hash)(item.key, len);
+
+ head = &htable[hashval & (htablesize - 1)];
+ ie = SLIST_FIRST(head);
+ while (ie != NULL) {
+ if (strcmp(ie->ent.key, item.key) == 0)
+ break;
+ ie = SLIST_NEXT(ie, link);
+ }
+
+ if (ie != NULL)
+ return &ie->ent;
+ else if (action == FIND)
+ return NULL;
+
+ ie = malloc(sizeof *ie);
+ if (ie == NULL)
+ return NULL;
+ ie->ent.key = item.key;
+ ie->ent.data = item.data;
+
+ SLIST_INSERT_HEAD(head, ie, link);
+ return &ie->ent;
+}
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
new file mode 100644
index 0000000..135c48b
--- /dev/null
+++ b/lib/libc/stdlib/heapsort.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)heapsort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * 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
+ * common case (and, were it not, could easily be made so). Regardless, it
+ * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
+ * arithmetic gets lost in the time required for comparison function calls.
+ */
+#define SWAP(a, b, count, size, tmp) { \
+ count = size; \
+ do { \
+ tmp = *a; \
+ *a++ = *b; \
+ *b++ = tmp; \
+ } while (--count); \
+}
+
+/* Copy one block of size size to another. */
+#define COPY(a, b, count, size, tmp1, tmp2) { \
+ count = size; \
+ tmp1 = a; \
+ tmp2 = b; \
+ do { \
+ *tmp1++ = *tmp2++; \
+ } while (--count); \
+}
+
+/*
+ * Build the list into a heap, where a heap is defined such that for
+ * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.
+ *
+ * There two cases. If j == nmemb, select largest of Ki and Kj. If
+ * j < nmemb, select largest of Ki, Kj and Kj+1.
+ */
+#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \
+ 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) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ if (compar(child, par) <= 0) \
+ break; \
+ SWAP(par, child, count, size, tmp); \
+ } \
+}
+
+/*
+ * Select the top of the heap and 'heapify'. Since by far the most expensive
+ * action is the call to the compar function, a considerable optimization
+ * in the average case can be achieved due to the fact that k, the displaced
+ * elememt, is ususally quite small, so it would be preferable to first
+ * heapify, always maintaining the invariant that the larger child is copied
+ * over its parent's record.
+ *
+ * Then, starting from the *bottom* of the heap, finding k's correct place,
+ * again maintianing the invariant. As a result of the invariant no element
+ * is 'lost' when k is assigned its correct place in the heap.
+ *
+ * The time savings from this optimization are on the order of 15-20% for the
+ * average case. See Knuth, Vol. 3, page 158, problem 18.
+ *
+ * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.
+ */
+#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) { \
+ child += size; \
+ ++child_i; \
+ } \
+ par = base + par_i * size; \
+ COPY(par, child, count, size, tmp1, tmp2); \
+ } \
+ for (;;) { \
+ child_i = par_i; \
+ par_i = child_i / 2; \
+ child = base + child_i * size; \
+ par = base + par_i * size; \
+ if (child_i == 1 || compar(k, par) < 0) { \
+ COPY(child, k, count, size, tmp1, tmp2); \
+ break; \
+ } \
+ COPY(child, par, count, size, tmp1, tmp2); \
+ } \
+}
+
+/*
+ * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average
+ * and worst. While heapsort is faster than the worst case of quicksort,
+ * the BSD quicksort does median selection so that the chance of finding
+ * a data set that will trigger the worst case is nonexistent. Heapsort's
+ * only advantage over quicksort is that it requires little additional memory.
+ */
+int
+heapsort(vbase, nmemb, size, compar)
+ void *vbase;
+ size_t nmemb, size;
+ int (*compar)(const void *, const void *);
+{
+ int cnt, i, j, l;
+ char tmp, *tmp1, *tmp2;
+ char *base, *k, *p, *t;
+
+ if (nmemb <= 1)
+ return (0);
+
+ if (!size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((k = malloc(size)) == NULL)
+ return (-1);
+
+ /*
+ * Items are numbered from 1 to nmemb, so offset from size bytes
+ * below the starting address.
+ */
+ base = (char *)vbase - size;
+
+ for (l = nmemb / 2 + 1; --l;)
+ CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);
+
+ /*
+ * For each element of the heap, save the largest element into its
+ * final slot, save the displaced element (k), then recreate the
+ * heap.
+ */
+ while (nmemb > 1) {
+ COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);
+ COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);
+ --nmemb;
+ SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);
+ }
+ free(k);
+ return (0);
+}
diff --git a/lib/libc/stdlib/imaxabs.3 b/lib/libc/stdlib/imaxabs.3
new file mode 100644
index 0000000..430f873
--- /dev/null
+++ b/lib/libc/stdlib/imaxabs.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" 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$
+.\"
+.Dd November 14, 2001
+.Dt IMAXABS 3
+.Os
+.Sh NAME
+.Nm imaxabs
+.Nd returns absolute value
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In inttypes.h
+.Ft intmax_t
+.Fn imaxabs "intmax_t j"
+.Sh DESCRIPTION
+The
+.Fn imaxabs
+function returns the absolute value of
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr hypot 3 ,
+.Xr labs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn imaxabs
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn imaxabs
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/imaxabs.c b/lib/libc/stdlib/imaxabs.c
new file mode 100644
index 0000000..35e3dee
--- /dev/null
+++ b/lib/libc/stdlib/imaxabs.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <inttypes.h>
+
+intmax_t
+imaxabs(intmax_t j)
+{
+ return (j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/imaxdiv.3 b/lib/libc/stdlib/imaxdiv.3
new file mode 100644
index 0000000..0ee0971
--- /dev/null
+++ b/lib/libc/stdlib/imaxdiv.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" 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$
+.\"
+.Dd November 14, 2001
+.Dt IMAXDIV 3
+.Os
+.Sh NAME
+.Nm imaxdiv
+.Nd returns quotient and remainder
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In inttypes.h
+.Ft imaxdiv_t
+.Fn imaxdiv "intmax_t numer" "intmax_t denom"
+.Sh DESCRIPTION
+The
+.Fn imaxdiv
+function computes the value of
+.Fa numer
+divided by
+.Fa denom
+and returns the stored result in the form of the
+.Vt imaxdiv_t
+type.
+.Pp
+The
+.Vt imaxdiv_t
+type is defined as:
+.Bd -literal -offset indent
+typedef struct {
+ intmax_t quot; /* Quotient. */
+ intmax_t rem; /* Remainder. */
+} imaxdiv_t;
+.Ed
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr ldiv 3 ,
+.Xr lldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn imaxdiv
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn imaxdiv
+function first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/stdlib/imaxdiv.c b/lib/libc/stdlib/imaxdiv.c
new file mode 100644
index 0000000..7dae467
--- /dev/null
+++ b/lib/libc/stdlib/imaxdiv.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <inttypes.h>
+
+/* See comments in div.c for implementation details. */
+imaxdiv_t
+imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t retval;
+
+ retval.quot = numer / denom;
+ retval.rem = numer % denom;
+ if (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+ return (retval);
+}
diff --git a/lib/libc/stdlib/insque.3 b/lib/libc/stdlib/insque.3
new file mode 100644
index 0000000..a54434c
--- /dev/null
+++ b/lib/libc/stdlib/insque.3
@@ -0,0 +1,61 @@
+.\"
+.\" Initial implementation:
+.\" Copyright (c) 2002 Robert Drehmel
+.\" All rights reserved.
+.\"
+.\" As long as the above copyright statement and this notice remain
+.\" unchanged, you can do what ever you want with this file.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 10, 2002
+.Dt INSQUE 3
+.Os
+.Sh NAME
+.Nm insque ,
+.Nm remque
+.Nd doubly-linked list management
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft void
+.Fn insque "void *element1" "void *pred"
+.Ft void
+.Fn remque "void *element"
+.Sh DESCRIPTION
+The
+.Fn insque
+and
+.Fn remque
+functions encapsulate the ever-repeating task of doing insertion and
+removal operations on doubly linked lists.
+The functions expect their
+arguments to point to a structure whose first and second members are
+pointers to the next and previous element, respectively.
+The
+.Fn insque
+function also allows the
+.Fa pred
+argument to be a
+.Dv NULL
+pointer for the initialization of a new list's
+head element.
+.Sh STANDARDS
+The
+.Fn insque
+and
+.Fn remque
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn insque
+and
+.Fn remque
+functions appeared in
+.Bx 4.2 .
+In
+.Fx 5.0 ,
+they reappeared conforming to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdlib/insque.c b/lib/libc/stdlib/insque.c
new file mode 100644
index 0000000..388e4d5
--- /dev/null
+++ b/lib/libc/stdlib/insque.c
@@ -0,0 +1,47 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#ifdef DEBUG
+#include <stdio.h>
+#else
+#include <stdlib.h> /* for NULL */
+#endif
+
+void
+insque(void *element, void *pred)
+{
+ struct que_elem *prev, *next, *elem;
+
+ elem = (struct que_elem *)element;
+ prev = (struct que_elem *)pred;
+
+ if (prev == NULL) {
+ elem->prev = elem->next = NULL;
+ return;
+ }
+
+ next = prev->next;
+ if (next != NULL) {
+#ifdef DEBUG
+ if (next->prev != prev) {
+ fprintf(stderr, "insque: Inconsistency detected:"
+ " next(%p)->prev(%p) != prev(%p)\n",
+ next, next->prev, prev);
+ }
+#endif
+ next->prev = elem;
+ }
+ prev->next = elem;
+ elem->prev = prev;
+ elem->next = next;
+}
diff --git a/lib/libc/stdlib/l64a.c b/lib/libc/stdlib/l64a.c
new file mode 100644
index 0000000..bc10553
--- /dev/null
+++ b/lib/libc/stdlib/l64a.c
@@ -0,0 +1,52 @@
+/*
+ * Written by J.T. Conklin <jtc@NetBSD.org>.
+ * Public domain.
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: l64a.c,v 1.13 2003/07/26 19:24:54 salo Exp $");
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+#define ADOT 46 /* ASCII '.' */
+#define ASLASH ADOT + 1 /* ASCII '/' */
+#define A0 48 /* ASCII '0' */
+#define AA 65 /* ASCII 'A' */
+#define Aa 97 /* ASCII 'a' */
+
+char *
+l64a(long value)
+{
+ static char buf[8];
+
+ (void)l64a_r(value, buf, sizeof(buf));
+ return (buf);
+}
+
+int
+l64a_r(long value, char *buffer, int buflen)
+{
+ long v;
+ int digit;
+
+ v = value & (long)0xffffffff;
+ for (; v != 0 && buflen > 1; buffer++, buflen--) {
+ digit = v & 0x3f;
+ if (digit < 2)
+ *buffer = digit + ADOT;
+ else if (digit < 12)
+ *buffer = digit + A0 - 2;
+ else if (digit < 38)
+ *buffer = digit + AA - 12;
+ else
+ *buffer = digit + Aa - 38;
+ v >>= 6;
+ }
+ return (v == 0 ? 0 : -1);
+}
diff --git a/lib/libc/stdlib/labs.3 b/lib/libc/stdlib/labs.3
new file mode 100644
index 0000000..b714fe3
--- /dev/null
+++ b/lib/libc/stdlib/labs.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)labs.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LABS 3
+.Os
+.Sh NAME
+.Nm labs
+.Nd return the absolute value of a long integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn labs "long j"
+.Sh DESCRIPTION
+The
+.Fn labs
+function
+returns the absolute value of the long integer
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr cabs 3 ,
+.Xr floor 3 ,
+.Xr imaxabs 3 ,
+.Xr llabs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn labs
+function
+conforms to
+.St -isoC .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/labs.c b/lib/libc/stdlib/labs.c
new file mode 100644
index 0000000..d22975e
--- /dev/null
+++ b/lib/libc/stdlib/labs.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)labs.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long
+labs(j)
+ long j;
+{
+ return(j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/ldiv.3 b/lib/libc/stdlib/ldiv.3
new file mode 100644
index 0000000..221e68d
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.3
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)ldiv.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 14, 2001
+.Dt LDIV 3
+.Os
+.Sh NAME
+.Nm ldiv
+.Nd return quotient and remainder from division
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft ldiv_t
+.Fn ldiv "long num" "long denom"
+.Sh DESCRIPTION
+The
+.Fn ldiv
+function
+computes the value
+.Fa num Ns / Ns Fa denom
+and returns the quotient and remainder in a structure named
+.Vt ldiv_t
+that contains two
+.Vt long
+members named
+.Va quot
+and
+.Va rem .
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr imaxdiv 3 ,
+.Xr lldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn ldiv
+function
+conforms to
+.St -isoC-99 .
diff --git a/lib/libc/stdlib/ldiv.c b/lib/libc/stdlib/ldiv.c
new file mode 100644
index 0000000..0311d06
--- /dev/null
+++ b/lib/libc/stdlib/ldiv.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h> /* ldiv_t */
+
+ldiv_t
+ldiv(num, denom)
+ long num, denom;
+{
+ ldiv_t r;
+
+ /* see div.c for comments */
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ if (num >= 0 && r.rem < 0) {
+ r.quot++;
+ r.rem -= denom;
+ }
+ return (r);
+}
diff --git a/lib/libc/stdlib/llabs.3 b/lib/libc/stdlib/llabs.3
new file mode 100644
index 0000000..8c031a9
--- /dev/null
+++ b/lib/libc/stdlib/llabs.3
@@ -0,0 +1,62 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" 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$
+.\"
+.Dd November 14, 2001
+.Dt LLABS 3
+.Os
+.Sh NAME
+.Nm llabs
+.Nd returns absolute value
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft "long long"
+.Fn llabs "long long j"
+.Sh DESCRIPTION
+The
+.Fn llabs
+function returns the absolute value of
+.Fa j .
+.Sh SEE ALSO
+.Xr abs 3 ,
+.Xr fabs 3 ,
+.Xr hypot 3 ,
+.Xr imaxabs 3 ,
+.Xr labs 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn llabs
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn llabs
+function first appeared in
+.Fx 5.0 .
+.Sh BUGS
+The absolute value of the most negative integer remains negative.
diff --git a/lib/libc/stdlib/llabs.c b/lib/libc/stdlib/llabs.c
new file mode 100644
index 0000000..2bfbada
--- /dev/null
+++ b/lib/libc/stdlib/llabs.c
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+long long
+llabs(long long j)
+{
+ return (j < 0 ? -j : j);
+}
diff --git a/lib/libc/stdlib/lldiv.3 b/lib/libc/stdlib/lldiv.3
new file mode 100644
index 0000000..976a997
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+.\" 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$
+.\"
+.Dd November 14, 2001
+.Dt LLDIV 3
+.Os
+.Sh NAME
+.Nm lldiv
+.Nd returns quotient and remainder
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft lldiv_t
+.Fn lldiv "long long numer" "long long denom"
+.Sh DESCRIPTION
+The
+.Fn lldiv
+function computes the value of
+.Fa numer
+divided by
+.Fa denom
+and returns the stored result in the form of the
+.Vt lldiv_t
+type.
+.Pp
+The
+.Vt lldiv_t
+type is defined as:
+.Bd -literal -offset indent
+typedef struct {
+ long long quot; /* Quotient. */
+ long long rem; /* Remainder. */
+} lldiv_t;
+.Ed
+.Sh SEE ALSO
+.Xr div 3 ,
+.Xr imaxdiv 3 ,
+.Xr ldiv 3 ,
+.Xr math 3
+.Sh STANDARDS
+The
+.Fn lldiv
+function conforms to
+.St -isoC-99 .
+.Sh HISTORY
+The
+.Fn lldiv
+function first appeared in
+.Fx 5.0 .
diff --git a/lib/libc/stdlib/lldiv.c b/lib/libc/stdlib/lldiv.c
new file mode 100644
index 0000000..b34b65e
--- /dev/null
+++ b/lib/libc/stdlib/lldiv.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+/* See comments in div.c for implementation details. */
+lldiv_t
+lldiv(long long numer, long long denom)
+{
+ lldiv_t retval;
+
+ retval.quot = numer / denom;
+ retval.rem = numer % denom;
+ if (numer >= 0 && retval.rem < 0) {
+ retval.quot++;
+ retval.rem -= denom;
+ }
+ return (retval);
+}
diff --git a/lib/libc/stdlib/lsearch.3 b/lib/libc/stdlib/lsearch.3
new file mode 100644
index 0000000..5e76724
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.3
@@ -0,0 +1,105 @@
+.\"
+.\" Initial implementation:
+.\" Copyright (c) 2002 Robert Drehmel
+.\" All rights reserved.
+.\"
+.\" As long as the above copyright statement and this notice remain
+.\" unchanged, you can do what ever you want with this file.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 11, 2002
+.Dt LSEARCH 3
+.Os
+.Sh NAME
+.Nm lsearch ,
+.Nm lfind
+.Nd linear search and append
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In search.h
+.Ft "void *"
+.Fo lsearch
+.Fa "const void *key" "void *base" "size_t *nelp" "size_t width"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Ft "void *"
+.Fo lfind
+.Fa "const void *key" "const void *base" "size_t *nelp" "size_t width"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *\*[rp]"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn lsearch
+and
+.Fn lfind
+functions walk linearly through an array and compare each element with
+the one to be sought using a supplied comparison function.
+.Pp
+The
+.Fa key
+argument
+points to an element that matches the one that is searched.
+The array's address in memory is denoted by the
+.Fa base
+argument.
+The width of one element (i.e., the size as returned by
+.Fn sizeof )
+is passed as the
+.Fa width
+argument.
+The number of valid elements contained in the array (not the number of
+elements the array has space reserved for) is given in the integer pointed
+to by
+.Fa nelp .
+The
+.Fa compar
+argument points to a function which compares its two arguments and returns
+zero if they are matching, and non-zero otherwise.
+.Pp
+If no matching element was found in the array,
+.Fn lsearch
+copies
+.Fa key
+into the position after the last element and increments the
+integer pointed to by
+.Fa nelp .
+.Sh RETURN VALUES
+The
+.Fn lsearch
+and
+.Fn lfind
+functions
+return a pointer to the first element found.
+If no element was found,
+.Fn lsearch
+returns a pointer to the newly added element, whereas
+.Fn lfind
+returns
+.Dv NULL .
+Both functions return
+.Dv NULL
+if an error occurs.
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr hsearch 3 ,
+.Xr tsearch 3
+.Sh STANDARDS
+The
+.Fn lsearch
+and
+.Fn lfind
+functions conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn lsearch
+and
+.Fn lfind
+functions appeared in
+.Bx 4.2 .
+In
+.Fx 5.0 ,
+they reappeared conforming to
+.St -p1003.1-2001 .
diff --git a/lib/libc/stdlib/lsearch.c b/lib/libc/stdlib/lsearch.c
new file mode 100644
index 0000000..e4d1dd5
--- /dev/null
+++ b/lib/libc/stdlib/lsearch.c
@@ -0,0 +1,64 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/types.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdint.h> /* for uint8_t */
+#include <stdlib.h> /* for NULL */
+#include <string.h> /* for memcpy() prototype */
+
+static void *lwork(const void *, const void *, size_t *, size_t,
+ int (*)(const void *, const void *), int);
+
+void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *))
+{
+
+ return (lwork(key, base, nelp, width, compar, 1));
+}
+
+void *lfind(const void *key, const void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *))
+{
+
+ return (lwork(key, base, nelp, width, compar, 0));
+}
+
+static void *
+lwork(const void *key, const void *base, size_t *nelp, size_t width,
+ int (*compar)(const void *, const void *), int addelem)
+{
+ uint8_t *ep, *endp;
+
+ /*
+ * Cast to an integer value first to avoid the warning for removing
+ * 'const' via a cast.
+ */
+ ep = (uint8_t *)(uintptr_t)base;
+ for (endp = (uint8_t *)(ep + width * *nelp); ep < endp; ep += width) {
+ if (compar(key, ep) == 0)
+ return (ep);
+ }
+
+ /* lfind() shall return when the key was not found. */
+ if (!addelem)
+ return (NULL);
+
+ /*
+ * lsearch() adds the key to the end of the table and increments
+ * the number of elements.
+ */
+ memcpy(endp, key, width);
+ ++*nelp;
+
+ return (endp);
+}
diff --git a/lib/libc/stdlib/malloc.3 b/lib/libc/stdlib/malloc.3
new file mode 100644
index 0000000..7a85da8
--- /dev/null
+++ b/lib/libc/stdlib/malloc.3
@@ -0,0 +1,490 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)malloc.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 27, 2007
+.Dt MALLOC 3
+.Os
+.Sh NAME
+.Nm malloc , calloc , realloc , free , reallocf , malloc_usable_size
+.Nd general purpose memory allocation functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn malloc "size_t size"
+.Ft void *
+.Fn calloc "size_t number" "size_t size"
+.Ft void *
+.Fn realloc "void *ptr" "size_t size"
+.Ft void *
+.Fn reallocf "void *ptr" "size_t size"
+.Ft void
+.Fn free "void *ptr"
+.Ft const char *
+.Va _malloc_options ;
+.Ft void
+.Fo \*(lp*_malloc_message\*(rp
+.Fa "const char *p1" "const char *p2" "const char *p3" "const char *p4"
+.Fc
+.In malloc_np.h
+.Ft size_t
+.Fn malloc_usable_size "const void *ptr"
+.Sh DESCRIPTION
+The
+.Fn malloc
+function allocates
+.Fa size
+bytes of uninitialized memory.
+The allocated space is suitably aligned (after possible pointer coercion)
+for storage of any type of object.
+.Pp
+The
+.Fn calloc
+function allocates space for
+.Fa number
+objects,
+each
+.Fa size
+bytes in length.
+The result is identical to calling
+.Fn malloc
+with an argument of
+.Dq "number * size" ,
+with the exception that the allocated memory is explicitly initialized
+to zero bytes.
+.Pp
+The
+.Fn realloc
+function changes the size of the previously allocated memory referenced by
+.Fa ptr
+to
+.Fa size
+bytes.
+The contents of the memory are unchanged up to the lesser of the new and
+old sizes.
+If the new size is larger,
+the value of the newly allocated portion of the memory is undefined.
+Upon success, the memory referenced by
+.Fa ptr
+is freed and a pointer to the newly allocated memory is returned.
+Note that
+.Fn realloc
+and
+.Fn reallocf
+may move the memory allocation, resulting in a different return value than
+.Fa ptr .
+If
+.Fa ptr
+is
+.Dv NULL ,
+the
+.Fn realloc
+function behaves identically to
+.Fn malloc
+for the specified size.
+.Pp
+The
+.Fn reallocf
+function is identical to the
+.Fn realloc
+function, except that it
+will free the passed pointer when the requested memory cannot be allocated.
+This is a
+.Fx
+specific API designed to ease the problems with traditional coding styles
+for realloc causing memory leaks in libraries.
+.Pp
+The
+.Fn free
+function causes the allocated memory referenced by
+.Fa ptr
+to be made available for future allocations.
+If
+.Fa ptr
+is
+.Dv NULL ,
+no action occurs.
+.Pp
+The
+.Fn malloc_usable_size
+function returns the usable size of the allocation pointed to by
+.Fa ptr .
+The return value may be larger than the size that was requested during
+allocation.
+The
+.Fn malloc_usable_size
+function is not a mechanism for in-place
+.Fn realloc ;
+rather it is provided solely as a tool for introspection purposes.
+Any discrepancy between the requested allocation size and the size reported by
+.Fn malloc_usable_size
+should not be depended on, since such behavior is entirely
+implementation-dependent.
+.Sh TUNING
+Once, when the first call is made to one of these memory allocation
+routines, various flags will be set or reset, which affect the
+workings of this allocator implementation.
+.Pp
+The
+.Dq name
+of the file referenced by the symbolic link named
+.Pa /etc/malloc.conf ,
+the value of the environment variable
+.Ev MALLOC_OPTIONS ,
+and the string pointed to by the global variable
+.Va _malloc_options
+will be interpreted, in that order, character by character as flags.
+.Pp
+Most flags are single letters,
+where uppercase indicates that the behavior is set, or on,
+and lowercase means that the behavior is not set, or off.
+.Bl -tag -width indent
+.It A
+All warnings (except for the warning about unknown
+flags being set) become fatal.
+The process will call
+.Xr abort 3
+in these cases.
+.It H
+Use
+.Xr madvise 2
+when pages within a chunk are no longer in use, but the chunk as a whole cannot
+yet be deallocated.
+This is primarily of use when swapping is a real possibility, due to the high
+overhead of the
+.Fn madvise
+system call.
+.It J
+Each byte of new memory allocated by
+.Fn malloc ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0xa5.
+All memory returned by
+.Fn free ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0x5a.
+This is intended for debugging and will impact performance negatively.
+.It K
+Increase/decrease the virtual memory chunk size by a factor of two.
+The default chunk size is 1 MB.
+This option can be specified multiple times.
+.It N
+Increase/decrease the number of arenas by a factor of two.
+The default number of arenas is four times the number of CPUs, or one if there
+is a single CPU.
+This option can be specified multiple times.
+.It P
+Various statistics are printed at program exit via an
+.Xr atexit 3
+function.
+This has the potential to cause deadlock for a multi-threaded process that exits
+while one or more threads are executing in the memory allocation functions.
+Therefore, this option should only be used with care; it is primarily intended
+as a performance tuning aid during application development.
+.It Q
+Increase/decrease the size of the allocation quantum by a factor of two.
+The default quantum is the minimum allowed by the architecture (typically 8 or
+16 bytes).
+This option can be specified multiple times.
+.It S
+Increase/decrease the size of the maximum size class that is a multiple of the
+quantum by a factor of two.
+Above this size, power-of-two spacing is used for size classes.
+The default value is 512 bytes.
+This option can be specified multiple times.
+.It U
+Generate
+.Dq utrace
+entries for
+.Xr ktrace 1 ,
+for all operations.
+Consult the source for details on this option.
+.It V
+Attempting to allocate zero bytes will return a
+.Dv NULL
+pointer instead of
+a valid pointer.
+(The default behavior is to make a minimal allocation and return a
+pointer to it.)
+This option is provided for System V compatibility.
+This option is incompatible with the
+.Dq X
+option.
+.It X
+Rather than return failure for any allocation function,
+display a diagnostic message on
+.Dv stderr
+and cause the program to drop
+core (using
+.Xr abort 3 ) .
+This option should be set at compile time by including the following in
+the source code:
+.Bd -literal -offset indent
+_malloc_options = "X";
+.Ed
+.It Z
+Each byte of new memory allocated by
+.Fn malloc ,
+.Fn realloc
+or
+.Fn reallocf
+will be initialized to 0.
+Note that this initialization only happens once for each byte, so
+.Fn realloc
+and
+.Fn reallocf
+calls do not zero memory that was previously allocated.
+This is intended for debugging and will impact performance negatively.
+.El
+.Pp
+The
+.Dq J
+and
+.Dq Z
+options are intended for testing and debugging.
+An application which changes its behavior when these options are used
+is flawed.
+.Sh IMPLEMENTATION NOTES
+This allocator uses multiple arenas in order to reduce lock contention for
+threaded programs on multi-processor systems.
+This works well with regard to threading scalability, but incurs some costs.
+There is a small fixed per-arena overhead, and additionally, arenas manage
+memory completely independently of each other, which means a small fixed
+increase in overall memory fragmentation.
+These overheads are not generally an issue, given the number of arenas normally
+used.
+Note that using substantially more arenas than the default is not likely to
+improve performance, mainly due to reduced cache performance.
+However, it may make sense to reduce the number of arenas if an application
+does not make much use of the allocation functions.
+.Pp
+Memory is conceptually broken into equal-sized chunks, where the chunk size is
+a power of two that is greater than the page size.
+Chunks are always aligned to multiples of the chunk size.
+This alignment makes it possible to find metadata for user objects very
+quickly.
+.Pp
+User objects are broken into three categories according to size: small, large,
+and huge.
+Small objects are no larger than one half of a page.
+Large objects are smaller than the chunk size.
+Huge objects are a multiple of the chunk size.
+Small and large objects are managed by arenas; huge objects are managed
+separately in a single data structure that is shared by all threads.
+Huge objects are used by applications infrequently enough that this single
+data structure is not a scalability issue.
+.Pp
+Each chunk that is managed by an arena tracks its contents in a page map as
+runs of contiguous pages (unused, backing a set of small objects, or backing
+one large object).
+The combination of chunk alignment and chunk page maps makes it possible to
+determine all metadata regarding small and large allocations in constant time.
+.Pp
+Small objects are managed in groups by page runs.
+Each run maintains a bitmap that tracks which regions are in use.
+Allocation requests that are no more than half the quantum (see the
+.Dq Q
+option) are rounded up to the nearest power of two (typically 2, 4, or 8).
+Allocation requests that are more than half the quantum, but no more than the
+maximum quantum-multiple size class (see the
+.Dq S
+option) are rounded up to the nearest multiple of the quantum.
+Allocation requests that are larger than the maximum quantum-multiple size
+class, but no larger than one half of a page, are rounded up to the nearest
+power of two.
+Allocation requests that are larger than half of a page, but small enough to
+fit in an arena-managed chunk (see the
+.Dq K
+option), are rounded up to the nearest run size.
+Allocation requests that are too large to fit in an arena-managed chunk are
+rounded up to the nearest multiple of the chunk size.
+.Pp
+Allocations are packed tightly together, which can be an issue for
+multi-threaded applications.
+If you need to assure that allocations do not suffer from cache line sharing,
+round your allocation requests up to the nearest multiple of the cache line
+size.
+.Sh DEBUGGING MALLOC PROBLEMS
+The first thing to do is to set the
+.Dq A
+option.
+This option forces a coredump (if possible) at the first sign of trouble,
+rather than the normal policy of trying to continue if at all possible.
+.Pp
+It is probably also a good idea to recompile the program with suitable
+options and symbols for debugger support.
+.Pp
+If the program starts to give unusual results, coredump or generally behave
+differently without emitting any of the messages mentioned in the next
+section, it is likely because it depends on the storage being filled with
+zero bytes.
+Try running it with the
+.Dq Z
+option set;
+if that improves the situation, this diagnosis has been confirmed.
+If the program still misbehaves,
+the likely problem is accessing memory outside the allocated area.
+.Pp
+Alternatively, if the symptoms are not easy to reproduce, setting the
+.Dq J
+option may help provoke the problem.
+.Pp
+In truly difficult cases, the
+.Dq U
+option, if supported by the kernel, can provide a detailed trace of
+all calls made to these functions.
+.Pp
+Unfortunately this implementation does not provide much detail about
+the problems it detects; the performance impact for storing such information
+would be prohibitive.
+There are a number of allocator implementations available on the Internet
+which focus on detecting and pinpointing problems by trading performance for
+extra sanity checks and detailed diagnostics.
+.Sh DIAGNOSTIC MESSAGES
+If any of the memory allocation/deallocation functions detect an error or
+warning condition, a message will be printed to file descriptor
+.Dv STDERR_FILENO .
+Errors will result in the process dumping core.
+If the
+.Dq A
+option is set, all warnings are treated as errors.
+.Pp
+The
+.Va _malloc_message
+variable allows the programmer to override the function which emits
+the text strings forming the errors and warnings if for some reason
+the
+.Dv stderr
+file descriptor is not suitable for this.
+Please note that doing anything which tries to allocate memory in
+this function is likely to result in a crash or deadlock.
+.Pp
+All messages are prefixed by
+.Dq Ao Ar progname Ac Ns Li : (malloc) .
+.Sh RETURN VALUES
+The
+.Fn malloc
+and
+.Fn calloc
+functions return a pointer to the allocated memory if successful; otherwise
+a
+.Dv NULL
+pointer is returned and
+.Va errno
+is set to
+.Er ENOMEM .
+.Pp
+The
+.Fn realloc
+and
+.Fn reallocf
+functions return a pointer, possibly identical to
+.Fa ptr ,
+to the allocated memory
+if successful; otherwise a
+.Dv NULL
+pointer is returned, and
+.Va errno
+is set to
+.Er ENOMEM
+if the error was the result of an allocation failure.
+The
+.Fn realloc
+function always leaves the original buffer intact
+when an error occurs, whereas
+.Fn reallocf
+deallocates it in this case.
+.Pp
+The
+.Fn free
+function returns no value.
+.Pp
+The
+.Fn malloc_usable_size
+function returns the usable size of the allocation pointed to by
+.Fa ptr .
+.Sh ENVIRONMENT
+The following environment variables affect the execution of the allocation
+functions:
+.Bl -tag -width ".Ev MALLOC_OPTIONS"
+.It Ev MALLOC_OPTIONS
+If the environment variable
+.Ev MALLOC_OPTIONS
+is set, the characters it contains will be interpreted as flags to the
+allocation functions.
+.El
+.Sh EXAMPLES
+To dump core whenever a problem occurs:
+.Pp
+.Bd -literal -offset indent
+ln -s 'A' /etc/malloc.conf
+.Ed
+.Pp
+To specify in the source that a program does no return value checking
+on calls to these functions:
+.Bd -literal -offset indent
+_malloc_options = "X";
+.Ed
+.Sh SEE ALSO
+.Xr madvise 2 ,
+.Xr mmap 2 ,
+.Xr alloca 3 ,
+.Xr atexit 3 ,
+.Xr getpagesize 3 ,
+.Xr memory 3 ,
+.Xr posix_memalign 3
+.Sh STANDARDS
+The
+.Fn malloc ,
+.Fn calloc ,
+.Fn realloc
+and
+.Fn free
+functions conform to
+.St -isoC .
+.Sh HISTORY
+The
+.Fn reallocf
+function first appeared in
+.Fx 3.0 .
+.Pp
+The
+.Fn malloc_usable_size
+function first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
new file mode 100644
index 0000000..4bb2a92
--- /dev/null
+++ b/lib/libc/stdlib/malloc.c
@@ -0,0 +1,3806 @@
+/*-
+ * Copyright (C) 2006 Jason Evans <jasone@FreeBSD.org>.
+ * 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(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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.
+ *
+ *******************************************************************************
+ *
+ * This allocator implementation is designed to provide scalable performance
+ * for multi-threaded programs on multi-processor systems. The following
+ * features are included for this purpose:
+ *
+ * + Multiple arenas are used if there are multiple CPUs, which reduces lock
+ * contention and cache sloshing.
+ *
+ * + Cache line sharing between arenas is avoided for internal data
+ * structures.
+ *
+ * + Memory is managed in chunks and runs (chunks can be split into runs),
+ * rather than as individual pages. This provides a constant-time
+ * mechanism for associating allocations with particular arenas.
+ *
+ * Allocation requests are rounded up to the nearest size class, and no record
+ * of the original request size is maintained. Allocations are broken into
+ * categories according to size class. Assuming runtime defaults, 4 kB pages
+ * and a 16 byte quantum, the size classes in each category are as follows:
+ *
+ * |====================================|
+ * | Category | Subcategory | Size |
+ * |====================================|
+ * | Small | Tiny | 2 |
+ * | | | 4 |
+ * | | | 8 |
+ * | |----------------+--------|
+ * | | Quantum-spaced | 16 |
+ * | | | 32 |
+ * | | | 48 |
+ * | | | ... |
+ * | | | 480 |
+ * | | | 496 |
+ * | | | 512 |
+ * | |----------------+--------|
+ * | | Sub-page | 1 kB |
+ * | | | 2 kB |
+ * |====================================|
+ * | Large | 4 kB |
+ * | | 8 kB |
+ * | | 16 kB |
+ * | | ... |
+ * | | 256 kB |
+ * | | 512 kB |
+ * |====================================|
+ * | Huge | 1 MB |
+ * | | 2 MB |
+ * | | 3 MB |
+ * | | ... |
+ * |====================================|
+ *
+ * A different mechanism is used for each category:
+ *
+ * Small : Each size class is segregated into its own set of runs. Each run
+ * maintains a bitmap of which regions are free/allocated.
+ *
+ * Large : Each allocation is backed by a dedicated run. Metadata are stored
+ * in the associated arena chunk header maps.
+ *
+ * Huge : Each allocation is backed by a dedicated contiguous set of chunks.
+ * Metadata are stored in a separate red-black tree.
+ *
+ *******************************************************************************
+ */
+
+/*
+ * MALLOC_PRODUCTION disables assertions and statistics gathering. It also
+ * defaults the A and J runtime options to off. These settings are appropriate
+ * for production systems.
+ */
+/* #define MALLOC_PRODUCTION */
+
+#ifndef MALLOC_PRODUCTION
+# define MALLOC_DEBUG
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "libc_private.h"
+#ifdef MALLOC_DEBUG
+# define _LOCK_DEBUG
+#endif
+#include "spinlock.h"
+#include "namespace.h"
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stddef.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+#include <sys/ktrace.h> /* Must come after several other sys/ includes. */
+
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
+#include <machine/vmparam.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "un-namespace.h"
+
+/* MALLOC_STATS enables statistics calculation. */
+#ifndef MALLOC_PRODUCTION
+# define MALLOC_STATS
+#endif
+
+#ifdef MALLOC_DEBUG
+# ifdef NDEBUG
+# undef NDEBUG
+# endif
+#else
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+#endif
+#include <assert.h>
+
+#ifdef MALLOC_DEBUG
+ /* Disable inlining to make debugging easier. */
+# define inline
+#endif
+
+/* Size of stack-allocated buffer passed to strerror_r(). */
+#define STRERROR_BUF 64
+
+/* Minimum alignment of allocations is 2^QUANTUM_2POW_MIN bytes. */
+#ifdef __i386__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 2
+# define USE_BRK
+#endif
+#ifdef __ia64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 3
+#endif
+#ifdef __alpha__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 3
+# define NO_TLS
+#endif
+#ifdef __sparc64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 3
+# define NO_TLS
+#endif
+#ifdef __amd64__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 3
+#endif
+#ifdef __arm__
+# define QUANTUM_2POW_MIN 3
+# define SIZEOF_PTR_2POW 2
+# define USE_BRK
+# define NO_TLS
+#endif
+#ifdef __powerpc__
+# define QUANTUM_2POW_MIN 4
+# define SIZEOF_PTR_2POW 2
+# define USE_BRK
+#endif
+
+#define SIZEOF_PTR (1 << SIZEOF_PTR_2POW)
+
+/* sizeof(int) == (1 << SIZEOF_INT_2POW). */
+#ifndef SIZEOF_INT_2POW
+# define SIZEOF_INT_2POW 2
+#endif
+
+/* We can't use TLS in non-PIC programs, since TLS relies on loader magic. */
+#if (!defined(PIC) && !defined(NO_TLS))
+# define NO_TLS
+#endif
+
+/*
+ * Size and alignment of memory chunks that are allocated by the OS's virtual
+ * memory system.
+ */
+#define CHUNK_2POW_DEFAULT 20
+
+/*
+ * Maximum size of L1 cache line. This is used to avoid cache line aliasing,
+ * so over-estimates are okay (up to a point), but under-estimates will
+ * negatively affect performance.
+ */
+#define CACHELINE_2POW 6
+#define CACHELINE ((size_t)(1 << CACHELINE_2POW))
+
+/* Smallest size class to support. */
+#define TINY_MIN_2POW 1
+
+/*
+ * Maximum size class that is a multiple of the quantum, but not (necessarily)
+ * a power of 2. Above this size, allocations are rounded up to the nearest
+ * power of 2.
+ */
+#define SMALL_MAX_2POW_DEFAULT 9
+#define SMALL_MAX_DEFAULT (1 << SMALL_MAX_2POW_DEFAULT)
+
+/*
+ * Maximum desired run header overhead. Runs are sized as small as possible
+ * such that this setting is still honored, without violating other constraints.
+ * The goal is to make runs as small as possible without exceeding a per run
+ * external fragmentation threshold.
+ *
+ * Note that it is possible to set this low enough that it cannot be honored
+ * for some/all object sizes, since there is one bit of header overhead per
+ * object (plus a constant). In such cases, this constraint is relaxed.
+ *
+ * RUN_MAX_OVRHD_RELAX specifies the maximum number of bits per region of
+ * overhead for which RUN_MAX_OVRHD is relaxed.
+ */
+#define RUN_MAX_OVRHD 0.015
+#define RUN_MAX_OVRHD_RELAX 1.5
+
+/* Put a cap on small object run size. This overrides RUN_MAX_OVRHD. */
+#define RUN_MAX_SMALL_2POW 15
+#define RUN_MAX_SMALL (1 << RUN_MAX_SMALL_2POW)
+
+/******************************************************************************/
+
+/*
+ * Mutexes based on spinlocks. We can't use normal pthread mutexes, because
+ * they require malloc()ed memory.
+ */
+typedef struct {
+ spinlock_t lock;
+} malloc_mutex_t;
+
+/* Set to true once the allocator has been initialized. */
+static bool malloc_initialized = false;
+
+/* Used to avoid initialization races. */
+static malloc_mutex_t init_lock = {_SPINLOCK_INITIALIZER};
+
+/******************************************************************************/
+/*
+ * Statistics data structures.
+ */
+
+#ifdef MALLOC_STATS
+
+typedef struct malloc_bin_stats_s malloc_bin_stats_t;
+struct malloc_bin_stats_s {
+ /*
+ * Number of allocation requests that corresponded to the size of this
+ * bin.
+ */
+ uint64_t nrequests;
+
+ /* Total number of runs created for this bin's size class. */
+ uint64_t nruns;
+
+ /*
+ * Total number of runs reused by extracting them from the runs tree for
+ * this bin's size class.
+ */
+ uint64_t reruns;
+
+ /* High-water mark for this bin. */
+ unsigned long highruns;
+
+ /* Current number of runs in this bin. */
+ unsigned long curruns;
+};
+
+typedef struct arena_stats_s arena_stats_t;
+struct arena_stats_s {
+ /* Number of bytes currently mapped. */
+ size_t mapped;
+
+ /* Per-size-category statistics. */
+ size_t allocated_small;
+ uint64_t nmalloc_small;
+ uint64_t ndalloc_small;
+
+ size_t allocated_large;
+ uint64_t nmalloc_large;
+ uint64_t ndalloc_large;
+};
+
+typedef struct chunk_stats_s chunk_stats_t;
+struct chunk_stats_s {
+ /* Number of chunks that were allocated. */
+ uint64_t nchunks;
+
+ /* High-water mark for number of chunks allocated. */
+ unsigned long highchunks;
+
+ /*
+ * Current number of chunks allocated. This value isn't maintained for
+ * any other purpose, so keep track of it in order to be able to set
+ * highchunks.
+ */
+ unsigned long curchunks;
+};
+
+#endif /* #ifdef MALLOC_STATS */
+
+/******************************************************************************/
+/*
+ * Chunk data structures.
+ */
+
+/* Tree of chunks. */
+typedef struct chunk_node_s chunk_node_t;
+struct chunk_node_s {
+ /* Linkage for the chunk tree. */
+ RB_ENTRY(chunk_node_s) link;
+
+ /*
+ * Pointer to the chunk that this tree node is responsible for. In some
+ * (but certainly not all) cases, this data structure is placed at the
+ * beginning of the corresponding chunk, so this field may point to this
+ * node.
+ */
+ void *chunk;
+
+ /* Total chunk size. */
+ size_t size;
+};
+typedef struct chunk_tree_s chunk_tree_t;
+RB_HEAD(chunk_tree_s, chunk_node_s);
+
+/******************************************************************************/
+/*
+ * Arena data structures.
+ */
+
+typedef struct arena_s arena_t;
+typedef struct arena_bin_s arena_bin_t;
+
+typedef struct arena_chunk_map_s arena_chunk_map_t;
+struct arena_chunk_map_s {
+ /* Number of pages in run. */
+ uint32_t npages;
+ /*
+ * Position within run. For a free run, this is POS_FREE for the first
+ * and last pages. The POS_FREE special value makes it possible to
+ * quickly coalesce free runs.
+ *
+ * This is the limiting factor for chunksize; there can be at most 2^31
+ * pages in a run.
+ */
+#define POS_FREE ((uint32_t)0xffffffffU)
+ uint32_t pos;
+};
+
+/* Arena chunk header. */
+typedef struct arena_chunk_s arena_chunk_t;
+struct arena_chunk_s {
+ /* Arena that owns the chunk. */
+ arena_t *arena;
+
+ /* Linkage for the arena's chunk tree. */
+ RB_ENTRY(arena_chunk_s) link;
+
+ /*
+ * Number of pages in use. This is maintained in order to make
+ * detection of empty chunks fast.
+ */
+ uint32_t pages_used;
+
+ /*
+ * Every time a free run larger than this value is created/coalesced,
+ * this value is increased. The only way that the value decreases is if
+ * arena_run_alloc() fails to find a free run as large as advertised by
+ * this value.
+ */
+ uint32_t max_frun_npages;
+
+ /*
+ * Every time a free run that starts at an earlier page than this value
+ * is created/coalesced, this value is decreased. It is reset in a
+ * similar fashion to max_frun_npages.
+ */
+ uint32_t min_frun_ind;
+
+ /*
+ * Map of pages within chunk that keeps track of free/large/small. For
+ * free runs, only the map entries for the first and last pages are
+ * kept up to date, so that free runs can be quickly coalesced.
+ */
+ arena_chunk_map_t map[1]; /* Dynamically sized. */
+};
+typedef struct arena_chunk_tree_s arena_chunk_tree_t;
+RB_HEAD(arena_chunk_tree_s, arena_chunk_s);
+
+typedef struct arena_run_s arena_run_t;
+struct arena_run_s {
+ /* Linkage for run trees. */
+ RB_ENTRY(arena_run_s) link;
+
+#ifdef MALLOC_DEBUG
+ uint32_t magic;
+# define ARENA_RUN_MAGIC 0x384adf93
+#endif
+
+ /* Bin this run is associated with. */
+ arena_bin_t *bin;
+
+ /* Index of first element that might have a free region. */
+ unsigned regs_minelm;
+
+ /* Number of free regions in run. */
+ unsigned nfree;
+
+ /* Bitmask of in-use regions (0: in use, 1: free). */
+ unsigned regs_mask[1]; /* Dynamically sized. */
+};
+typedef struct arena_run_tree_s arena_run_tree_t;
+RB_HEAD(arena_run_tree_s, arena_run_s);
+
+struct arena_bin_s {
+ /*
+ * Current run being used to service allocations of this bin's size
+ * class.
+ */
+ arena_run_t *runcur;
+
+ /*
+ * Tree of non-full runs. This tree is used when looking for an
+ * existing run when runcur is no longer usable. We choose the
+ * non-full run that is lowest in memory; this policy tends to keep
+ * objects packed well, and it can also help reduce the number of
+ * almost-empty chunks.
+ */
+ arena_run_tree_t runs;
+
+ /* Size of regions in a run for this bin's size class. */
+ size_t reg_size;
+
+ /* Total size of a run for this bin's size class. */
+ size_t run_size;
+
+ /* Total number of regions in a run for this bin's size class. */
+ uint32_t nregs;
+
+ /* Number of elements in a run's regs_mask for this bin's size class. */
+ uint32_t regs_mask_nelms;
+
+ /* Offset of first region in a run for this bin's size class. */
+ uint32_t reg0_offset;
+
+#ifdef MALLOC_STATS
+ /* Bin statistics. */
+ malloc_bin_stats_t stats;
+#endif
+};
+
+struct arena_s {
+#ifdef MALLOC_DEBUG
+ uint32_t magic;
+# define ARENA_MAGIC 0x947d3d24
+#endif
+
+ /* All operations on this arena require that mtx be locked. */
+ malloc_mutex_t mtx;
+
+#ifdef MALLOC_STATS
+ arena_stats_t stats;
+#endif
+
+ /*
+ * Tree of chunks this arena manages.
+ */
+ arena_chunk_tree_t chunks;
+
+ /*
+ * In order to avoid rapid chunk allocation/deallocation when an arena
+ * oscillates right on the cusp of needing a new chunk, cache the most
+ * recently freed chunk. This caching is disabled by opt_hint.
+ *
+ * There is one spare chunk per arena, rather than one spare total, in
+ * order to avoid interactions between multiple threads that could make
+ * a single spare inadequate.
+ */
+ arena_chunk_t *spare;
+
+ /*
+ * bins is used to store rings of free regions of the following sizes,
+ * assuming a 16-byte quantum, 4kB pagesize, and default MALLOC_OPTIONS.
+ *
+ * bins[i] | size |
+ * --------+------+
+ * 0 | 2 |
+ * 1 | 4 |
+ * 2 | 8 |
+ * --------+------+
+ * 3 | 16 |
+ * 4 | 32 |
+ * 5 | 48 |
+ * 6 | 64 |
+ * : :
+ * : :
+ * 33 | 496 |
+ * 34 | 512 |
+ * --------+------+
+ * 35 | 1024 |
+ * 36 | 2048 |
+ * --------+------+
+ */
+ arena_bin_t bins[1]; /* Dynamically sized. */
+};
+
+/******************************************************************************/
+/*
+ * Data.
+ */
+
+/* Number of CPUs. */
+static unsigned ncpus;
+
+/* VM page size. */
+static size_t pagesize;
+static size_t pagesize_mask;
+static size_t pagesize_2pow;
+
+/* Various bin-related settings. */
+static size_t bin_maxclass; /* Max size class for bins. */
+static unsigned ntbins; /* Number of (2^n)-spaced tiny bins. */
+static unsigned nqbins; /* Number of quantum-spaced bins. */
+static unsigned nsbins; /* Number of (2^n)-spaced sub-page bins. */
+static size_t small_min;
+static size_t small_max;
+
+/* Various quantum-related settings. */
+static size_t quantum;
+static size_t quantum_mask; /* (quantum - 1). */
+
+/* Various chunk-related settings. */
+static size_t chunksize;
+static size_t chunksize_mask; /* (chunksize - 1). */
+static unsigned chunk_npages;
+static unsigned arena_chunk_header_npages;
+static size_t arena_maxclass; /* Max size class for arenas. */
+
+/********/
+/*
+ * Chunks.
+ */
+
+/* Protects chunk-related data structures. */
+static malloc_mutex_t chunks_mtx;
+
+/* Tree of chunks that are stand-alone huge allocations. */
+static chunk_tree_t huge;
+
+#ifdef USE_BRK
+/*
+ * Try to use brk for chunk-size allocations, due to address space constraints.
+ */
+/*
+ * Protects sbrk() calls. This must be separate from chunks_mtx, since
+ * base_pages_alloc() also uses sbrk(), but cannot lock chunks_mtx (doing so
+ * could cause recursive lock acquisition).
+ */
+static malloc_mutex_t brk_mtx;
+/* Result of first sbrk(0) call. */
+static void *brk_base;
+/* Current end of brk, or ((void *)-1) if brk is exhausted. */
+static void *brk_prev;
+/* Current upper limit on brk addresses. */
+static void *brk_max;
+#endif
+
+#ifdef MALLOC_STATS
+/* Huge allocation statistics. */
+static uint64_t huge_nmalloc;
+static uint64_t huge_ndalloc;
+static size_t huge_allocated;
+#endif
+
+/*
+ * Tree of chunks that were previously allocated. This is used when allocating
+ * chunks, in an attempt to re-use address space.
+ */
+static chunk_tree_t old_chunks;
+
+/****************************/
+/*
+ * base (internal allocation).
+ */
+
+/*
+ * Current pages that are being used for internal memory allocations. These
+ * pages are carved up in cacheline-size quanta, so that there is no chance of
+ * false cache line sharing.
+ */
+static void *base_pages;
+static void *base_next_addr;
+static void *base_past_addr; /* Addr immediately past base_pages. */
+static chunk_node_t *base_chunk_nodes; /* LIFO cache of chunk nodes. */
+static malloc_mutex_t base_mtx;
+#ifdef MALLOC_STATS
+static size_t base_mapped;
+#endif
+
+/********/
+/*
+ * Arenas.
+ */
+
+/*
+ * Arenas that are used to service external requests. Not all elements of the
+ * arenas array are necessarily used; arenas are created lazily as needed.
+ */
+static arena_t **arenas;
+static unsigned narenas;
+#ifndef NO_TLS
+static unsigned next_arena;
+#endif
+static malloc_mutex_t arenas_mtx; /* Protects arenas initialization. */
+
+#ifndef NO_TLS
+/*
+ * Map of pthread_self() --> arenas[???], used for selecting an arena to use
+ * for allocations.
+ */
+static __thread arena_t *arenas_map;
+#endif
+
+#ifdef MALLOC_STATS
+/* Chunk statistics. */
+static chunk_stats_t stats_chunks;
+#endif
+
+/*******************************/
+/*
+ * Runtime configuration options.
+ */
+const char *_malloc_options;
+
+#ifndef MALLOC_PRODUCTION
+static bool opt_abort = true;
+static bool opt_junk = true;
+#else
+static bool opt_abort = false;
+static bool opt_junk = false;
+#endif
+static bool opt_hint = false;
+static bool opt_print_stats = false;
+static size_t opt_quantum_2pow = QUANTUM_2POW_MIN;
+static size_t opt_small_max_2pow = SMALL_MAX_2POW_DEFAULT;
+static size_t opt_chunk_2pow = CHUNK_2POW_DEFAULT;
+static bool opt_utrace = false;
+static bool opt_sysv = false;
+static bool opt_xmalloc = false;
+static bool opt_zero = false;
+static int32_t opt_narenas_lshift = 0;
+
+typedef struct {
+ void *p;
+ size_t s;
+ void *r;
+} malloc_utrace_t;
+
+#define UTRACE(a, b, c) \
+ if (opt_utrace) { \
+ malloc_utrace_t ut = {a, b, c}; \
+ utrace(&ut, sizeof(ut)); \
+ }
+
+/******************************************************************************/
+/*
+ * Begin function prototypes for non-inline static functions.
+ */
+
+static void malloc_mutex_init(malloc_mutex_t *a_mutex);
+static void wrtmessage(const char *p1, const char *p2, const char *p3,
+ const char *p4);
+#ifdef MALLOC_STATS
+static void malloc_printf(const char *format, ...);
+#endif
+static char *umax2s(uintmax_t x, char *s);
+static bool base_pages_alloc(size_t minsize);
+static void *base_alloc(size_t size);
+static chunk_node_t *base_chunk_node_alloc(void);
+static void base_chunk_node_dealloc(chunk_node_t *node);
+#ifdef MALLOC_STATS
+static void stats_print(arena_t *arena);
+#endif
+static void *pages_map(void *addr, size_t size);
+static void pages_unmap(void *addr, size_t size);
+static void *chunk_alloc(size_t size);
+static void chunk_dealloc(void *chunk, size_t size);
+#ifndef NO_TLS
+static arena_t *choose_arena_hard(void);
+#endif
+static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size);
+static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
+static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
+static arena_run_t *arena_run_alloc(arena_t *arena, size_t size);
+static void arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size);
+static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
+static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
+static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
+static void *arena_malloc(arena_t *arena, size_t size);
+static void *arena_palloc(arena_t *arena, size_t alignment, size_t size,
+ size_t alloc_size);
+static size_t arena_salloc(const void *ptr);
+static void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
+static void arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
+static bool arena_new(arena_t *arena);
+static arena_t *arenas_extend(unsigned ind);
+static void *huge_malloc(size_t size);
+static void *huge_palloc(size_t alignment, size_t size);
+static void *huge_ralloc(void *ptr, size_t size, size_t oldsize);
+static void huge_dalloc(void *ptr);
+static void *imalloc(size_t size);
+static void *ipalloc(size_t alignment, size_t size);
+static void *icalloc(size_t size);
+static size_t isalloc(const void *ptr);
+static void *iralloc(void *ptr, size_t size);
+static void idalloc(void *ptr);
+static void malloc_print_stats(void);
+static bool malloc_init_hard(void);
+
+/*
+ * End function prototypes.
+ */
+/******************************************************************************/
+/*
+ * Begin mutex.
+ */
+
+static void
+malloc_mutex_init(malloc_mutex_t *a_mutex)
+{
+ static const spinlock_t lock = _SPINLOCK_INITIALIZER;
+
+ a_mutex->lock = lock;
+}
+
+static inline void
+malloc_mutex_lock(malloc_mutex_t *a_mutex)
+{
+
+ if (__isthreaded)
+ _SPINLOCK(&a_mutex->lock);
+}
+
+static inline void
+malloc_mutex_unlock(malloc_mutex_t *a_mutex)
+{
+
+ if (__isthreaded)
+ _SPINUNLOCK(&a_mutex->lock);
+}
+
+/*
+ * End mutex.
+ */
+/******************************************************************************/
+/*
+ * Begin Utility functions/macros.
+ */
+
+/* Return the chunk address for allocation address a. */
+#define CHUNK_ADDR2BASE(a) \
+ ((void *)((uintptr_t)(a) & ~chunksize_mask))
+
+/* Return the chunk offset of address a. */
+#define CHUNK_ADDR2OFFSET(a) \
+ ((size_t)((uintptr_t)(a) & chunksize_mask))
+
+/* Return the smallest chunk multiple that is >= s. */
+#define CHUNK_CEILING(s) \
+ (((s) + chunksize_mask) & ~chunksize_mask)
+
+/* Return the smallest cacheline multiple that is >= s. */
+#define CACHELINE_CEILING(s) \
+ (((s) + (CACHELINE - 1)) & ~(CACHELINE - 1))
+
+/* Return the smallest quantum multiple that is >= a. */
+#define QUANTUM_CEILING(a) \
+ (((a) + quantum_mask) & ~quantum_mask)
+
+/* Return the smallest pagesize multiple that is >= s. */
+#define PAGE_CEILING(s) \
+ (((s) + pagesize_mask) & ~pagesize_mask)
+
+/* Compute the smallest power of 2 that is >= x. */
+static inline size_t
+pow2_ceil(size_t x)
+{
+
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+#if (SIZEOF_PTR == 8)
+ x |= x >> 32;
+#endif
+ x++;
+ return (x);
+}
+
+static void
+wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
+{
+
+ _write(STDERR_FILENO, p1, strlen(p1));
+ _write(STDERR_FILENO, p2, strlen(p2));
+ _write(STDERR_FILENO, p3, strlen(p3));
+ _write(STDERR_FILENO, p4, strlen(p4));
+}
+
+void (*_malloc_message)(const char *p1, const char *p2, const char *p3,
+ const char *p4) = wrtmessage;
+
+#ifdef MALLOC_STATS
+/*
+ * Print to stderr in such a way as to (hopefully) avoid memory allocation.
+ */
+static void
+malloc_printf(const char *format, ...)
+{
+ char buf[4096];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+ _malloc_message(buf, "", "", "");
+}
+#endif
+
+/*
+ * We don't want to depend on vsnprintf() for production builds, since that can
+ * cause unnecessary bloat for static binaries. umax2s() provides minimal
+ * integer printing functionality, so that malloc_printf() use can be limited to
+ * MALLOC_STATS code.
+ */
+#define UMAX2S_BUFSIZE 21
+static char *
+umax2s(uintmax_t x, char *s)
+{
+ unsigned i;
+
+ /* Make sure UMAX2S_BUFSIZE is large enough. */
+ assert(sizeof(uintmax_t) <= 8);
+
+ i = UMAX2S_BUFSIZE - 1;
+ s[i] = '\0';
+ do {
+ i--;
+ s[i] = "0123456789"[x % 10];
+ x /= 10;
+ } while (x > 0);
+
+ return (&s[i]);
+}
+
+/******************************************************************************/
+
+static bool
+base_pages_alloc(size_t minsize)
+{
+ size_t csize;
+
+#ifdef USE_BRK
+ /*
+ * Do special brk allocation here, since base allocations don't need to
+ * be chunk-aligned.
+ */
+ if (brk_prev != (void *)-1) {
+ void *brk_cur;
+ intptr_t incr;
+
+ if (minsize != 0)
+ csize = CHUNK_CEILING(minsize);
+
+ malloc_mutex_lock(&brk_mtx);
+ do {
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Calculate how much padding is necessary to
+ * chunk-align the end of brk. Don't worry about
+ * brk_cur not being chunk-aligned though.
+ */
+ incr = (intptr_t)chunksize
+ - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
+ if (incr < minsize)
+ incr += csize;
+
+ brk_prev = sbrk(incr);
+ if (brk_prev == brk_cur) {
+ /* Success. */
+ malloc_mutex_unlock(&brk_mtx);
+ base_pages = brk_cur;
+ base_next_addr = base_pages;
+ base_past_addr = (void *)((uintptr_t)base_pages
+ + incr);
+#ifdef MALLOC_STATS
+ base_mapped += incr;
+#endif
+ return (false);
+ }
+ } while (brk_prev != (void *)-1);
+ malloc_mutex_unlock(&brk_mtx);
+ }
+ if (minsize == 0) {
+ /*
+ * Failure during initialization doesn't matter, so avoid
+ * falling through to the mmap-based page mapping code.
+ */
+ return (true);
+ }
+#endif
+ assert(minsize != 0);
+ csize = PAGE_CEILING(minsize);
+ base_pages = pages_map(NULL, csize);
+ if (base_pages == NULL)
+ return (true);
+ base_next_addr = base_pages;
+ base_past_addr = (void *)((uintptr_t)base_pages + csize);
+#ifdef MALLOC_STATS
+ base_mapped += csize;
+#endif
+ return (false);
+}
+
+static void *
+base_alloc(size_t size)
+{
+ void *ret;
+ size_t csize;
+
+ /* Round size up to nearest multiple of the cacheline size. */
+ csize = CACHELINE_CEILING(size);
+
+ malloc_mutex_lock(&base_mtx);
+
+ /* Make sure there's enough space for the allocation. */
+ if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
+ if (base_pages_alloc(csize)) {
+ ret = NULL;
+ goto RETURN;
+ }
+ }
+
+ /* Allocate. */
+ ret = base_next_addr;
+ base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
+
+RETURN:
+ malloc_mutex_unlock(&base_mtx);
+ return (ret);
+}
+
+static chunk_node_t *
+base_chunk_node_alloc(void)
+{
+ chunk_node_t *ret;
+
+ malloc_mutex_lock(&base_mtx);
+ if (base_chunk_nodes != NULL) {
+ ret = base_chunk_nodes;
+ base_chunk_nodes = *(chunk_node_t **)ret;
+ malloc_mutex_unlock(&base_mtx);
+ } else {
+ malloc_mutex_unlock(&base_mtx);
+ ret = (chunk_node_t *)base_alloc(sizeof(chunk_node_t));
+ }
+
+ return (ret);
+}
+
+static void
+base_chunk_node_dealloc(chunk_node_t *node)
+{
+
+ malloc_mutex_lock(&base_mtx);
+ *(chunk_node_t **)node = base_chunk_nodes;
+ base_chunk_nodes = node;
+ malloc_mutex_unlock(&base_mtx);
+}
+
+/******************************************************************************/
+
+#ifdef MALLOC_STATS
+static void
+stats_print(arena_t *arena)
+{
+ unsigned i;
+ int gap_start;
+
+ malloc_printf(
+ " allocated/mapped nmalloc ndalloc\n");
+ malloc_printf("small: %12llu %-12s %12llu %12llu\n",
+ arena->stats.allocated_small, "", arena->stats.nmalloc_small,
+ arena->stats.ndalloc_small);
+ malloc_printf("large: %12llu %-12s %12llu %12llu\n",
+ arena->stats.allocated_large, "", arena->stats.nmalloc_large,
+ arena->stats.ndalloc_large);
+ malloc_printf("total: %12llu/%-12llu %12llu %12llu\n",
+ arena->stats.allocated_small + arena->stats.allocated_large,
+ arena->stats.mapped,
+ arena->stats.nmalloc_small + arena->stats.nmalloc_large,
+ arena->stats.ndalloc_small + arena->stats.ndalloc_large);
+
+ malloc_printf("bins: bin size regs pgs requests newruns"
+ " reruns maxruns curruns\n");
+ for (i = 0, gap_start = -1; i < ntbins + nqbins + nsbins; i++) {
+ if (arena->bins[i].stats.nrequests == 0) {
+ if (gap_start == -1)
+ gap_start = i;
+ } else {
+ if (gap_start != -1) {
+ if (i > gap_start + 1) {
+ /* Gap of more than one size class. */
+ malloc_printf("[%u..%u]\n",
+ gap_start, i - 1);
+ } else {
+ /* Gap of one size class. */
+ malloc_printf("[%u]\n", gap_start);
+ }
+ gap_start = -1;
+ }
+ malloc_printf(
+ "%13u %1s %4u %4u %3u %9llu %9llu"
+ " %9llu %7lu %7lu\n",
+ i,
+ i < ntbins ? "T" : i < ntbins + nqbins ? "Q" : "S",
+ arena->bins[i].reg_size,
+ arena->bins[i].nregs,
+ arena->bins[i].run_size >> pagesize_2pow,
+ arena->bins[i].stats.nrequests,
+ arena->bins[i].stats.nruns,
+ arena->bins[i].stats.reruns,
+ arena->bins[i].stats.highruns,
+ arena->bins[i].stats.curruns);
+ }
+ }
+ if (gap_start != -1) {
+ if (i > gap_start + 1) {
+ /* Gap of more than one size class. */
+ malloc_printf("[%u..%u]\n", gap_start, i - 1);
+ } else {
+ /* Gap of one size class. */
+ malloc_printf("[%u]\n", gap_start);
+ }
+ }
+}
+#endif
+
+/*
+ * End Utility functions/macros.
+ */
+/******************************************************************************/
+/*
+ * Begin chunk management functions.
+ */
+
+static inline int
+chunk_comp(chunk_node_t *a, chunk_node_t *b)
+{
+
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if ((uintptr_t)a->chunk < (uintptr_t)b->chunk)
+ return (-1);
+ else if (a->chunk == b->chunk)
+ return (0);
+ else
+ return (1);
+}
+
+/* Generate red-black tree code for chunks. */
+RB_GENERATE_STATIC(chunk_tree_s, chunk_node_s, link, chunk_comp);
+
+static void *
+pages_map(void *addr, size_t size)
+{
+ void *ret;
+
+ /*
+ * We don't use MAP_FIXED here, because it can cause the *replacement*
+ * of existing mappings, and we only want to create new mappings.
+ */
+ ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ assert(ret != NULL);
+
+ if (ret == MAP_FAILED)
+ ret = NULL;
+ else if (addr != NULL && ret != addr) {
+ /*
+ * We succeeded in mapping memory, but not in the right place.
+ */
+ if (munmap(ret, size) == -1) {
+ char buf[STRERROR_BUF];
+
+ strerror_r(errno, buf, sizeof(buf));
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in munmap(): ", buf, "\n");
+ if (opt_abort)
+ abort();
+ }
+ ret = NULL;
+ }
+
+ assert(ret == NULL || (addr == NULL && ret != addr)
+ || (addr != NULL && ret == addr));
+ return (ret);
+}
+
+static void
+pages_unmap(void *addr, size_t size)
+{
+
+ if (munmap(addr, size) == -1) {
+ char buf[STRERROR_BUF];
+
+ strerror_r(errno, buf, sizeof(buf));
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in munmap(): ", buf, "\n");
+ if (opt_abort)
+ abort();
+ }
+}
+
+static void *
+chunk_alloc(size_t size)
+{
+ void *ret, *chunk;
+ chunk_node_t *tchunk, *delchunk;
+
+ assert(size != 0);
+ assert((size & chunksize_mask) == 0);
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ if (size == chunksize) {
+ /*
+ * Check for address ranges that were previously chunks and try
+ * to use them.
+ */
+
+ tchunk = RB_MIN(chunk_tree_s, &old_chunks);
+ while (tchunk != NULL) {
+ /* Found an address range. Try to recycle it. */
+
+ chunk = tchunk->chunk;
+ delchunk = tchunk;
+ tchunk = RB_NEXT(chunk_tree_s, &old_chunks, delchunk);
+
+ /* Remove delchunk from the tree. */
+ RB_REMOVE(chunk_tree_s, &old_chunks, delchunk);
+ base_chunk_node_dealloc(delchunk);
+
+#ifdef USE_BRK
+ if ((uintptr_t)chunk >= (uintptr_t)brk_base
+ && (uintptr_t)chunk < (uintptr_t)brk_max) {
+ /* Re-use a previously freed brk chunk. */
+ ret = chunk;
+ goto RETURN;
+ }
+#endif
+ if ((ret = pages_map(chunk, size)) != NULL) {
+ /* Success. */
+ goto RETURN;
+ }
+ }
+ }
+
+ /*
+ * Try to over-allocate, but allow the OS to place the allocation
+ * anywhere. Beware of size_t wrap-around.
+ */
+ if (size + chunksize > size) {
+ if ((ret = pages_map(NULL, size + chunksize)) != NULL) {
+ size_t offset = CHUNK_ADDR2OFFSET(ret);
+
+ /*
+ * Success. Clean up unneeded leading/trailing space.
+ */
+ if (offset != 0) {
+ /* Leading space. */
+ pages_unmap(ret, chunksize - offset);
+
+ ret = (void *)((uintptr_t)ret + (chunksize -
+ offset));
+
+ /* Trailing space. */
+ pages_unmap((void *)((uintptr_t)ret + size),
+ offset);
+ } else {
+ /* Trailing space only. */
+ pages_unmap((void *)((uintptr_t)ret + size),
+ chunksize);
+ }
+ goto RETURN;
+ }
+ }
+
+#ifdef USE_BRK
+ /*
+ * Try to create allocations in brk, in order to make full use of
+ * limited address space.
+ */
+ if (brk_prev != (void *)-1) {
+ void *brk_cur;
+ intptr_t incr;
+
+ /*
+ * The loop is necessary to recover from races with other
+ * threads that are using brk for something other than malloc.
+ */
+ malloc_mutex_lock(&brk_mtx);
+ do {
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Calculate how much padding is necessary to
+ * chunk-align the end of brk.
+ */
+ incr = (intptr_t)size
+ - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
+ if (incr == size) {
+ ret = brk_cur;
+ } else {
+ ret = (void *)((intptr_t)brk_cur + incr);
+ incr += size;
+ }
+
+ brk_prev = sbrk(incr);
+ if (brk_prev == brk_cur) {
+ /* Success. */
+ malloc_mutex_unlock(&brk_mtx);
+ brk_max = (void *)((intptr_t)ret + size);
+ goto RETURN;
+ }
+ } while (brk_prev != (void *)-1);
+ malloc_mutex_unlock(&brk_mtx);
+ }
+#endif
+
+ /* All strategies for allocation failed. */
+ ret = NULL;
+RETURN:
+ if (ret != NULL) {
+ chunk_node_t key;
+ /*
+ * Clean out any entries in old_chunks that overlap with the
+ * memory we just allocated.
+ */
+ key.chunk = ret;
+ tchunk = RB_NFIND(chunk_tree_s, &old_chunks, &key);
+ while (tchunk != NULL
+ && (uintptr_t)tchunk->chunk >= (uintptr_t)ret
+ && (uintptr_t)tchunk->chunk < (uintptr_t)ret + size) {
+ delchunk = tchunk;
+ tchunk = RB_NEXT(chunk_tree_s, &old_chunks, delchunk);
+ RB_REMOVE(chunk_tree_s, &old_chunks, delchunk);
+ base_chunk_node_dealloc(delchunk);
+ }
+
+ }
+#ifdef MALLOC_STATS
+ if (ret != NULL) {
+ stats_chunks.nchunks += (size / chunksize);
+ stats_chunks.curchunks += (size / chunksize);
+ }
+ if (stats_chunks.curchunks > stats_chunks.highchunks)
+ stats_chunks.highchunks = stats_chunks.curchunks;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ assert(CHUNK_ADDR2BASE(ret) == ret);
+ return (ret);
+}
+
+static void
+chunk_dealloc(void *chunk, size_t size)
+{
+ chunk_node_t *node;
+
+ assert(chunk != NULL);
+ assert(CHUNK_ADDR2BASE(chunk) == chunk);
+ assert(size != 0);
+ assert((size & chunksize_mask) == 0);
+
+ malloc_mutex_lock(&chunks_mtx);
+
+#ifdef USE_BRK
+ if ((uintptr_t)chunk >= (uintptr_t)brk_base
+ && (uintptr_t)chunk < (uintptr_t)brk_max) {
+ void *brk_cur;
+
+ malloc_mutex_lock(&brk_mtx);
+ /* Get the current end of brk. */
+ brk_cur = sbrk(0);
+
+ /*
+ * Try to shrink the data segment if this chunk is at the end
+ * of the data segment. The sbrk() call here is subject to a
+ * race condition with threads that use brk(2) or sbrk(2)
+ * directly, but the alternative would be to leak memory for
+ * the sake of poorly designed multi-threaded programs.
+ */
+ if (brk_cur == brk_max
+ && (void *)((uintptr_t)chunk + size) == brk_max
+ && sbrk(-(intptr_t)size) == brk_max) {
+ malloc_mutex_unlock(&brk_mtx);
+ if (brk_prev == brk_max) {
+ /* Success. */
+ brk_prev = (void *)((intptr_t)brk_max
+ - (intptr_t)size);
+ brk_max = brk_prev;
+ }
+ } else {
+ size_t offset;
+
+ malloc_mutex_unlock(&brk_mtx);
+ madvise(chunk, size, MADV_FREE);
+
+ /*
+ * Iteratively create records of each chunk-sized
+ * memory region that 'chunk' is comprised of, so that
+ * the address range can be recycled if memory usage
+ * increases later on.
+ */
+ for (offset = 0; offset < size; offset += chunksize) {
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ break;
+
+ node->chunk = (void *)((uintptr_t)chunk
+ + (uintptr_t)offset);
+ node->size = chunksize;
+ RB_INSERT(chunk_tree_s, &old_chunks, node);
+ }
+ }
+ } else {
+#endif
+ pages_unmap(chunk, size);
+
+ /*
+ * Make a record of the chunk's address, so that the address
+ * range can be recycled if memory usage increases later on.
+ * Don't bother to create entries if (size > chunksize), since
+ * doing so could cause scalability issues for truly gargantuan
+ * objects (many gigabytes or larger).
+ */
+ if (size == chunksize) {
+ node = base_chunk_node_alloc();
+ if (node != NULL) {
+ node->chunk = (void *)(uintptr_t)chunk;
+ node->size = chunksize;
+ RB_INSERT(chunk_tree_s, &old_chunks, node);
+ }
+ }
+#ifdef USE_BRK
+ }
+#endif
+
+#ifdef MALLOC_STATS
+ stats_chunks.curchunks -= (size / chunksize);
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+}
+
+/*
+ * End chunk management functions.
+ */
+/******************************************************************************/
+/*
+ * Begin arena.
+ */
+
+/*
+ * Choose an arena based on a per-thread value (fast-path code, calls slow-path
+ * code if necessary.
+ */
+static inline arena_t *
+choose_arena(void)
+{
+ arena_t *ret;
+
+ /*
+ * We can only use TLS if this is a PIC library, since for the static
+ * library version, libc's malloc is used by TLS allocation, which
+ * introduces a bootstrapping issue.
+ */
+#ifndef NO_TLS
+ if (__isthreaded == false) {
+ /*
+ * Avoid the overhead of TLS for single-threaded operation. If the
+ * app switches to threaded mode, the initial thread may end up
+ * being assigned to some other arena, but this one-time switch
+ * shouldn't cause significant issues.
+ * */
+ return (arenas[0]);
+ }
+
+ ret = arenas_map;
+ if (ret == NULL)
+ ret = choose_arena_hard();
+#else
+ if (__isthreaded) {
+ unsigned long ind;
+
+ /*
+ * Hash _pthread_self() to one of the arenas. There is a prime
+ * number of arenas, so this has a reasonable chance of
+ * working. Even so, the hashing can be easily thwarted by
+ * inconvenient _pthread_self() values. Without specific
+ * knowledge of how _pthread_self() calculates values, we can't
+ * easily do much better than this.
+ */
+ ind = (unsigned long) _pthread_self() % narenas;
+
+ /*
+ * Optimistially assume that arenas[ind] has been initialized.
+ * At worst, we find out that some other thread has already
+ * done so, after acquiring the lock in preparation. Note that
+ * this lazy locking also has the effect of lazily forcing
+ * cache coherency; without the lock acquisition, there's no
+ * guarantee that modification of arenas[ind] by another thread
+ * would be seen on this CPU for an arbitrary amount of time.
+ *
+ * In general, this approach to modifying a synchronized value
+ * isn't a good idea, but in this case we only ever modify the
+ * value once, so things work out well.
+ */
+ ret = arenas[ind];
+ if (ret == NULL) {
+ /*
+ * Avoid races with another thread that may have already
+ * initialized arenas[ind].
+ */
+ malloc_mutex_lock(&arenas_mtx);
+ if (arenas[ind] == NULL)
+ ret = arenas_extend((unsigned)ind);
+ else
+ ret = arenas[ind];
+ malloc_mutex_unlock(&arenas_mtx);
+ }
+ } else
+ ret = arenas[0];
+#endif
+
+ assert(ret != NULL);
+ return (ret);
+}
+
+#ifndef NO_TLS
+/*
+ * Choose an arena based on a per-thread value (slow-path code only, called
+ * only by choose_arena()).
+ */
+static arena_t *
+choose_arena_hard(void)
+{
+ arena_t *ret;
+
+ assert(__isthreaded);
+
+ /* Assign one of the arenas to this thread, in a round-robin fashion. */
+ malloc_mutex_lock(&arenas_mtx);
+ ret = arenas[next_arena];
+ if (ret == NULL)
+ ret = arenas_extend(next_arena);
+ if (ret == NULL) {
+ /*
+ * Make sure that this function never returns NULL, so that
+ * choose_arena() doesn't have to check for a NULL return
+ * value.
+ */
+ ret = arenas[0];
+ }
+ next_arena = (next_arena + 1) % narenas;
+ malloc_mutex_unlock(&arenas_mtx);
+ arenas_map = ret;
+
+ return (ret);
+}
+#endif
+
+static inline int
+arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
+{
+
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if ((uintptr_t)a < (uintptr_t)b)
+ return (-1);
+ else if (a == b)
+ return (0);
+ else
+ return (1);
+}
+
+/* Generate red-black tree code for arena chunks. */
+RB_GENERATE_STATIC(arena_chunk_tree_s, arena_chunk_s, link, arena_chunk_comp);
+
+static inline int
+arena_run_comp(arena_run_t *a, arena_run_t *b)
+{
+
+ assert(a != NULL);
+ assert(b != NULL);
+
+ if ((uintptr_t)a < (uintptr_t)b)
+ return (-1);
+ else if (a == b)
+ return (0);
+ else
+ return (1);
+}
+
+/* Generate red-black tree code for arena runs. */
+RB_GENERATE_STATIC(arena_run_tree_s, arena_run_s, link, arena_run_comp);
+
+static inline void *
+arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
+{
+ void *ret;
+ unsigned i, mask, bit, regind;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+ assert(run->regs_minelm < bin->regs_mask_nelms);
+
+ /*
+ * Move the first check outside the loop, so that run->regs_minelm can
+ * be updated unconditionally, without the possibility of updating it
+ * multiple times.
+ */
+ i = run->regs_minelm;
+ mask = run->regs_mask[i];
+ if (mask != 0) {
+ /* Usable allocation found. */
+ bit = ffs((int)mask) - 1;
+
+ regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
+ ret = (void *)(((uintptr_t)run) + bin->reg0_offset
+ + (bin->reg_size * regind));
+
+ /* Clear bit. */
+ mask ^= (1 << bit);
+ run->regs_mask[i] = mask;
+
+ return (ret);
+ }
+
+ for (i++; i < bin->regs_mask_nelms; i++) {
+ mask = run->regs_mask[i];
+ if (mask != 0) {
+ /* Usable allocation found. */
+ bit = ffs((int)mask) - 1;
+
+ regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
+ ret = (void *)(((uintptr_t)run) + bin->reg0_offset
+ + (bin->reg_size * regind));
+
+ /* Clear bit. */
+ mask ^= (1 << bit);
+ run->regs_mask[i] = mask;
+
+ /*
+ * Make a note that nothing before this element
+ * contains a free region.
+ */
+ run->regs_minelm = i; /* Low payoff: + (mask == 0); */
+
+ return (ret);
+ }
+ }
+ /* Not reached. */
+ assert(0);
+ return (NULL);
+}
+
+static inline void
+arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
+{
+ /*
+ * To divide by a number D that is not a power of two we multiply
+ * by (2^21 / D) and then right shift by 21 positions.
+ *
+ * X / D
+ *
+ * becomes
+ *
+ * (X * size_invs[(D >> QUANTUM_2POW_MIN) - 3]) >> SIZE_INV_SHIFT
+ */
+#define SIZE_INV_SHIFT 21
+#define SIZE_INV(s) (((1 << SIZE_INV_SHIFT) / (s << QUANTUM_2POW_MIN)) + 1)
+ static const unsigned size_invs[] = {
+ SIZE_INV(3),
+ SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
+ SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
+ SIZE_INV(12),SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
+ SIZE_INV(16),SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
+ SIZE_INV(20),SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
+ SIZE_INV(24),SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
+ SIZE_INV(28),SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
+#if (QUANTUM_2POW_MIN < 4)
+ ,
+ SIZE_INV(32), SIZE_INV(33), SIZE_INV(34), SIZE_INV(35),
+ SIZE_INV(36), SIZE_INV(37), SIZE_INV(38), SIZE_INV(39),
+ SIZE_INV(40), SIZE_INV(41), SIZE_INV(42), SIZE_INV(43),
+ SIZE_INV(44), SIZE_INV(45), SIZE_INV(46), SIZE_INV(47),
+ SIZE_INV(48), SIZE_INV(49), SIZE_INV(50), SIZE_INV(51),
+ SIZE_INV(52), SIZE_INV(53), SIZE_INV(54), SIZE_INV(55),
+ SIZE_INV(56), SIZE_INV(57), SIZE_INV(58), SIZE_INV(59),
+ SIZE_INV(60), SIZE_INV(61), SIZE_INV(62), SIZE_INV(63)
+#endif
+ };
+ unsigned diff, regind, elm, bit;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+ assert(((sizeof(size_invs)) / sizeof(unsigned)) + 3
+ >= (SMALL_MAX_DEFAULT >> QUANTUM_2POW_MIN));
+
+ /*
+ * Avoid doing division with a variable divisor if possible. Using
+ * actual division here can reduce allocator throughput by over 20%!
+ */
+ diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
+ if ((size & (size - 1)) == 0) {
+ /*
+ * log2_table allows fast division of a power of two in the
+ * [1..128] range.
+ *
+ * (x / divisor) becomes (x >> log2_table[divisor - 1]).
+ */
+ static const unsigned char log2_table[] = {
+ 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
+ };
+
+ if (size <= 128)
+ regind = (diff >> log2_table[size - 1]);
+ else if (size <= 32768)
+ regind = diff >> (8 + log2_table[(size >> 8) - 1]);
+ else {
+ /*
+ * The page size is too large for us to use the lookup
+ * table. Use real division.
+ */
+ regind = diff / size;
+ }
+ } else if (size <= ((sizeof(size_invs) / sizeof(unsigned))
+ << QUANTUM_2POW_MIN) + 2) {
+ regind = size_invs[(size >> QUANTUM_2POW_MIN) - 3] * diff;
+ regind >>= SIZE_INV_SHIFT;
+ } else {
+ /*
+ * size_invs isn't large enough to handle this size class, so
+ * calculate regind using actual division. This only happens
+ * if the user increases small_max via the 'S' runtime
+ * configuration option.
+ */
+ regind = diff / size;
+ };
+ assert(diff == regind * size);
+ assert(regind < bin->nregs);
+
+ elm = regind >> (SIZEOF_INT_2POW + 3);
+ if (elm < run->regs_minelm)
+ run->regs_minelm = elm;
+ bit = regind - (elm << (SIZEOF_INT_2POW + 3));
+ assert((run->regs_mask[elm] & (1 << bit)) == 0);
+ run->regs_mask[elm] |= (1 << bit);
+#undef SIZE_INV
+#undef SIZE_INV_SHIFT
+}
+
+static void
+arena_run_split(arena_t *arena, arena_run_t *run, size_t size)
+{
+ arena_chunk_t *chunk;
+ unsigned run_ind, map_offset, total_pages, need_pages, rem_pages;
+ unsigned i;
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
+ run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
+ >> pagesize_2pow);
+ total_pages = chunk->map[run_ind].npages;
+ need_pages = (size >> pagesize_2pow);
+ assert(need_pages <= total_pages);
+ rem_pages = total_pages - need_pages;
+
+ /* Split enough pages from the front of run to fit allocation size. */
+ map_offset = run_ind;
+ for (i = 0; i < need_pages; i++) {
+ chunk->map[map_offset + i].npages = need_pages;
+ chunk->map[map_offset + i].pos = i;
+ }
+
+ /* Keep track of trailing unused pages for later use. */
+ if (rem_pages > 0) {
+ /* Update map for trailing pages. */
+ map_offset += need_pages;
+ chunk->map[map_offset].npages = rem_pages;
+ chunk->map[map_offset].pos = POS_FREE;
+ chunk->map[map_offset + rem_pages - 1].npages = rem_pages;
+ chunk->map[map_offset + rem_pages - 1].pos = POS_FREE;
+ }
+
+ chunk->pages_used += need_pages;
+}
+
+static arena_chunk_t *
+arena_chunk_alloc(arena_t *arena)
+{
+ arena_chunk_t *chunk;
+
+ if (arena->spare != NULL) {
+ chunk = arena->spare;
+ arena->spare = NULL;
+
+ RB_INSERT(arena_chunk_tree_s, &arena->chunks, chunk);
+ } else {
+ chunk = (arena_chunk_t *)chunk_alloc(chunksize);
+ if (chunk == NULL)
+ return (NULL);
+#ifdef MALLOC_STATS
+ arena->stats.mapped += chunksize;
+#endif
+
+ chunk->arena = arena;
+
+ RB_INSERT(arena_chunk_tree_s, &arena->chunks, chunk);
+
+ /*
+ * Claim that no pages are in use, since the header is merely
+ * overhead.
+ */
+ chunk->pages_used = 0;
+
+ chunk->max_frun_npages = chunk_npages -
+ arena_chunk_header_npages;
+ chunk->min_frun_ind = arena_chunk_header_npages;
+
+ /*
+ * Initialize enough of the map to support one maximal free run.
+ */
+ chunk->map[arena_chunk_header_npages].npages = chunk_npages -
+ arena_chunk_header_npages;
+ chunk->map[arena_chunk_header_npages].pos = POS_FREE;
+ chunk->map[chunk_npages - 1].npages = chunk_npages -
+ arena_chunk_header_npages;
+ chunk->map[chunk_npages - 1].pos = POS_FREE;
+ }
+
+ return (chunk);
+}
+
+static void
+arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
+{
+
+ /*
+ * Remove chunk from the chunk tree, regardless of whether this chunk
+ * will be cached, so that the arena does not use it.
+ */
+ RB_REMOVE(arena_chunk_tree_s, &chunk->arena->chunks, chunk);
+
+ if (opt_hint == false) {
+ if (arena->spare != NULL) {
+ chunk_dealloc((void *)arena->spare, chunksize);
+#ifdef MALLOC_STATS
+ arena->stats.mapped -= chunksize;
+#endif
+ }
+ arena->spare = chunk;
+ } else {
+ assert(arena->spare == NULL);
+ chunk_dealloc((void *)chunk, chunksize);
+#ifdef MALLOC_STATS
+ arena->stats.mapped -= chunksize;
+#endif
+ }
+}
+
+static arena_run_t *
+arena_run_alloc(arena_t *arena, size_t size)
+{
+ arena_chunk_t *chunk;
+ arena_run_t *run;
+ unsigned need_npages, limit_pages, compl_need_npages;
+
+ assert(size <= (chunksize - (arena_chunk_header_npages <<
+ pagesize_2pow)));
+ assert((size & pagesize_mask) == 0);
+
+ /*
+ * Search through arena's chunks in address order for a free run that is
+ * large enough. Look for the first fit.
+ */
+ need_npages = (size >> pagesize_2pow);
+ limit_pages = chunk_npages - arena_chunk_header_npages;
+ compl_need_npages = limit_pages - need_npages;
+ RB_FOREACH(chunk, arena_chunk_tree_s, &arena->chunks) {
+ /*
+ * Avoid searching this chunk if there are not enough
+ * contiguous free pages for there to possibly be a large
+ * enough free run.
+ */
+ if (chunk->pages_used <= compl_need_npages &&
+ need_npages <= chunk->max_frun_npages) {
+ arena_chunk_map_t *mapelm;
+ unsigned i;
+ unsigned max_frun_npages = 0;
+ unsigned min_frun_ind = chunk_npages;
+
+ assert(chunk->min_frun_ind >=
+ arena_chunk_header_npages);
+ for (i = chunk->min_frun_ind; i < chunk_npages;) {
+ mapelm = &chunk->map[i];
+ if (mapelm->pos == POS_FREE) {
+ if (mapelm->npages >= need_npages) {
+ run = (arena_run_t *)
+ ((uintptr_t)chunk + (i <<
+ pagesize_2pow));
+ /* Update page map. */
+ arena_run_split(arena, run,
+ size);
+ return (run);
+ }
+ if (mapelm->npages >
+ max_frun_npages) {
+ max_frun_npages =
+ mapelm->npages;
+ }
+ if (i < min_frun_ind) {
+ min_frun_ind = i;
+ if (i < chunk->min_frun_ind)
+ chunk->min_frun_ind = i;
+ }
+ }
+ i += mapelm->npages;
+ }
+ /*
+ * Search failure. Reset cached chunk->max_frun_npages.
+ * chunk->min_frun_ind was already reset above (if
+ * necessary).
+ */
+ chunk->max_frun_npages = max_frun_npages;
+ }
+ }
+
+ /* No usable runs. Allocate a new chunk, then try again. */
+ chunk = arena_chunk_alloc(arena);
+ if (chunk == NULL)
+ return (NULL);
+ run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
+ pagesize_2pow));
+ /* Update page map. */
+ arena_run_split(arena, run, size);
+ return (run);
+}
+
+static void
+arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size)
+{
+ arena_chunk_t *chunk;
+ unsigned run_ind, run_pages;
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
+
+ run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
+ >> pagesize_2pow);
+ assert(run_ind >= arena_chunk_header_npages);
+ assert(run_ind < (chunksize >> pagesize_2pow));
+ run_pages = (size >> pagesize_2pow);
+ assert(run_pages == chunk->map[run_ind].npages);
+
+ /* Subtract pages from count of pages used in chunk. */
+ chunk->pages_used -= run_pages;
+
+ /* Mark run as deallocated. */
+ assert(chunk->map[run_ind].npages == run_pages);
+ chunk->map[run_ind].pos = POS_FREE;
+ assert(chunk->map[run_ind + run_pages - 1].npages == run_pages);
+ chunk->map[run_ind + run_pages - 1].pos = POS_FREE;
+
+ /*
+ * Tell the kernel that we don't need the data in this run, but only if
+ * requested via runtime configuration.
+ */
+ if (opt_hint)
+ madvise(run, size, MADV_FREE);
+
+ /* Try to coalesce with neighboring runs. */
+ if (run_ind > arena_chunk_header_npages &&
+ chunk->map[run_ind - 1].pos == POS_FREE) {
+ unsigned prev_npages;
+
+ /* Coalesce with previous run. */
+ prev_npages = chunk->map[run_ind - 1].npages;
+ run_ind -= prev_npages;
+ assert(chunk->map[run_ind].npages == prev_npages);
+ assert(chunk->map[run_ind].pos == POS_FREE);
+ run_pages += prev_npages;
+
+ chunk->map[run_ind].npages = run_pages;
+ assert(chunk->map[run_ind].pos == POS_FREE);
+ chunk->map[run_ind + run_pages - 1].npages = run_pages;
+ assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
+ }
+
+ if (run_ind + run_pages < chunk_npages &&
+ chunk->map[run_ind + run_pages].pos == POS_FREE) {
+ unsigned next_npages;
+
+ /* Coalesce with next run. */
+ next_npages = chunk->map[run_ind + run_pages].npages;
+ run_pages += next_npages;
+ assert(chunk->map[run_ind + run_pages - 1].npages ==
+ next_npages);
+ assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
+
+ chunk->map[run_ind].npages = run_pages;
+ chunk->map[run_ind].pos = POS_FREE;
+ chunk->map[run_ind + run_pages - 1].npages = run_pages;
+ assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
+ }
+
+ if (chunk->map[run_ind].npages > chunk->max_frun_npages)
+ chunk->max_frun_npages = chunk->map[run_ind].npages;
+ if (run_ind < chunk->min_frun_ind)
+ chunk->min_frun_ind = run_ind;
+
+ /* Deallocate chunk if it is now completely unused. */
+ if (chunk->pages_used == 0)
+ arena_chunk_dealloc(arena, chunk);
+}
+
+static arena_run_t *
+arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
+{
+ arena_run_t *run;
+ unsigned i, remainder;
+
+ /* Look for a usable run. */
+ if ((run = RB_MIN(arena_run_tree_s, &bin->runs)) != NULL) {
+ /* run is guaranteed to have available space. */
+ RB_REMOVE(arena_run_tree_s, &bin->runs, run);
+#ifdef MALLOC_STATS
+ bin->stats.reruns++;
+#endif
+ return (run);
+ }
+ /* No existing runs have any space available. */
+
+ /* Allocate a new run. */
+ run = arena_run_alloc(arena, bin->run_size);
+ if (run == NULL)
+ return (NULL);
+
+ /* Initialize run internals. */
+ run->bin = bin;
+
+ for (i = 0; i < bin->regs_mask_nelms; i++)
+ run->regs_mask[i] = UINT_MAX;
+ remainder = bin->nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1);
+ if (remainder != 0) {
+ /* The last element has spare bits that need to be unset. */
+ run->regs_mask[i] = (UINT_MAX >> ((1 << (SIZEOF_INT_2POW + 3))
+ - remainder));
+ }
+
+ run->regs_minelm = 0;
+
+ run->nfree = bin->nregs;
+#ifdef MALLOC_DEBUG
+ run->magic = ARENA_RUN_MAGIC;
+#endif
+
+#ifdef MALLOC_STATS
+ bin->stats.nruns++;
+ bin->stats.curruns++;
+ if (bin->stats.curruns > bin->stats.highruns)
+ bin->stats.highruns = bin->stats.curruns;
+#endif
+ return (run);
+}
+
+/* bin->runcur must have space available before this function is called. */
+static inline void *
+arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
+{
+ void *ret;
+
+ assert(run->magic == ARENA_RUN_MAGIC);
+ assert(run->nfree > 0);
+
+ ret = arena_run_reg_alloc(run, bin);
+ assert(ret != NULL);
+ run->nfree--;
+
+ return (ret);
+}
+
+/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
+static void *
+arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
+{
+
+ bin->runcur = arena_bin_nonfull_run_get(arena, bin);
+ if (bin->runcur == NULL)
+ return (NULL);
+ assert(bin->runcur->magic == ARENA_RUN_MAGIC);
+ assert(bin->runcur->nfree > 0);
+
+ return (arena_bin_malloc_easy(arena, bin, bin->runcur));
+}
+
+/*
+ * Calculate bin->run_size such that it meets the following constraints:
+ *
+ * *) bin->run_size >= min_run_size
+ * *) bin->run_size <= arena_maxclass
+ * *) bin->run_size <= RUN_MAX_SMALL
+ * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
+ *
+ * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
+ * also calculated here, since these settings are all interdependent.
+ */
+static size_t
+arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
+{
+ size_t try_run_size, good_run_size;
+ unsigned good_nregs, good_mask_nelms, good_reg0_offset;
+ unsigned try_nregs, try_mask_nelms, try_reg0_offset;
+ float max_ovrhd = RUN_MAX_OVRHD;
+
+ assert(min_run_size >= pagesize);
+ assert(min_run_size <= arena_maxclass);
+ assert(min_run_size <= RUN_MAX_SMALL);
+
+ /*
+ * Calculate known-valid settings before entering the run_size
+ * expansion loop, so that the first part of the loop always copies
+ * valid settings.
+ *
+ * The do..while loop iteratively reduces the number of regions until
+ * the run header and the regions no longer overlap. A closed formula
+ * would be quite messy, since there is an interdependency between the
+ * header's mask length and the number of regions.
+ */
+ try_run_size = min_run_size;
+ try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size)
+ + 1; /* Counter-act the first line of the loop. */
+ do {
+ try_nregs--;
+ try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
+ ((try_nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0);
+ try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
+ } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
+ > try_reg0_offset);
+
+ /* run_size expansion loop. */
+ do {
+ /*
+ * Copy valid settings before trying more aggressive settings.
+ */
+ good_run_size = try_run_size;
+ good_nregs = try_nregs;
+ good_mask_nelms = try_mask_nelms;
+ good_reg0_offset = try_reg0_offset;
+
+ /* Try more aggressive settings. */
+ try_run_size += pagesize;
+ try_nregs = ((try_run_size - sizeof(arena_run_t)) /
+ bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */
+ do {
+ try_nregs--;
+ try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
+ ((try_nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1)) ?
+ 1 : 0);
+ try_reg0_offset = try_run_size - (try_nregs *
+ bin->reg_size);
+ } while (sizeof(arena_run_t) + (sizeof(unsigned) *
+ (try_mask_nelms - 1)) > try_reg0_offset);
+ } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
+ && max_ovrhd > RUN_MAX_OVRHD_RELAX / ((float)(bin->reg_size << 3))
+ && ((float)(try_reg0_offset)) / ((float)(try_run_size)) >
+ max_ovrhd);
+
+ assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
+ <= good_reg0_offset);
+ assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs);
+
+ /* Copy final settings. */
+ bin->run_size = good_run_size;
+ bin->nregs = good_nregs;
+ bin->regs_mask_nelms = good_mask_nelms;
+ bin->reg0_offset = good_reg0_offset;
+
+ return (good_run_size);
+}
+
+static void *
+arena_malloc(arena_t *arena, size_t size)
+{
+ void *ret;
+
+ assert(arena != NULL);
+ assert(arena->magic == ARENA_MAGIC);
+ assert(size != 0);
+ assert(QUANTUM_CEILING(size) <= arena_maxclass);
+
+ if (size <= bin_maxclass) {
+ arena_bin_t *bin;
+ arena_run_t *run;
+
+ /* Small allocation. */
+
+ if (size < small_min) {
+ /* Tiny. */
+ size = pow2_ceil(size);
+ bin = &arena->bins[ffs((int)(size >> (TINY_MIN_2POW +
+ 1)))];
+#if (!defined(NDEBUG) || defined(MALLOC_STATS))
+ /*
+ * Bin calculation is always correct, but we may need
+ * to fix size for the purposes of assertions and/or
+ * stats accuracy.
+ */
+ if (size < (1 << TINY_MIN_2POW))
+ size = (1 << TINY_MIN_2POW);
+#endif
+ } else if (size <= small_max) {
+ /* Quantum-spaced. */
+ size = QUANTUM_CEILING(size);
+ bin = &arena->bins[ntbins + (size >> opt_quantum_2pow)
+ - 1];
+ } else {
+ /* Sub-page. */
+ size = pow2_ceil(size);
+ bin = &arena->bins[ntbins + nqbins
+ + (ffs((int)(size >> opt_small_max_2pow)) - 2)];
+ }
+ assert(size == bin->reg_size);
+
+ malloc_mutex_lock(&arena->mtx);
+ if ((run = bin->runcur) != NULL && run->nfree > 0)
+ ret = arena_bin_malloc_easy(arena, bin, run);
+ else
+ ret = arena_bin_malloc_hard(arena, bin);
+
+ if (ret == NULL) {
+ malloc_mutex_unlock(&arena->mtx);
+ return (NULL);
+ }
+
+#ifdef MALLOC_STATS
+ bin->stats.nrequests++;
+ arena->stats.nmalloc_small++;
+ arena->stats.allocated_small += size;
+#endif
+ } else {
+ /* Large allocation. */
+ size = PAGE_CEILING(size);
+ malloc_mutex_lock(&arena->mtx);
+ ret = (void *)arena_run_alloc(arena, size);
+ if (ret == NULL) {
+ malloc_mutex_unlock(&arena->mtx);
+ return (NULL);
+ }
+#ifdef MALLOC_STATS
+ arena->stats.nmalloc_large++;
+ arena->stats.allocated_large += size;
+#endif
+ }
+
+ malloc_mutex_unlock(&arena->mtx);
+
+ if (opt_junk)
+ memset(ret, 0xa5, size);
+ else if (opt_zero)
+ memset(ret, 0, size);
+ return (ret);
+}
+
+static inline void
+arena_palloc_trim(arena_t *arena, arena_chunk_t *chunk, unsigned pageind,
+ unsigned npages)
+{
+ unsigned i;
+
+ assert(npages > 0);
+
+ /*
+ * Modifiy the map such that arena_run_dalloc() sees the run as
+ * separately allocated.
+ */
+ for (i = 0; i < npages; i++) {
+ chunk->map[pageind + i].npages = npages;
+ chunk->map[pageind + i].pos = i;
+ }
+ arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)chunk + (pageind <<
+ pagesize_2pow)), npages << pagesize_2pow);
+}
+
+/* Only handles large allocations that require more than page alignment. */
+static void *
+arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
+{
+ void *ret;
+ size_t offset;
+ arena_chunk_t *chunk;
+ unsigned pageind, i, npages;
+
+ assert((size & pagesize_mask) == 0);
+ assert((alignment & pagesize_mask) == 0);
+
+ npages = size >> pagesize_2pow;
+
+ malloc_mutex_lock(&arena->mtx);
+ ret = (void *)arena_run_alloc(arena, alloc_size);
+ if (ret == NULL) {
+ malloc_mutex_unlock(&arena->mtx);
+ return (NULL);
+ }
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
+
+ offset = (uintptr_t)ret & (alignment - 1);
+ assert((offset & pagesize_mask) == 0);
+ assert(offset < alloc_size);
+ if (offset == 0) {
+ pageind = (((uintptr_t)ret - (uintptr_t)chunk) >>
+ pagesize_2pow);
+
+ /* Update the map for the run to be kept. */
+ for (i = 0; i < npages; i++) {
+ chunk->map[pageind + i].npages = npages;
+ assert(chunk->map[pageind + i].pos == i);
+ }
+
+ /* Trim trailing space. */
+ arena_palloc_trim(arena, chunk, pageind + npages,
+ (alloc_size - size) >> pagesize_2pow);
+ } else {
+ size_t leadsize, trailsize;
+
+ leadsize = alignment - offset;
+ ret = (void *)((uintptr_t)ret + leadsize);
+ pageind = (((uintptr_t)ret - (uintptr_t)chunk) >>
+ pagesize_2pow);
+
+ /* Update the map for the run to be kept. */
+ for (i = 0; i < npages; i++) {
+ chunk->map[pageind + i].npages = npages;
+ chunk->map[pageind + i].pos = i;
+ }
+
+ /* Trim leading space. */
+ arena_palloc_trim(arena, chunk, pageind - (leadsize >>
+ pagesize_2pow), leadsize >> pagesize_2pow);
+
+ trailsize = alloc_size - leadsize - size;
+ if (trailsize != 0) {
+ /* Trim trailing space. */
+ assert(trailsize < alloc_size);
+ arena_palloc_trim(arena, chunk, pageind + npages,
+ trailsize >> pagesize_2pow);
+ }
+ }
+
+#ifdef MALLOC_STATS
+ arena->stats.nmalloc_large++;
+ arena->stats.allocated_large += size;
+#endif
+ malloc_mutex_unlock(&arena->mtx);
+
+ if (opt_junk)
+ memset(ret, 0xa5, size);
+ else if (opt_zero)
+ memset(ret, 0, size);
+ return (ret);
+}
+
+/* Return the size of the allocation pointed to by ptr. */
+static size_t
+arena_salloc(const void *ptr)
+{
+ size_t ret;
+ arena_chunk_t *chunk;
+ arena_chunk_map_t *mapelm;
+ unsigned pageind;
+
+ assert(ptr != NULL);
+ assert(CHUNK_ADDR2BASE(ptr) != ptr);
+
+ /*
+ * No arena data structures that we query here can change in a way that
+ * affects this function, so we don't need to lock.
+ */
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow);
+ mapelm = &chunk->map[pageind];
+ if (mapelm->pos != 0 || ptr != (void *)((uintptr_t)chunk) + (pageind <<
+ pagesize_2pow)) {
+ arena_run_t *run;
+
+ pageind -= mapelm->pos;
+
+ run = (arena_run_t *)((uintptr_t)chunk + (pageind <<
+ pagesize_2pow));
+ assert(run->magic == ARENA_RUN_MAGIC);
+ ret = run->bin->reg_size;
+ } else
+ ret = mapelm->npages << pagesize_2pow;
+
+ return (ret);
+}
+
+static void *
+arena_ralloc(void *ptr, size_t size, size_t oldsize)
+{
+ void *ret;
+
+ /* Avoid moving the allocation if the size class would not change. */
+ if (size < small_min) {
+ if (oldsize < small_min &&
+ ffs((int)(pow2_ceil(size) >> (TINY_MIN_2POW + 1)))
+ == ffs((int)(pow2_ceil(oldsize) >> (TINY_MIN_2POW + 1))))
+ goto IN_PLACE;
+ } else if (size <= small_max) {
+ if (oldsize >= small_min && oldsize <= small_max &&
+ (QUANTUM_CEILING(size) >> opt_quantum_2pow)
+ == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow))
+ goto IN_PLACE;
+ } else {
+ /*
+ * We make no attempt to resize runs here, though it would be
+ * possible to do so.
+ */
+ if (oldsize > small_max && PAGE_CEILING(size) == oldsize)
+ goto IN_PLACE;
+ }
+
+ /*
+ * If we get here, then size and oldsize are different enough that we
+ * need to use a different size class. In that case, fall back to
+ * allocating new space and copying.
+ */
+ ret = arena_malloc(choose_arena(), size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (size < oldsize)
+ memcpy(ret, ptr, size);
+ else
+ memcpy(ret, ptr, oldsize);
+ idalloc(ptr);
+ return (ret);
+IN_PLACE:
+ if (opt_junk && size < oldsize)
+ memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
+ else if (opt_zero && size > oldsize)
+ memset((void *)((uintptr_t)ptr + size), 0, oldsize - size);
+ return (ptr);
+}
+
+static void
+arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
+{
+ unsigned pageind;
+ arena_chunk_map_t *mapelm;
+ size_t size;
+
+ assert(arena != NULL);
+ assert(arena->magic == ARENA_MAGIC);
+ assert(chunk->arena == arena);
+ assert(ptr != NULL);
+ assert(CHUNK_ADDR2BASE(ptr) != ptr);
+
+ pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow);
+ mapelm = &chunk->map[pageind];
+ if (mapelm->pos != 0 || ptr != (void *)((uintptr_t)chunk) + (pageind <<
+ pagesize_2pow)) {
+ arena_run_t *run;
+ arena_bin_t *bin;
+
+ /* Small allocation. */
+
+ pageind -= mapelm->pos;
+
+ run = (arena_run_t *)((uintptr_t)chunk + (pageind <<
+ pagesize_2pow));
+ assert(run->magic == ARENA_RUN_MAGIC);
+ bin = run->bin;
+ size = bin->reg_size;
+
+ if (opt_junk)
+ memset(ptr, 0x5a, size);
+
+ malloc_mutex_lock(&arena->mtx);
+ arena_run_reg_dalloc(run, bin, ptr, size);
+ run->nfree++;
+
+ if (run->nfree == bin->nregs) {
+ /* Deallocate run. */
+ if (run == bin->runcur)
+ bin->runcur = NULL;
+ else if (bin->nregs != 1) {
+ /*
+ * This block's conditional is necessary because
+ * if the run only contains one region, then it
+ * never gets inserted into the non-full runs
+ * tree.
+ */
+ RB_REMOVE(arena_run_tree_s, &bin->runs, run);
+ }
+#ifdef MALLOC_DEBUG
+ run->magic = 0;
+#endif
+ arena_run_dalloc(arena, run, bin->run_size);
+#ifdef MALLOC_STATS
+ bin->stats.curruns--;
+#endif
+ } else if (run->nfree == 1 && run != bin->runcur) {
+ /*
+ * Make sure that bin->runcur always refers to the
+ * lowest non-full run, if one exists.
+ */
+ if (bin->runcur == NULL)
+ bin->runcur = run;
+ else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
+ /* Switch runcur. */
+ if (bin->runcur->nfree > 0) {
+ /* Insert runcur. */
+ RB_INSERT(arena_run_tree_s, &bin->runs,
+ bin->runcur);
+ }
+ bin->runcur = run;
+ } else
+ RB_INSERT(arena_run_tree_s, &bin->runs, run);
+ }
+#ifdef MALLOC_STATS
+ arena->stats.allocated_small -= size;
+ arena->stats.ndalloc_small++;
+#endif
+ } else {
+ /* Large allocation. */
+
+ size = mapelm->npages << pagesize_2pow;
+ assert((((uintptr_t)ptr) & pagesize_mask) == 0);
+
+ if (opt_junk)
+ memset(ptr, 0x5a, size);
+
+ malloc_mutex_lock(&arena->mtx);
+ arena_run_dalloc(arena, (arena_run_t *)ptr, size);
+#ifdef MALLOC_STATS
+ arena->stats.allocated_large -= size;
+ arena->stats.ndalloc_large++;
+#endif
+ }
+
+ malloc_mutex_unlock(&arena->mtx);
+}
+
+static bool
+arena_new(arena_t *arena)
+{
+ unsigned i;
+ arena_bin_t *bin;
+ size_t pow2_size, prev_run_size;
+
+ malloc_mutex_init(&arena->mtx);
+
+#ifdef MALLOC_STATS
+ memset(&arena->stats, 0, sizeof(arena_stats_t));
+#endif
+
+ /* Initialize chunks. */
+ RB_INIT(&arena->chunks);
+ arena->spare = NULL;
+
+ /* Initialize bins. */
+ prev_run_size = pagesize;
+
+ /* (2^n)-spaced tiny bins. */
+ for (i = 0; i < ntbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ RB_INIT(&bin->runs);
+
+ bin->reg_size = (1 << (TINY_MIN_2POW + i));
+
+ prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+ /* Quantum-spaced bins. */
+ for (; i < ntbins + nqbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ RB_INIT(&bin->runs);
+
+ bin->reg_size = quantum * (i - ntbins + 1);
+
+ pow2_size = pow2_ceil(quantum * (i - ntbins + 1));
+ prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+ /* (2^n)-spaced sub-page bins. */
+ for (; i < ntbins + nqbins + nsbins; i++) {
+ bin = &arena->bins[i];
+ bin->runcur = NULL;
+ RB_INIT(&bin->runs);
+
+ bin->reg_size = (small_max << (i - (ntbins + nqbins) + 1));
+
+ prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
+
+#ifdef MALLOC_STATS
+ memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
+#endif
+ }
+
+#ifdef MALLOC_DEBUG
+ arena->magic = ARENA_MAGIC;
+#endif
+
+ return (false);
+}
+
+/* Create a new arena and insert it into the arenas array at index ind. */
+static arena_t *
+arenas_extend(unsigned ind)
+{
+ arena_t *ret;
+
+ /* Allocate enough space for trailing bins. */
+ ret = (arena_t *)base_alloc(sizeof(arena_t)
+ + (sizeof(arena_bin_t) * (ntbins + nqbins + nsbins - 1)));
+ if (ret != NULL && arena_new(ret) == false) {
+ arenas[ind] = ret;
+ return (ret);
+ }
+ /* Only reached if there is an OOM error. */
+
+ /*
+ * OOM here is quite inconvenient to propagate, since dealing with it
+ * would require a check for failure in the fast path. Instead, punt
+ * by using arenas[0]. In practice, this is an extremely unlikely
+ * failure.
+ */
+ _malloc_message(_getprogname(),
+ ": (malloc) Error initializing arena\n", "", "");
+ if (opt_abort)
+ abort();
+
+ return (arenas[0]);
+}
+
+/*
+ * End arena.
+ */
+/******************************************************************************/
+/*
+ * Begin general internal functions.
+ */
+
+static void *
+huge_malloc(size_t size)
+{
+ void *ret;
+ size_t csize;
+ chunk_node_t *node;
+
+ /* Allocate one or more contiguous chunks for this request. */
+
+ csize = CHUNK_CEILING(size);
+ if (csize == 0) {
+ /* size is large enough to cause size_t wrap-around. */
+ return (NULL);
+ }
+
+ /* Allocate a chunk node with which to track the chunk. */
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ return (NULL);
+
+ ret = chunk_alloc(csize);
+ if (ret == NULL) {
+ base_chunk_node_dealloc(node);
+ return (NULL);
+ }
+
+ /* Insert node into huge. */
+ node->chunk = ret;
+ node->size = csize;
+
+ malloc_mutex_lock(&chunks_mtx);
+ RB_INSERT(chunk_tree_s, &huge, node);
+#ifdef MALLOC_STATS
+ huge_nmalloc++;
+ huge_allocated += csize;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ if (opt_junk)
+ memset(ret, 0xa5, csize);
+ else if (opt_zero)
+ memset(ret, 0, csize);
+
+ return (ret);
+}
+
+/* Only handles large allocations that require more than chunk alignment. */
+static void *
+huge_palloc(size_t alignment, size_t size)
+{
+ void *ret;
+ size_t alloc_size, chunk_size, offset;
+ chunk_node_t *node;
+
+ /*
+ * This allocation requires alignment that is even larger than chunk
+ * alignment. This means that huge_malloc() isn't good enough.
+ *
+ * Allocate almost twice as many chunks as are demanded by the size or
+ * alignment, in order to assure the alignment can be achieved, then
+ * unmap leading and trailing chunks.
+ */
+ assert(alignment >= chunksize);
+
+ chunk_size = CHUNK_CEILING(size);
+
+ if (size >= alignment)
+ alloc_size = chunk_size + alignment - chunksize;
+ else
+ alloc_size = (alignment << 1) - chunksize;
+
+ /* Allocate a chunk node with which to track the chunk. */
+ node = base_chunk_node_alloc();
+ if (node == NULL)
+ return (NULL);
+
+ ret = chunk_alloc(alloc_size);
+ if (ret == NULL) {
+ base_chunk_node_dealloc(node);
+ return (NULL);
+ }
+
+ offset = (uintptr_t)ret & (alignment - 1);
+ assert((offset & chunksize_mask) == 0);
+ assert(offset < alloc_size);
+ if (offset == 0) {
+ /* Trim trailing space. */
+ chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
+ - chunk_size);
+ } else {
+ size_t trailsize;
+
+ /* Trim leading space. */
+ chunk_dealloc(ret, alignment - offset);
+
+ ret = (void *)((uintptr_t)ret + (alignment - offset));
+
+ trailsize = alloc_size - (alignment - offset) - chunk_size;
+ if (trailsize != 0) {
+ /* Trim trailing space. */
+ assert(trailsize < alloc_size);
+ chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
+ trailsize);
+ }
+ }
+
+ /* Insert node into huge. */
+ node->chunk = ret;
+ node->size = chunk_size;
+
+ malloc_mutex_lock(&chunks_mtx);
+ RB_INSERT(chunk_tree_s, &huge, node);
+#ifdef MALLOC_STATS
+ huge_nmalloc++;
+ huge_allocated += chunk_size;
+#endif
+ malloc_mutex_unlock(&chunks_mtx);
+
+ if (opt_junk)
+ memset(ret, 0xa5, chunk_size);
+ else if (opt_zero)
+ memset(ret, 0, chunk_size);
+
+ return (ret);
+}
+
+static void *
+huge_ralloc(void *ptr, size_t size, size_t oldsize)
+{
+ void *ret;
+
+ /* Avoid moving the allocation if the size class would not change. */
+ if (oldsize > arena_maxclass &&
+ CHUNK_CEILING(size) == CHUNK_CEILING(oldsize))
+ return (ptr);
+
+ /*
+ * If we get here, then size and oldsize are different enough that we
+ * need to use a different size class. In that case, fall back to
+ * allocating new space and copying.
+ */
+ ret = huge_malloc(size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (CHUNK_ADDR2BASE(ptr) == ptr) {
+ /* The old allocation is a chunk. */
+ if (size < oldsize)
+ memcpy(ret, ptr, size);
+ else
+ memcpy(ret, ptr, oldsize);
+ } else {
+ /* The old allocation is a region. */
+ assert(oldsize < size);
+ memcpy(ret, ptr, oldsize);
+ }
+ idalloc(ptr);
+ return (ret);
+}
+
+static void
+huge_dalloc(void *ptr)
+{
+ chunk_node_t key;
+ chunk_node_t *node;
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ /* Extract from tree of huge allocations. */
+ key.chunk = ptr;
+ node = RB_FIND(chunk_tree_s, &huge, &key);
+ assert(node != NULL);
+ assert(node->chunk == ptr);
+ RB_REMOVE(chunk_tree_s, &huge, node);
+
+#ifdef MALLOC_STATS
+ huge_ndalloc++;
+ huge_allocated -= node->size;
+#endif
+
+ malloc_mutex_unlock(&chunks_mtx);
+
+ /* Unmap chunk. */
+#ifdef USE_BRK
+ if (opt_junk)
+ memset(node->chunk, 0x5a, node->size);
+#endif
+ chunk_dealloc(node->chunk, node->size);
+
+ base_chunk_node_dealloc(node);
+}
+
+static void *
+imalloc(size_t size)
+{
+ void *ret;
+
+ assert(size != 0);
+
+ if (size <= arena_maxclass)
+ ret = arena_malloc(choose_arena(), size);
+ else
+ ret = huge_malloc(size);
+
+ return (ret);
+}
+
+static void *
+ipalloc(size_t alignment, size_t size)
+{
+ void *ret;
+ size_t ceil_size;
+
+ /*
+ * Round size up to the nearest multiple of alignment.
+ *
+ * This done, we can take advantage of the fact that for each small
+ * size class, every object is aligned at the smallest power of two
+ * that is non-zero in the base two representation of the size. For
+ * example:
+ *
+ * Size | Base 2 | Minimum alignment
+ * -----+----------+------------------
+ * 96 | 1100000 | 32
+ * 144 | 10100000 | 32
+ * 192 | 11000000 | 64
+ *
+ * Depending on runtime settings, it is possible that arena_malloc()
+ * will further round up to a power of two, but that never causes
+ * correctness issues.
+ */
+ ceil_size = (size + (alignment - 1)) & (-alignment);
+ /*
+ * (ceil_size < size) protects against the combination of maximal
+ * alignment and size greater than maximal alignment.
+ */
+ if (ceil_size < size) {
+ /* size_t overflow. */
+ return (NULL);
+ }
+
+ if (ceil_size <= pagesize || (alignment <= pagesize
+ && ceil_size <= arena_maxclass))
+ ret = arena_malloc(choose_arena(), ceil_size);
+ else {
+ size_t run_size;
+
+ /*
+ * We can't achieve sub-page alignment, so round up alignment
+ * permanently; it makes later calculations simpler.
+ */
+ alignment = PAGE_CEILING(alignment);
+ ceil_size = PAGE_CEILING(size);
+ /*
+ * (ceil_size < size) protects against very large sizes within
+ * pagesize of SIZE_T_MAX.
+ *
+ * (ceil_size + alignment < ceil_size) protects against the
+ * combination of maximal alignment and ceil_size large enough
+ * to cause overflow. This is similar to the first overflow
+ * check above, but it needs to be repeated due to the new
+ * ceil_size value, which may now be *equal* to maximal
+ * alignment, whereas before we only detected overflow if the
+ * original size was *greater* than maximal alignment.
+ */
+ if (ceil_size < size || ceil_size + alignment < ceil_size) {
+ /* size_t overflow. */
+ return (NULL);
+ }
+
+ /*
+ * Calculate the size of the over-size run that arena_palloc()
+ * would need to allocate in order to guarantee the alignment.
+ */
+ if (ceil_size >= alignment)
+ run_size = ceil_size + alignment - pagesize;
+ else {
+ /*
+ * It is possible that (alignment << 1) will cause
+ * overflow, but it doesn't matter because we also
+ * subtract pagesize, which in the case of overflow
+ * leaves us with a very large run_size. That causes
+ * the first conditional below to fail, which means
+ * that the bogus run_size value never gets used for
+ * anything important.
+ */
+ run_size = (alignment << 1) - pagesize;
+ }
+
+ if (run_size <= arena_maxclass) {
+ ret = arena_palloc(choose_arena(), alignment, ceil_size,
+ run_size);
+ } else if (alignment <= chunksize)
+ ret = huge_malloc(ceil_size);
+ else
+ ret = huge_palloc(alignment, ceil_size);
+ }
+
+ assert(((uintptr_t)ret & (alignment - 1)) == 0);
+ return (ret);
+}
+
+static void *
+icalloc(size_t size)
+{
+ void *ret;
+
+ if (size <= arena_maxclass) {
+ ret = arena_malloc(choose_arena(), size);
+ if (ret == NULL)
+ return (NULL);
+ memset(ret, 0, size);
+ } else {
+ /*
+ * The virtual memory system provides zero-filled pages, so
+ * there is no need to do so manually, unless opt_junk is
+ * enabled, in which case huge_malloc() fills huge allocations
+ * with junk.
+ */
+ ret = huge_malloc(size);
+ if (ret == NULL)
+ return (NULL);
+
+ if (opt_junk)
+ memset(ret, 0, size);
+#ifdef USE_BRK
+ else if ((uintptr_t)ret >= (uintptr_t)brk_base
+ && (uintptr_t)ret < (uintptr_t)brk_max) {
+ /*
+ * This may be a re-used brk chunk. Therefore, zero
+ * the memory.
+ */
+ memset(ret, 0, size);
+ }
+#endif
+ }
+
+ return (ret);
+}
+
+static size_t
+isalloc(const void *ptr)
+{
+ size_t ret;
+ arena_chunk_t *chunk;
+
+ assert(ptr != NULL);
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ if (chunk != ptr) {
+ /* Region. */
+ assert(chunk->arena->magic == ARENA_MAGIC);
+
+ ret = arena_salloc(ptr);
+ } else {
+ chunk_node_t *node, key;
+
+ /* Chunk (huge allocation). */
+
+ malloc_mutex_lock(&chunks_mtx);
+
+ /* Extract from tree of huge allocations. */
+ key.chunk = __DECONST(void *, ptr);
+ node = RB_FIND(chunk_tree_s, &huge, &key);
+ assert(node != NULL);
+
+ ret = node->size;
+
+ malloc_mutex_unlock(&chunks_mtx);
+ }
+
+ return (ret);
+}
+
+static void *
+iralloc(void *ptr, size_t size)
+{
+ void *ret;
+ size_t oldsize;
+
+ assert(ptr != NULL);
+ assert(size != 0);
+
+ oldsize = isalloc(ptr);
+
+ if (size <= arena_maxclass)
+ ret = arena_ralloc(ptr, size, oldsize);
+ else
+ ret = huge_ralloc(ptr, size, oldsize);
+
+ return (ret);
+}
+
+static void
+idalloc(void *ptr)
+{
+ arena_chunk_t *chunk;
+
+ assert(ptr != NULL);
+
+ chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+ if (chunk != ptr) {
+ /* Region. */
+ arena_dalloc(chunk->arena, chunk, ptr);
+ } else
+ huge_dalloc(ptr);
+}
+
+static void
+malloc_print_stats(void)
+{
+
+ if (opt_print_stats) {
+ char s[UMAX2S_BUFSIZE];
+ _malloc_message("___ Begin malloc statistics ___\n", "", "",
+ "");
+ _malloc_message("Assertions ",
+#ifdef NDEBUG
+ "disabled",
+#else
+ "enabled",
+#endif
+ "\n", "");
+ _malloc_message("Boolean MALLOC_OPTIONS: ",
+ opt_abort ? "A" : "a",
+ opt_junk ? "J" : "j",
+ opt_hint ? "H" : "h");
+ _malloc_message(opt_utrace ? "PU" : "Pu",
+ opt_sysv ? "V" : "v",
+ opt_xmalloc ? "X" : "x",
+ opt_zero ? "Z\n" : "z\n");
+
+ _malloc_message("CPUs: ", umax2s(ncpus, s), "\n", "");
+ _malloc_message("Max arenas: ", umax2s(narenas, s), "\n", "");
+ _malloc_message("Pointer size: ", umax2s(sizeof(void *), s),
+ "\n", "");
+ _malloc_message("Quantum size: ", umax2s(quantum, s), "\n", "");
+ _malloc_message("Max small size: ", umax2s(small_max, s), "\n",
+ "");
+
+ _malloc_message("Chunk size: ", umax2s(chunksize, s), "", "");
+ _malloc_message(" (2^", umax2s(opt_chunk_2pow, s), ")\n", "");
+
+#ifdef MALLOC_STATS
+ {
+ size_t allocated, mapped;
+ unsigned i;
+ arena_t *arena;
+
+ /* Calculate and print allocated/mapped stats. */
+
+ /* arenas. */
+ for (i = 0, allocated = 0; i < narenas; i++) {
+ if (arenas[i] != NULL) {
+ malloc_mutex_lock(&arenas[i]->mtx);
+ allocated +=
+ arenas[i]->stats.allocated_small;
+ allocated +=
+ arenas[i]->stats.allocated_large;
+ malloc_mutex_unlock(&arenas[i]->mtx);
+ }
+ }
+
+ /* huge/base. */
+ malloc_mutex_lock(&chunks_mtx);
+ allocated += huge_allocated;
+ mapped = stats_chunks.curchunks * chunksize;
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_mutex_lock(&base_mtx);
+ mapped += base_mapped;
+ malloc_mutex_unlock(&base_mtx);
+
+ malloc_printf("Allocated: %zu, mapped: %zu\n",
+ allocated, mapped);
+
+ /* Print chunk stats. */
+ {
+ chunk_stats_t chunks_stats;
+
+ malloc_mutex_lock(&chunks_mtx);
+ chunks_stats = stats_chunks;
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_printf("chunks: nchunks "
+ "highchunks curchunks\n");
+ malloc_printf(" %13llu%13lu%13lu\n",
+ chunks_stats.nchunks,
+ chunks_stats.highchunks,
+ chunks_stats.curchunks);
+ }
+
+ /* Print chunk stats. */
+ malloc_printf(
+ "huge: nmalloc ndalloc allocated\n");
+ malloc_printf(" %12llu %12llu %12zu\n",
+ huge_nmalloc, huge_ndalloc, huge_allocated
+ * chunksize);
+
+ /* Print stats for each arena. */
+ for (i = 0; i < narenas; i++) {
+ arena = arenas[i];
+ if (arena != NULL) {
+ malloc_printf(
+ "\narenas[%u]:\n", i);
+ malloc_mutex_lock(&arena->mtx);
+ stats_print(arena);
+ malloc_mutex_unlock(&arena->mtx);
+ }
+ }
+ }
+#endif /* #ifdef MALLOC_STATS */
+ _malloc_message("--- End malloc statistics ---\n", "", "", "");
+ }
+}
+
+/*
+ * FreeBSD's pthreads implementation calls malloc(3), so the malloc
+ * implementation has to take pains to avoid infinite recursion during
+ * initialization.
+ */
+static inline bool
+malloc_init(void)
+{
+
+ if (malloc_initialized == false)
+ return (malloc_init_hard());
+
+ return (false);
+}
+
+static bool
+malloc_init_hard(void)
+{
+ unsigned i, j;
+ int linklen;
+ char buf[PATH_MAX + 1];
+ const char *opts;
+
+ malloc_mutex_lock(&init_lock);
+ if (malloc_initialized) {
+ /*
+ * Another thread initialized the allocator before this one
+ * acquired init_lock.
+ */
+ malloc_mutex_unlock(&init_lock);
+ return (false);
+ }
+
+ /* Get number of CPUs. */
+ {
+ int mib[2];
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(ncpus);
+ if (sysctl(mib, 2, &ncpus, &len, (void *) 0, 0) == -1) {
+ /* Error. */
+ ncpus = 1;
+ }
+ }
+
+ /* Get page size. */
+ {
+ long result;
+
+ result = sysconf(_SC_PAGESIZE);
+ assert(result != -1);
+ pagesize = (unsigned) result;
+
+ /*
+ * We assume that pagesize is a power of 2 when calculating
+ * pagesize_mask and pagesize_2pow.
+ */
+ assert(((result - 1) & result) == 0);
+ pagesize_mask = result - 1;
+ pagesize_2pow = ffs((int)result) - 1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ /* Get runtime configuration. */
+ switch (i) {
+ case 0:
+ if ((linklen = readlink("/etc/malloc.conf", buf,
+ sizeof(buf) - 1)) != -1) {
+ /*
+ * Use the contents of the "/etc/malloc.conf"
+ * symbolic link's name.
+ */
+ buf[linklen] = '\0';
+ opts = buf;
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ case 1:
+ if (issetugid() == 0 && (opts =
+ getenv("MALLOC_OPTIONS")) != NULL) {
+ /*
+ * Do nothing; opts is already initialized to
+ * the value of the MALLOC_OPTIONS environment
+ * variable.
+ */
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ case 2:
+ if (_malloc_options != NULL) {
+ /*
+ * Use options that were compiled into the program.
+ */
+ opts = _malloc_options;
+ } else {
+ /* No configuration specified. */
+ buf[0] = '\0';
+ opts = buf;
+ }
+ break;
+ default:
+ /* NOTREACHED */
+ assert(false);
+ }
+
+ for (j = 0; opts[j] != '\0'; j++) {
+ switch (opts[j]) {
+ case 'a':
+ opt_abort = false;
+ break;
+ case 'A':
+ opt_abort = true;
+ break;
+ case 'h':
+ opt_hint = false;
+ break;
+ case 'H':
+ opt_hint = true;
+ break;
+ case 'j':
+ opt_junk = false;
+ break;
+ case 'J':
+ opt_junk = true;
+ break;
+ case 'k':
+ /*
+ * Chunks always require at least one header
+ * page, so chunks can never be smaller than
+ * two pages.
+ */
+ if (opt_chunk_2pow > pagesize_2pow + 1)
+ opt_chunk_2pow--;
+ break;
+ case 'K':
+ /*
+ * There must be fewer pages in a chunk than
+ * can be recorded by the pos field of
+ * arena_chunk_map_t, in order to make POS_FREE
+ * special.
+ */
+ if (opt_chunk_2pow - pagesize_2pow
+ < (sizeof(uint32_t) << 3) - 1)
+ opt_chunk_2pow++;
+ break;
+ case 'n':
+ opt_narenas_lshift--;
+ break;
+ case 'N':
+ opt_narenas_lshift++;
+ break;
+ case 'p':
+ opt_print_stats = false;
+ break;
+ case 'P':
+ opt_print_stats = true;
+ break;
+ case 'q':
+ if (opt_quantum_2pow > QUANTUM_2POW_MIN)
+ opt_quantum_2pow--;
+ break;
+ case 'Q':
+ if (opt_quantum_2pow < pagesize_2pow - 1)
+ opt_quantum_2pow++;
+ break;
+ case 's':
+ if (opt_small_max_2pow > QUANTUM_2POW_MIN)
+ opt_small_max_2pow--;
+ break;
+ case 'S':
+ if (opt_small_max_2pow < pagesize_2pow - 1)
+ opt_small_max_2pow++;
+ break;
+ case 'u':
+ opt_utrace = false;
+ break;
+ case 'U':
+ opt_utrace = true;
+ break;
+ case 'v':
+ opt_sysv = false;
+ break;
+ case 'V':
+ opt_sysv = true;
+ break;
+ case 'x':
+ opt_xmalloc = false;
+ break;
+ case 'X':
+ opt_xmalloc = true;
+ break;
+ case 'z':
+ opt_zero = false;
+ break;
+ case 'Z':
+ opt_zero = true;
+ break;
+ default: {
+ char cbuf[2];
+
+ cbuf[0] = opts[j];
+ cbuf[1] = '\0';
+ _malloc_message(_getprogname(),
+ ": (malloc) Unsupported character in "
+ "malloc options: '", cbuf, "'\n");
+ }
+ }
+ }
+ }
+
+ /* Take care to call atexit() only once. */
+ if (opt_print_stats) {
+ /* Print statistics at exit. */
+ atexit(malloc_print_stats);
+ }
+
+ /* Set variables according to the value of opt_small_max_2pow. */
+ if (opt_small_max_2pow < opt_quantum_2pow)
+ opt_small_max_2pow = opt_quantum_2pow;
+ small_max = (1 << opt_small_max_2pow);
+
+ /* Set bin-related variables. */
+ bin_maxclass = (pagesize >> 1);
+ assert(opt_quantum_2pow >= TINY_MIN_2POW);
+ ntbins = opt_quantum_2pow - TINY_MIN_2POW;
+ assert(ntbins <= opt_quantum_2pow);
+ nqbins = (small_max >> opt_quantum_2pow);
+ nsbins = pagesize_2pow - opt_small_max_2pow - 1;
+
+ /* Set variables according to the value of opt_quantum_2pow. */
+ quantum = (1 << opt_quantum_2pow);
+ quantum_mask = quantum - 1;
+ if (ntbins > 0)
+ small_min = (quantum >> 1) + 1;
+ else
+ small_min = 1;
+ assert(small_min <= quantum);
+
+ /* Set variables according to the value of opt_chunk_2pow. */
+ chunksize = (1LU << opt_chunk_2pow);
+ chunksize_mask = chunksize - 1;
+ chunk_npages = (chunksize >> pagesize_2pow);
+ {
+ unsigned header_size;
+
+ header_size = sizeof(arena_chunk_t) + (sizeof(arena_chunk_map_t)
+ * (chunk_npages - 1));
+ arena_chunk_header_npages = (header_size >> pagesize_2pow);
+ if ((header_size & pagesize_mask) != 0)
+ arena_chunk_header_npages++;
+ }
+ arena_maxclass = chunksize - (arena_chunk_header_npages <<
+ pagesize_2pow);
+
+ UTRACE(0, 0, 0);
+
+#ifdef MALLOC_STATS
+ memset(&stats_chunks, 0, sizeof(chunk_stats_t));
+#endif
+
+ /* Various sanity checks that regard configuration. */
+ assert(quantum >= sizeof(void *));
+ assert(quantum <= pagesize);
+ assert(chunksize >= pagesize);
+ assert(quantum * 4 <= chunksize);
+
+ /* Initialize chunks data. */
+ malloc_mutex_init(&chunks_mtx);
+ RB_INIT(&huge);
+#ifdef USE_BRK
+ malloc_mutex_init(&brk_mtx);
+ brk_base = sbrk(0);
+ brk_prev = brk_base;
+ brk_max = brk_base;
+#endif
+#ifdef MALLOC_STATS
+ huge_nmalloc = 0;
+ huge_ndalloc = 0;
+ huge_allocated = 0;
+#endif
+ RB_INIT(&old_chunks);
+
+ /* Initialize base allocation data structures. */
+#ifdef MALLOC_STATS
+ base_mapped = 0;
+#endif
+#ifdef USE_BRK
+ /*
+ * Allocate a base chunk here, since it doesn't actually have to be
+ * chunk-aligned. Doing this before allocating any other chunks allows
+ * the use of space that would otherwise be wasted.
+ */
+ base_pages_alloc(0);
+#endif
+ base_chunk_nodes = NULL;
+ malloc_mutex_init(&base_mtx);
+
+ if (ncpus > 1) {
+ /*
+ * For SMP systems, create four times as many arenas as there
+ * are CPUs by default.
+ */
+ opt_narenas_lshift += 2;
+ }
+
+ /* Determine how many arenas to use. */
+ narenas = ncpus;
+ if (opt_narenas_lshift > 0) {
+ if ((narenas << opt_narenas_lshift) > narenas)
+ narenas <<= opt_narenas_lshift;
+ /*
+ * Make sure not to exceed the limits of what base_malloc()
+ * can handle.
+ */
+ if (narenas * sizeof(arena_t *) > chunksize)
+ narenas = chunksize / sizeof(arena_t *);
+ } else if (opt_narenas_lshift < 0) {
+ if ((narenas << opt_narenas_lshift) < narenas)
+ narenas <<= opt_narenas_lshift;
+ /* Make sure there is at least one arena. */
+ if (narenas == 0)
+ narenas = 1;
+ }
+
+#ifdef NO_TLS
+ if (narenas > 1) {
+ static const unsigned primes[] = {1, 3, 5, 7, 11, 13, 17, 19,
+ 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
+ 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+ 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
+ 223, 227, 229, 233, 239, 241, 251, 257, 263};
+ unsigned nprimes, parenas;
+
+ /*
+ * Pick a prime number of hash arenas that is more than narenas
+ * so that direct hashing of pthread_self() pointers tends to
+ * spread allocations evenly among the arenas.
+ */
+ assert((narenas & 1) == 0); /* narenas must be even. */
+ nprimes = (sizeof(primes) >> SIZEOF_INT_2POW);
+ parenas = primes[nprimes - 1]; /* In case not enough primes. */
+ for (i = 1; i < nprimes; i++) {
+ if (primes[i] > narenas) {
+ parenas = primes[i];
+ break;
+ }
+ }
+ narenas = parenas;
+ }
+#endif
+
+#ifndef NO_TLS
+ next_arena = 0;
+#endif
+
+ /* Allocate and initialize arenas. */
+ arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
+ if (arenas == NULL) {
+ malloc_mutex_unlock(&init_lock);
+ return (true);
+ }
+ /*
+ * Zero the array. In practice, this should always be pre-zeroed,
+ * since it was just mmap()ed, but let's be sure.
+ */
+ memset(arenas, 0, sizeof(arena_t *) * narenas);
+
+ /*
+ * Initialize one arena here. The rest are lazily created in
+ * arena_choose_hard().
+ */
+ arenas_extend(0);
+ if (arenas[0] == NULL) {
+ malloc_mutex_unlock(&init_lock);
+ return (true);
+ }
+
+ malloc_mutex_init(&arenas_mtx);
+
+ malloc_initialized = true;
+ malloc_mutex_unlock(&init_lock);
+ return (false);
+}
+
+/*
+ * End general internal functions.
+ */
+/******************************************************************************/
+/*
+ * Begin malloc(3)-compatible functions.
+ */
+
+void *
+malloc(size_t size)
+{
+ void *ret;
+
+ if (malloc_init()) {
+ ret = NULL;
+ goto RETURN;
+ }
+
+ if (size == 0) {
+ if (opt_sysv == false)
+ size = 1;
+ else {
+ ret = NULL;
+ goto RETURN;
+ }
+ }
+
+ ret = imalloc(size);
+
+RETURN:
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in malloc(): out of memory\n", "",
+ "");
+ abort();
+ }
+ errno = ENOMEM;
+ }
+
+ UTRACE(0, size, ret);
+ return (ret);
+}
+
+int
+posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+ int ret;
+ void *result;
+
+ if (malloc_init())
+ result = NULL;
+ else {
+ /* Make sure that alignment is a large enough power of 2. */
+ if (((alignment - 1) & alignment) != 0
+ || alignment < sizeof(void *)) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in posix_memalign(): "
+ "invalid alignment\n", "", "");
+ abort();
+ }
+ result = NULL;
+ ret = EINVAL;
+ goto RETURN;
+ }
+
+ result = ipalloc(alignment, size);
+ }
+
+ if (result == NULL) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in posix_memalign(): out of memory\n",
+ "", "");
+ abort();
+ }
+ ret = ENOMEM;
+ goto RETURN;
+ }
+
+ *memptr = result;
+ ret = 0;
+
+RETURN:
+ UTRACE(0, size, result);
+ return (ret);
+}
+
+void *
+calloc(size_t num, size_t size)
+{
+ void *ret;
+ size_t num_size;
+
+ if (malloc_init()) {
+ num_size = 0;
+ ret = NULL;
+ goto RETURN;
+ }
+
+ num_size = num * size;
+ if (num_size == 0) {
+ if ((opt_sysv == false) && ((num == 0) || (size == 0)))
+ num_size = 1;
+ else {
+ ret = NULL;
+ goto RETURN;
+ }
+ /*
+ * Try to avoid division here. We know that it isn't possible to
+ * overflow during multiplication if neither operand uses any of the
+ * most significant half of the bits in a size_t.
+ */
+ } else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
+ && (num_size / size != num)) {
+ /* size_t overflow. */
+ ret = NULL;
+ goto RETURN;
+ }
+
+ ret = icalloc(num_size);
+
+RETURN:
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in calloc(): out of memory\n", "",
+ "");
+ abort();
+ }
+ errno = ENOMEM;
+ }
+
+ UTRACE(0, num_size, ret);
+ return (ret);
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+ void *ret;
+
+ if (size == 0) {
+ if (opt_sysv == false)
+ size = 1;
+ else {
+ if (ptr != NULL)
+ idalloc(ptr);
+ ret = NULL;
+ goto RETURN;
+ }
+ }
+
+ if (ptr != NULL) {
+ assert(malloc_initialized);
+
+ ret = iralloc(ptr, size);
+
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in realloc(): out of "
+ "memory\n", "", "");
+ abort();
+ }
+ errno = ENOMEM;
+ }
+ } else {
+ if (malloc_init())
+ ret = NULL;
+ else
+ ret = imalloc(size);
+
+ if (ret == NULL) {
+ if (opt_xmalloc) {
+ _malloc_message(_getprogname(),
+ ": (malloc) Error in realloc(): out of "
+ "memory\n", "", "");
+ abort();
+ }
+ errno = ENOMEM;
+ }
+ }
+
+RETURN:
+ UTRACE(ptr, size, ret);
+ return (ret);
+}
+
+void
+free(void *ptr)
+{
+
+ UTRACE(ptr, 0, 0);
+ if (ptr != NULL) {
+ assert(malloc_initialized);
+
+ idalloc(ptr);
+ }
+}
+
+/*
+ * End malloc(3)-compatible functions.
+ */
+/******************************************************************************/
+/*
+ * Begin non-standard functions.
+ */
+
+size_t
+malloc_usable_size(const void *ptr)
+{
+
+ assert(ptr != NULL);
+
+ return (isalloc(ptr));
+}
+
+/*
+ * End non-standard functions.
+ */
+/******************************************************************************/
+/*
+ * Begin library-private functions, used by threading libraries for protection
+ * of malloc during fork(). These functions are only called if the program is
+ * running in threaded mode, so there is no need to check whether the program
+ * is threaded here.
+ */
+
+void
+_malloc_prefork(void)
+{
+ unsigned i;
+
+ /* Acquire all mutexes in a safe order. */
+
+ malloc_mutex_lock(&arenas_mtx);
+ for (i = 0; i < narenas; i++) {
+ if (arenas[i] != NULL)
+ malloc_mutex_lock(&arenas[i]->mtx);
+ }
+ malloc_mutex_unlock(&arenas_mtx);
+
+ malloc_mutex_lock(&base_mtx);
+
+ malloc_mutex_lock(&chunks_mtx);
+}
+
+void
+_malloc_postfork(void)
+{
+ unsigned i;
+
+ /* Release all mutexes, now that fork() has completed. */
+
+ malloc_mutex_unlock(&chunks_mtx);
+
+ malloc_mutex_unlock(&base_mtx);
+
+ malloc_mutex_lock(&arenas_mtx);
+ for (i = 0; i < narenas; i++) {
+ if (arenas[i] != NULL)
+ malloc_mutex_unlock(&arenas[i]->mtx);
+ }
+ malloc_mutex_unlock(&arenas_mtx);
+}
+
+/*
+ * End library-private functions.
+ */
+/******************************************************************************/
diff --git a/lib/libc/stdlib/memory.3 b/lib/libc/stdlib/memory.3
new file mode 100644
index 0000000..9f42fa6
--- /dev/null
+++ b/lib/libc/stdlib/memory.3
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)memory.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt MEMORY 3
+.Os
+.Sh NAME
+.Nm malloc ,
+.Nm free ,
+.Nm realloc ,
+.Nm calloc ,
+.Nm alloca ,
+.Nm mmap
+.Nd general memory allocation operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void *
+.Fn malloc "size_t size"
+.Ft void
+.Fn free "void *ptr"
+.Ft void *
+.Fn realloc "void *ptr" "size_t size"
+.Ft void *
+.Fn calloc "size_t nelem" "size_t elsize"
+.Ft void *
+.Fn alloca "size_t size"
+.In sys/types.h
+.In sys/mman.h
+.Ft void *
+.Fn mmap "void * addr" "size_t len" "int prot" "int flags" "int fd" "off_t offset"
+.Sh DESCRIPTION
+These functions allocate and free memory for the calling process.
+They are described in the
+individual manual pages.
+.Sh SEE ALSO
+.Xr mmap 2 ,
+.Xr alloca 3 ,
+.Xr calloc 3 ,
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3
+.Sh STANDARDS
+These functions, with the exception of
+.Fn alloca
+and
+.Fn mmap
+conform to
+.St -isoC .
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
new file mode 100644
index 0000000..e1078e7
--- /dev/null
+++ b/lib/libc/stdlib/merge.c
@@ -0,0 +1,351 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Hybrid exponential search/linear search merge sort with hybrid
+ * natural/pairwise first pass. Requires about .3% more comparisons
+ * for random data than LSMS with pairwise first pass alone.
+ * It works for objects as small as two bytes.
+ */
+
+#define NATURAL
+#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
+
+/* #define NATURAL to get hybrid natural merge.
+ * (The default is pairwise merging.)
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#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 *));
+
+#define ISIZE sizeof(int)
+#define PSIZE sizeof(u_char *)
+#define ICOPY_LIST(src, dst, last) \
+ do \
+ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
+ while(src < last)
+#define ICOPY_ELT(src, dst, i) \
+ do \
+ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
+ while (i -= ISIZE)
+
+#define CCOPY_LIST(src, dst, last) \
+ do \
+ *dst++ = *src++; \
+ while (src < last)
+#define CCOPY_ELT(src, dst, i) \
+ do \
+ *dst++ = *src++; \
+ while (i -= 1)
+
+/*
+ * Find the next possible pointer head. (Trickery for forcing an array
+ * to do double duty as a linked list when objects do not align with word
+ * boundaries.
+ */
+/* Assumption: PSIZE is a power of 2. */
+#define EVAL(p) (u_char **) \
+ ((u_char *)0 + \
+ (((u_char *)p + PSIZE - 1 - (u_char *) 0) & ~(PSIZE - 1)))
+
+/*
+ * Arguments are as for qsort.
+ */
+int
+mergesort(base, nmemb, size, cmp)
+ void *base;
+ size_t nmemb;
+ size_t size;
+ int (*cmp)(const void *, const void *);
+{
+ size_t i;
+ int sense;
+ int big, iflag;
+ u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
+ u_char *list2, *list1, *p2, *p, *last, **p1;
+
+ if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (nmemb == 0)
+ return (0);
+
+ /*
+ * XXX
+ * Stupid subtraction for the Cray.
+ */
+ iflag = 0;
+ if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE))
+ iflag = 1;
+
+ if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
+ return (-1);
+
+ list1 = base;
+ setup(list1, list2, nmemb, size, cmp);
+ last = list2 + nmemb * size;
+ i = big = 0;
+ while (*EVAL(list2) != last) {
+ l2 = list1;
+ p1 = EVAL(list1);
+ for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
+ p2 = *EVAL(p2);
+ f1 = l2;
+ f2 = l1 = list1 + (p2 - list2);
+ if (p2 != last)
+ p2 = *EVAL(p2);
+ l2 = list1 + (p2 - list2);
+ while (f1 < l1 && f2 < l2) {
+ if ((*cmp)(f1, f2) <= 0) {
+ q = f2;
+ b = f1, t = l1;
+ sense = -1;
+ } else {
+ q = f1;
+ b = f2, t = l2;
+ sense = 0;
+ }
+ if (!big) { /* here i = 0 */
+ while ((b += size) < t && cmp(q, b) >sense)
+ if (++i == 6) {
+ big = 1;
+ goto EXPONENTIAL;
+ }
+ } else {
+EXPONENTIAL: for (i = size; ; i <<= 1)
+ if ((p = (b + i)) >= t) {
+ if ((p = t - size) > b &&
+ (*cmp)(q, p) <= sense)
+ t = p;
+ else
+ b = p;
+ break;
+ } else if ((*cmp)(q, p) <= sense) {
+ t = p;
+ if (i == size)
+ big = 0;
+ goto FASTCASE;
+ } else
+ b = p;
+ while (t > b+size) {
+ i = (((t - b) / size) >> 1) * size;
+ if ((*cmp)(q, p = b + i) <= sense)
+ t = p;
+ else
+ b = p;
+ }
+ goto COPY;
+FASTCASE: while (i > size)
+ if ((*cmp)(q,
+ p = b + (i >>= 1)) <= sense)
+ t = p;
+ else
+ b = p;
+COPY: b = t;
+ }
+ i = size;
+ if (q == f1) {
+ if (iflag) {
+ ICOPY_LIST(f2, tp2, b);
+ ICOPY_ELT(f1, tp2, i);
+ } else {
+ CCOPY_LIST(f2, tp2, b);
+ CCOPY_ELT(f1, tp2, i);
+ }
+ } else {
+ if (iflag) {
+ ICOPY_LIST(f1, tp2, b);
+ ICOPY_ELT(f2, tp2, i);
+ } else {
+ CCOPY_LIST(f1, tp2, b);
+ CCOPY_ELT(f2, tp2, i);
+ }
+ }
+ }
+ if (f2 < l2) {
+ if (iflag)
+ ICOPY_LIST(f2, tp2, l2);
+ else
+ CCOPY_LIST(f2, tp2, l2);
+ } else if (f1 < l1) {
+ if (iflag)
+ ICOPY_LIST(f1, tp2, l1);
+ else
+ CCOPY_LIST(f1, tp2, l1);
+ }
+ *p1 = l2;
+ }
+ tp2 = list1; /* swap list1, list2 */
+ list1 = list2;
+ list2 = tp2;
+ last = list2 + nmemb*size;
+ }
+ if (base == list2) {
+ memmove(list2, list1, nmemb*size);
+ list2 = list1;
+ }
+ free(list2);
+ return (0);
+}
+
+#define swap(a, b) { \
+ s = b; \
+ i = size; \
+ do { \
+ tmp = *a; *a++ = *s; *s++ = tmp; \
+ } while (--i); \
+ a -= size; \
+ }
+#define reverse(bot, top) { \
+ s = top; \
+ do { \
+ i = size; \
+ do { \
+ tmp = *bot; *bot++ = *s; *s++ = tmp; \
+ } while (--i); \
+ s -= size2; \
+ } while(bot < s); \
+}
+
+/*
+ * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
+ * increasing order, list2 in a corresponding linked list. Checks for runs
+ * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
+ * is defined. Otherwise simple pairwise merging is used.)
+ */
+void
+setup(list1, list2, n, size, cmp)
+ size_t n, size;
+ int (*cmp)(const void *, const void *);
+ u_char *list1, *list2;
+{
+ int i, length, size2, tmp, sense;
+ u_char *f1, *f2, *s, *l2, *last, *p2;
+
+ size2 = size*2;
+ if (n <= 5) {
+ insertionsort(list1, n, size, cmp);
+ *EVAL(list2) = (u_char*) list2 + n*size;
+ return;
+ }
+ /*
+ * Avoid running pointers out of bounds; limit n to evens
+ * for simplicity.
+ */
+ i = 4 + (n & 1);
+ insertionsort(list1 + (n - i) * size, i, size, cmp);
+ last = list1 + size * (n - i);
+ *EVAL(list2 + (last - list1)) = list2 + n * size;
+
+#ifdef NATURAL
+ p2 = list2;
+ f1 = list1;
+ 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)
+ break;
+ length += 2;
+ }
+ if (length < THRESHOLD) { /* Pairwise merge */
+ do {
+ p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
+ if (sense > 0)
+ swap (f1, f1 + size);
+ } while ((f1 += size2) < f2);
+ } else { /* Natural merge */
+ l2 = f2;
+ for (f2 = f1 + size2; f2 < l2; f2 += size2) {
+ if ((cmp(f2-size, f2) > 0) != sense) {
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ if (sense > 0)
+ reverse(f1, f2-size);
+ f1 = f2;
+ }
+ }
+ if (sense > 0)
+ reverse (f1, f2-size);
+ f1 = f2;
+ if (f2 < last || cmp(f2 - size, f2) > 0)
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ else
+ p2 = *EVAL(p2) = list2 + n*size;
+ }
+ }
+#else /* pairwise merge only. */
+ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
+ p2 = *EVAL(p2) = p2 + size2;
+ if (cmp (f1, f1 + size) > 0)
+ swap(f1, f1 + size);
+ }
+#endif /* NATURAL */
+}
+
+/*
+ * This is to avoid out-of-bounds addresses in sorting the
+ * last 4 elements.
+ */
+static void
+insertionsort(a, n, size, cmp)
+ u_char *a;
+ size_t n, size;
+ int (*cmp)(const void *, const void *);
+{
+ u_char *ai, *s, *t, *u, tmp;
+ int i;
+
+ for (ai = a+size; --n >= 1; ai += size)
+ for (t = ai; t > a; t -= size) {
+ u = t - size;
+ if (cmp(u, t) <= 0)
+ break;
+ swap(u, t);
+ }
+}
diff --git a/lib/libc/stdlib/posix_memalign.3 b/lib/libc/stdlib/posix_memalign.3
new file mode 100644
index 0000000..b092ced
--- /dev/null
+++ b/lib/libc/stdlib/posix_memalign.3
@@ -0,0 +1,96 @@
+.\" Copyright (C) 2006 Jason Evans <jasone@FreeBSD.org>.
+.\" 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(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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$
+.\"
+.Dd January 11, 2006
+.Dt POSIX_MEMALIGN 3
+.Os
+.Sh NAME
+.Nm posix_memalign
+.Nd aligned memory allocation
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn posix_memalign "void **ptr" "size_t alignment" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn posix_memalign
+function allocates
+.Fa size
+bytes of memory such that the allocation's base address is an even multiple of
+.Fa alignment ,
+and returns the allocation in the value pointed to by
+.Fa ptr .
+.Pp
+The requested
+.Fa alignment
+must be a power of 2 at least as large as
+.Fn sizeof "void *" .
+.Pp
+Memory that is allocated via
+.Fn posix_memalign
+can be used as an argument in subsequent calls to
+.Xr realloc 3 ,
+.Xr reallocf 3 ,
+and
+.Xr free 3 .
+.Sh RETURN VALUES
+The
+.Fn posix_memalign
+function returns the value 0 if successful; otherwise it returns an error value.
+.Sh ERRORS
+The
+.Fn posix_memalign
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa alignment
+parameter is not a power of 2 at least as large as
+.Fn sizeof "void *" .
+.It Bq Er ENOMEM
+Memory allocation error.
+.El
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr realloc 3 ,
+.Xr reallocf 3 ,
+.Xr valloc 3
+.Sh STANDARDS
+The
+.Fn posix_memalign
+function conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Fn posix_memalign
+function first appeared in
+.Fx 7.0 .
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
new file mode 100644
index 0000000..a5eea5d
--- /dev/null
+++ b/lib/libc/stdlib/putenv.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)putenv.c 8.2 (Berkeley) 3/27/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+int
+putenv(str)
+ const char *str;
+{
+ char *p, *equal;
+ int rval;
+
+ if ((p = strdup(str)) == NULL)
+ return (-1);
+ if ((equal = index(p, '=')) == NULL) {
+ (void)free(p);
+ return (-1);
+ }
+ *equal = '\0';
+ rval = setenv(p, equal + 1, 1);
+ (void)free(p);
+ return (rval);
+}
diff --git a/lib/libc/stdlib/qsort.3 b/lib/libc/stdlib/qsort.3
new file mode 100644
index 0000000..0f7ef73
--- /dev/null
+++ b/lib/libc/stdlib/qsort.3
@@ -0,0 +1,286 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)qsort.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd September 30, 2003
+.Dt QSORT 3
+.Os
+.Sh NAME
+.Nm qsort , qsort_r , heapsort , mergesort
+.Nd sort functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fo qsort
+.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"
+.Fa "size_t size"
+.Fa "void *thunk"
+.Fa "int \*[lp]*compar\*[rp]\*[lp]void *, const void *, const void *\*[rp]"
+.Fc
+.Ft int
+.Fo heapsort
+.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
+.Sh DESCRIPTION
+The
+.Fn qsort
+function is a modified partition-exchange sort, or quicksort.
+The
+.Fn heapsort
+function is a modified selection sort.
+The
+.Fn mergesort
+function is a modified merge sort with exponential search
+intended for sorting data with pre-existing order.
+.Pp
+The
+.Fn qsort
+and
+.Fn heapsort
+functions sort an array of
+.Fa nmemb
+objects, the initial member of which is pointed to by
+.Fa base .
+The size of each object is specified by
+.Fa size .
+The
+.Fn mergesort
+function
+behaves similarly, but
+.Em requires
+that
+.Fa size
+be greater than
+.Dq "sizeof(void *) / 2" .
+.Pp
+The contents of the array
+.Fa base
+are sorted in ascending order according to
+a comparison function pointed to by
+.Fa compar ,
+which requires two arguments pointing to the objects being
+compared.
+.Pp
+The comparison function must return an integer less than, equal to, or
+greater than zero if the first argument is considered to be respectively
+less than, equal to, or greater than the second.
+.Pp
+The
+.Fn qsort_r
+function behaves identically to
+.Fn qsort ,
+except that it takes an additional argument,
+.Fa thunk ,
+which is passed unchanged as the first argument to function pointed to
+.Fa compar .
+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.
+.Pp
+The algorithms implemented by
+.Fn qsort ,
+.Fn qsort_r ,
+and
+.Fn heapsort
+are
+.Em not
+stable, that is, if two members compare as equal, their order in
+the sorted array is undefined.
+The
+.Fn mergesort
+algorithm is stable.
+.Pp
+The
+.Fn qsort
+and
+.Fn qsort_r
+functions are an implementation of C.A.R.
+Hoare's
+.Dq quicksort
+algorithm,
+a variant of partition-exchange sorting; in particular, see
+.An D.E. Knuth Ns 's
+.%T "Algorithm Q" .
+.Sy Quicksort
+takes O N lg N average time.
+This implementation uses median selection to avoid its
+O N**2 worst-case behavior.
+.Pp
+The
+.Fn heapsort
+function is an implementation of
+.An "J.W.J. William" Ns 's
+.Dq heapsort
+algorithm,
+a variant of selection sorting; in particular, see
+.An "D.E. Knuth" Ns 's
+.%T "Algorithm H" .
+.Sy Heapsort
+takes O N lg N worst-case time.
+Its
+.Em only
+advantage over
+.Fn qsort
+is that it uses almost no additional memory; while
+.Fn qsort
+does not allocate memory, it is implemented using recursion.
+.Pp
+The function
+.Fn mergesort
+requires additional memory of size
+.Fa nmemb *
+.Fa size
+bytes; it should be used only when space is not at a premium.
+The
+.Fn mergesort
+function
+is optimized for data with pre-existing order; its worst case
+time is O N lg N; its best case is O N.
+.Pp
+Normally,
+.Fn qsort
+is faster than
+.Fn mergesort
+is faster than
+.Fn heapsort .
+Memory availability and pre-existing order in the data can make this
+untrue.
+.Sh RETURN VALUES
+The
+.Fn qsort
+and
+.Fn qsort_r
+functions
+return no value.
+.Pp
+.Rv -std heapsort mergesort
+.Sh COMPATIBILITY
+Previous versions of
+.Fn qsort
+did not permit the comparison routine itself to call
+.Fn qsort 3 .
+This is no longer true.
+.Sh ERRORS
+The
+.Fn heapsort
+and
+.Fn mergesort
+functions succeed unless:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa size
+argument is zero, or,
+the
+.Fa size
+argument to
+.Fn mergesort
+is less than
+.Dq "sizeof(void *) / 2" .
+.It Bq Er ENOMEM
+The
+.Fn heapsort
+or
+.Fn mergesort
+functions
+were unable to allocate memory.
+.El
+.Sh SEE ALSO
+.Xr sort 1 ,
+.Xr radixsort 3
+.Rs
+.%A Hoare, C.A.R.
+.%D 1962
+.%T "Quicksort"
+.%J "The Computer Journal"
+.%V 5:1
+.%P pp. 10-15
+.Re
+.Rs
+.%A Williams, J.W.J
+.%D 1964
+.%T "Heapsort"
+.%J "Communications of the ACM"
+.%V 7:1
+.%P pp. 347-348
+.Re
+.Rs
+.%A Knuth, D.E.
+.%D 1968
+.%B "The Art of Computer Programming"
+.%V Vol. 3
+.%T "Sorting and Searching"
+.%P pp. 114-123, 145-149
+.Re
+.Rs
+.%A McIlroy, P.M.
+.%T "Optimistic Sorting and Information Theoretic Complexity"
+.%J "Fourth Annual ACM-SIAM Symposium on Discrete Algorithms"
+.%V January 1992
+.Re
+.Rs
+.%A Bentley, J.L.
+.%A McIlroy, M.D.
+.%T "Engineering a Sort Function"
+.%J "Software--Practice and Experience"
+.%V Vol. 23(11)
+.%P pp. 1249-1265
+.%D November\ 1993
+.Re
+.Sh STANDARDS
+The
+.Fn qsort
+function
+conforms to
+.St -isoC .
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
new file mode 100644
index 0000000..65e038c
--- /dev/null
+++ b/lib/libc/stdlib/qsort.c
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+#ifdef I_AM_QSORT_R
+typedef int cmp_t(void *, const void *, const void *);
+#else
+typedef int cmp_t(const void *, const void *);
+#endif
+static inline char *med3(char *, char *, char *, cmp_t *, void *);
+static inline void swapfunc(char *, char *, int, int);
+
+#define min(a, b) (a) < (b) ? a : b
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ TYPE *pi = (TYPE *) (parmi); \
+ TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static inline void
+swapfunc(a, b, n, swaptype)
+ char *a, *b;
+ int n, swaptype;
+{
+ if(swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+#ifdef I_AM_QSORT_R
+#define CMP(t, x, y) (cmp((t), (x), (y)))
+#else
+#define CMP(t, x, y) (cmp((x), (y)))
+#endif
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
+#ifndef I_AM_QSORT_R
+__unused
+#endif
+)
+{
+ 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 ? a : c ));
+}
+
+#ifdef I_AM_QSORT_R
+void
+qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+#else
+#define thunk NULL
+void
+qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+#endif
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+ pm = med3(pm - d, pm, pm + d, cmp, thunk);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+ }
+ pm = med3(pl, pm, pn, cmp, thunk);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+ for (pl = pm;
+ pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min(pd - pc, pn - pd - es);
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+#ifdef I_AM_QSORT_R
+ qsort_r(a, r / es, es, thunk, cmp);
+#else
+ qsort(a, r / es, es, cmp);
+#endif
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/lib/libc/stdlib/qsort_r.c b/lib/libc/stdlib/qsort_r.c
new file mode 100644
index 0000000..d868736
--- /dev/null
+++ b/lib/libc/stdlib/qsort_r.c
@@ -0,0 +1,8 @@
+/*
+ * This file is in the public domain. Originally written by Garrett
+ * A. Wollman.
+ *
+ * $FreeBSD$
+ */
+#define I_AM_QSORT_R
+#include "qsort.c"
diff --git a/lib/libc/stdlib/radixsort.3 b/lib/libc/stdlib/radixsort.3
new file mode 100644
index 0000000..dfa65f1
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.3
@@ -0,0 +1,160 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)radixsort.3 8.2 (Berkeley) 1/27/94
+.\" $FreeBSD$
+.\"
+.Dd January 27, 1994
+.Dt RADIXSORT 3
+.Os
+.Sh NAME
+.Nm radixsort , sradixsort
+.Nd radix sort
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In limits.h
+.In stdlib.h
+.Ft int
+.Fn radixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte"
+.Ft int
+.Fn sradixsort "const unsigned char **base" "int nmemb" "const unsigned char *table" "unsigned endbyte"
+.Sh DESCRIPTION
+The
+.Fn radixsort
+and
+.Fn sradixsort
+functions
+are implementations of radix sort.
+.Pp
+These functions sort an array of pointers to byte strings, the initial
+member of which is referenced by
+.Fa base .
+The byte strings may contain any values; the end of each string
+is denoted by the user-specified value
+.Fa endbyte .
+.Pp
+Applications may specify a sort order by providing the
+.Fa table
+argument.
+If
+.Pf non- Dv NULL ,
+.Fa table
+must reference an array of
+.Dv UCHAR_MAX
++ 1 bytes which contains the sort
+weight of each possible byte value.
+The end-of-string byte must have a sort weight of 0 or 255
+(for sorting in reverse order).
+More than one byte may have the same sort weight.
+The
+.Fa table
+argument
+is useful for applications which wish to sort different characters
+equally, for example, providing a table with the same weights
+for A-Z as for a-z will result in a case-insensitive sort.
+If
+.Fa table
+is NULL, the contents of the array are sorted in ascending order
+according to the
+.Tn ASCII
+order of the byte strings they reference and
+.Fa endbyte
+has a sorting weight of 0.
+.Pp
+The
+.Fn sradixsort
+function is stable, that is, if two elements compare as equal, their
+order in the sorted array is unchanged.
+The
+.Fn sradixsort
+function uses additional memory sufficient to hold
+.Fa nmemb
+pointers.
+.Pp
+The
+.Fn radixsort
+function is not stable, but uses no additional memory.
+.Pp
+These functions are variants of most-significant-byte radix sorting; in
+particular, see
+.An "D.E. Knuth" Ns 's
+.%T "Algorithm R"
+and section 5.2.5, exercise 10.
+They take linear time relative to the number of bytes in the strings.
+.Sh RETURN VALUES
+.Rv -std radixsort
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa endbyte
+element of
+.Fa table
+is not 0 or 255.
+.El
+.Pp
+Additionally, the
+.Fn sradixsort
+function
+may fail and set
+.Va errno
+for any of the errors specified for the library routine
+.Xr malloc 3 .
+.Sh SEE ALSO
+.Xr sort 1 ,
+.Xr qsort 3
+.Pp
+.Rs
+.%A Knuth, D.E.
+.%D 1968
+.%B "The Art of Computer Programming"
+.%T "Sorting and Searching"
+.%V Vol. 3
+.%P pp. 170-178
+.Re
+.Rs
+.%A Paige, R.
+.%D 1987
+.%T "Three Partition Refinement Algorithms"
+.%J "SIAM J. Comput."
+.%V Vol. 16
+.%N No. 6
+.Re
+.Rs
+.%A McIlroy, P.
+.%D 1993
+.%B "Engineering Radix Sort"
+.%T "Computing Systems"
+.%V Vol. 6:1
+.%P pp. 5-27
+.Re
+.Sh HISTORY
+The
+.Fn radixsort
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c
new file mode 100644
index 0000000..82ff1bc
--- /dev/null
+++ b/lib/libc/stdlib/radixsort.c
@@ -0,0 +1,327 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy and by Dan Bernstein at New York University,
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)radixsort.c 8.2 (Berkeley) 4/28/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Radixsort routines.
+ *
+ * Program r_sort_a() is unstable but uses O(logN) extra memory for a stack.
+ * Use radixsort(a, n, trace, endchar) for this case.
+ *
+ * For stable sorting (using N extra pointers) use sradixsort(), which calls
+ * r_sort_b().
+ *
+ * For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic,
+ * "Engineering Radix Sort".
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+typedef struct {
+ const u_char **sa;
+ int sn, si;
+} stack;
+
+static inline void simplesort
+(const u_char **, int, int, const u_char *, u_int);
+static void r_sort_a(const u_char **, int, int, const u_char *, u_int);
+static void r_sort_b(const u_char **, const u_char **, int, int,
+ const u_char *, u_int);
+
+#define THRESHOLD 20 /* Divert to simplesort(). */
+#define SIZE 512 /* Default stack size. */
+
+#define SETUP { \
+ if (tab == NULL) { \
+ tr = tr0; \
+ for (c = 0; c < endch; c++) \
+ tr0[c] = c + 1; \
+ tr0[c] = 0; \
+ for (c++; c < 256; c++) \
+ tr0[c] = c; \
+ endch = 0; \
+ } else { \
+ endch = tab[endch]; \
+ tr = tab; \
+ if (endch != 0 && endch != 255) { \
+ errno = EINVAL; \
+ return (-1); \
+ } \
+ } \
+}
+
+int
+radixsort(a, n, tab, endch)
+ const u_char **a, *tab;
+ int n;
+ u_int endch;
+{
+ const u_char *tr;
+ int c;
+ u_char tr0[256];
+
+ SETUP;
+ r_sort_a(a, n, 0, tr, endch);
+ return (0);
+}
+
+int
+sradixsort(a, n, tab, endch)
+ const u_char **a, *tab;
+ int n;
+ u_int endch;
+{
+ const u_char *tr, **ta;
+ int c;
+ u_char tr0[256];
+
+ SETUP;
+ if (n < THRESHOLD)
+ simplesort(a, n, 0, tr, endch);
+ else {
+ if ((ta = malloc(n * sizeof(a))) == NULL)
+ return (-1);
+ r_sort_b(a, ta, n, 0, tr, endch);
+ free(ta);
+ }
+ return (0);
+}
+
+#define empty(s) (s >= sp)
+#define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si
+#define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i
+#define swap(a, b, t) t = a, a = b, b = t
+
+/* Unstable, in-place sort. */
+static void
+r_sort_a(a, n, i, tr, endch)
+ const u_char **a;
+ int n, i;
+ const u_char *tr;
+ u_int endch;
+{
+ static int count[256], nc, bmin;
+ int c;
+ const u_char **ak, *r;
+ stack s[SIZE], *sp, *sp0, *sp1, temp;
+ int *cp, bigc;
+ const u_char **an, *t, **aj, **top[256];
+
+ /* Set up stack. */
+ sp = s;
+ push(a, n, i);
+ while (!empty(s)) {
+ pop(a, n, i);
+ if (n < THRESHOLD) {
+ simplesort(a, n, i, tr, endch);
+ continue;
+ }
+ an = a + n;
+
+ /* Make character histogram. */
+ if (nc == 0) {
+ bmin = 255; /* First occupied bin, excluding eos. */
+ for (ak = a; ak < an;) {
+ c = tr[(*ak++)[i]];
+ if (++count[c] == 1 && c != endch) {
+ if (c < bmin)
+ bmin = c;
+ nc++;
+ }
+ }
+ if (sp + nc > s + SIZE) { /* Get more stack. */
+ r_sort_a(a, n, i, tr, endch);
+ continue;
+ }
+ }
+
+ /*
+ * Special case: if all strings have the same
+ * character at position i, move on to the next
+ * character.
+ */
+ if (nc == 1 && count[bmin] == n) {
+ push(a, n, i+1);
+ nc = count[bmin] = 0;
+ continue;
+ }
+
+ /*
+ * Set top[]; push incompletely sorted bins onto stack.
+ * top[] = pointers to last out-of-place element in bins.
+ * count[] = counts of elements in bins.
+ * Before permuting: top[c-1] + count[c] = top[c];
+ * during deal: top[c] counts down to top[c-1].
+ */
+ sp0 = sp1 = sp; /* Stack position of biggest bin. */
+ bigc = 2; /* Size of biggest bin. */
+ if (endch == 0) /* Special case: set top[eos]. */
+ top[0] = ak = a + count[0];
+ else {
+ ak = a;
+ top[255] = an;
+ }
+ for (cp = count + bmin; nc > 0; cp++) {
+ while (*cp == 0) /* Find next non-empty pile. */
+ cp++;
+ if (*cp > 1) {
+ if (*cp > bigc) {
+ bigc = *cp;
+ sp1 = sp;
+ }
+ push(ak, *cp, i+1);
+ }
+ top[cp-count] = ak += *cp;
+ nc--;
+ }
+ swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */
+
+ /*
+ * Permute misplacements home. Already home: everything
+ * before aj, and in bin[c], items from top[c] on.
+ * Inner loop:
+ * r = next element to put in place;
+ * ak = top[r[i]] = location to put the next element.
+ * aj = bottom of 1st disordered bin.
+ * Outer loop:
+ * Once the 1st disordered bin is done, ie. aj >= ak,
+ * aj<-aj + count[c] connects the bins in a linked list;
+ * reset count[c].
+ */
+ for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0)
+ for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);)
+ swap(*ak, r, t);
+ }
+}
+
+/* Stable sort, requiring additional memory. */
+static void
+r_sort_b(a, ta, n, i, tr, endch)
+ const u_char **a, **ta;
+ int n, i;
+ const u_char *tr;
+ u_int endch;
+{
+ static int count[256], nc, bmin;
+ int c;
+ const u_char **ak, **ai;
+ stack s[512], *sp, *sp0, *sp1, temp;
+ const u_char **top[256];
+ int *cp, bigc;
+
+ sp = s;
+ push(a, n, i);
+ while (!empty(s)) {
+ pop(a, n, i);
+ if (n < THRESHOLD) {
+ simplesort(a, n, i, tr, endch);
+ continue;
+ }
+
+ if (nc == 0) {
+ bmin = 255;
+ for (ak = a + n; --ak >= a;) {
+ c = tr[(*ak)[i]];
+ if (++count[c] == 1 && c != endch) {
+ if (c < bmin)
+ bmin = c;
+ nc++;
+ }
+ }
+ if (sp + nc > s + SIZE) {
+ r_sort_b(a, ta, n, i, tr, endch);
+ continue;
+ }
+ }
+
+ sp0 = sp1 = sp;
+ bigc = 2;
+ if (endch == 0) {
+ top[0] = ak = a + count[0];
+ count[0] = 0;
+ } else {
+ ak = a;
+ top[255] = a + n;
+ count[255] = 0;
+ }
+ for (cp = count + bmin; nc > 0; cp++) {
+ while (*cp == 0)
+ cp++;
+ if ((c = *cp) > 1) {
+ if (c > bigc) {
+ bigc = c;
+ sp1 = sp;
+ }
+ push(ak, c, i+1);
+ }
+ top[cp-count] = ak += c;
+ *cp = 0; /* Reset count[]. */
+ nc--;
+ }
+ swap(*sp0, *sp1, temp);
+
+ for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */
+ *--ak = *--ai;
+ for (ak = ta+n; --ak >= ta;) /* Deal to piles. */
+ *--top[tr[(*ak)[i]]] = *ak;
+ }
+}
+
+static inline void
+simplesort(a, n, b, tr, endch) /* insertion sort */
+ const u_char **a;
+ int n, b;
+ const u_char *tr;
+ u_int endch;
+{
+ u_char ch;
+ const u_char **ak, **ai, *s, *t;
+
+ for (ak = a+1; --n >= 1; ak++)
+ for (ai = ak; ai > a; ai--) {
+ for (s = ai[0] + b, t = ai[-1] + b;
+ (ch = tr[*s]) != endch; s++, t++)
+ if (ch != tr[*t])
+ break;
+ if (ch >= tr[*t])
+ break;
+ swap(ai[0], ai[-1], s);
+ }
+}
diff --git a/lib/libc/stdlib/rand.3 b/lib/libc/stdlib/rand.3
new file mode 100644
index 0000000..9b24795
--- /dev/null
+++ b/lib/libc/stdlib/rand.3
@@ -0,0 +1,117 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)rand.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd May 25, 1999
+.Dt RAND 3
+.Os
+.Sh NAME
+.Nm rand ,
+.Nm srand ,
+.Nm sranddev ,
+.Nm rand_r
+.Nd bad random number generator
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft void
+.Fn srand "unsigned seed"
+.Ft void
+.Fn sranddev void
+.Ft int
+.Fn rand void
+.Ft int
+.Fn rand_r "unsigned *ctx"
+.Sh DESCRIPTION
+.Bf -symbolic
+These interfaces are obsoleted by
+.Xr random 3 .
+.Ef
+.Pp
+The
+.Fn rand
+function computes a sequence of pseudo-random integers in the range
+of 0 to
+.Dv RAND_MAX
+(as defined by the header file
+.In stdlib.h ) .
+.Pp
+The
+.Fn srand
+function sets its argument
+.Fa seed
+as the seed for a new sequence of
+pseudo-random numbers to be returned by
+.Fn rand .
+These sequences are repeatable by calling
+.Fn srand
+with the same seed value.
+.Pp
+If no
+.Fa seed
+value is provided, the functions are automatically
+seeded with a value of 1.
+.Pp
+The
+.Fn sranddev
+function initializes a seed using the
+.Xr random 4
+random number device which returns good random numbers.
+However, the
+.Fn rand
+function still remains unsuitable for cryptographic use.
+.Pp
+The
+.Fn rand_r
+function
+provides the same functionality as
+.Fn rand .
+A pointer to the context value
+.Fa ctx
+must be supplied by the caller.
+.Sh SEE ALSO
+.Xr random 3 ,
+.Xr random 4
+.Sh STANDARDS
+The
+.Fn rand
+and
+.Fn srand
+functions
+conform to
+.St -isoC .
+.Pp
+The
+.Fn rand_r
+function is as proposed in the POSIX.4a Draft #6 document.
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
new file mode 100644
index 0000000..d651a70
--- /dev/null
+++ b/lib/libc/stdlib/rand.c
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rand.c 8.1 (Berkeley) 6/14/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/time.h> /* for sranddev() */
+#include <sys/types.h>
+#include <fcntl.h> /* for sranddev() */
+#include <stdlib.h>
+#include <unistd.h> /* for sranddev() */
+#include "un-namespace.h"
+
+#ifdef TEST
+#include <stdio.h>
+#endif /* TEST */
+
+static int
+do_rand(unsigned long *ctx)
+{
+#ifdef USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
+ return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
+#else /* !USE_WEAK_SEEDING */
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ long hi, lo, x;
+
+ /* Can't be initialized with 0, so use another value. */
+ if (*ctx == 0)
+ *ctx = 123459876;
+ hi = *ctx / 127773;
+ lo = *ctx % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ return ((*ctx = x) % ((u_long)RAND_MAX + 1));
+#endif /* !USE_WEAK_SEEDING */
+}
+
+
+int
+rand_r(unsigned int *ctx)
+{
+ u_long val = (u_long) *ctx;
+ int r = do_rand(&val);
+
+ *ctx = (unsigned int) val;
+ return (r);
+}
+
+
+static u_long next = 1;
+
+int
+rand()
+{
+ return (do_rand(&next));
+}
+
+void
+srand(seed)
+u_int seed;
+{
+ next = seed;
+}
+
+
+/*
+ * sranddev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems. We seed the generator using the much more
+ * secure random(4) interface.
+ */
+void
+sranddev()
+{
+ int fd, done;
+
+ done = 0;
+ fd = _open("/dev/random", O_RDONLY, 0);
+ if (fd >= 0) {
+ if (_read(fd, (void *) &next, sizeof(next)) == sizeof(next))
+ done = 1;
+ _close(fd);
+ }
+
+ if (!done) {
+ struct timeval tv;
+ unsigned long junk;
+
+ gettimeofday(&tv, NULL);
+ srand((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+ }
+}
+
+
+#ifdef TEST
+
+main()
+{
+ int i;
+ unsigned myseed;
+
+ printf("seeding rand with 0x19610910: \n");
+ srand(0x19610910);
+
+ printf("generating three pseudo-random numbers:\n");
+ for (i = 0; i < 3; i++)
+ {
+ printf("next random number = %d\n", rand());
+ }
+
+ printf("generating the same sequence with rand_r:\n");
+ myseed = 0x19610910;
+ for (i = 0; i < 3; i++)
+ {
+ printf("next random number = %d\n", rand_r(&myseed));
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
+
diff --git a/lib/libc/stdlib/random.3 b/lib/libc/stdlib/random.3
new file mode 100644
index 0000000..aacf6e3
--- /dev/null
+++ b/lib/libc/stdlib/random.3
@@ -0,0 +1,195 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)random.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt RANDOM 3
+.Os
+.Sh NAME
+.Nm random ,
+.Nm srandom ,
+.Nm srandomdev ,
+.Nm initstate ,
+.Nm setstate
+.Nd better random number generator; routines for changing generators
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long
+.Fn random void
+.Ft void
+.Fn srandom "unsigned long seed"
+.Ft void
+.Fn srandomdev void
+.Ft char *
+.Fn initstate "unsigned long seed" "char *state" "long n"
+.Ft char *
+.Fn setstate "char *state"
+.Sh DESCRIPTION
+The
+.Fn random
+function
+uses a non-linear additive feedback random number generator employing a
+default table of size 31 long integers to return successive pseudo-random
+numbers in the range from 0 to
+.if t 2\u\s731\s10\d\(mi1.
+.if n (2**31)\(mi1.
+The period of this random number generator is very large, approximately
+.if t 16\(mu(2\u\s731\s10\d\(mi1).
+.if n 16*((2**31)\(mi1).
+.Pp
+The
+.Fn random
+and
+.Fn srandom
+functions have (almost) the same calling sequence and initialization properties as the
+.Xr rand 3
+and
+.Xr srand 3
+functions.
+The difference is that
+.Xr rand 3
+produces a much less random sequence \(em in fact, the low dozen bits
+generated by rand go through a cyclic pattern.
+All the bits generated by
+.Fn random
+are usable.
+For example,
+.Sq Li random()&01
+will produce a random binary
+value.
+.Pp
+Like
+.Xr rand 3 ,
+.Fn random
+will by default produce a sequence of numbers that can be duplicated
+by calling
+.Fn srandom
+with
+.Ql 1
+as the seed.
+.Pp
+The
+.Fn srandomdev
+routine initializes a state array using the
+.Xr random 4
+random number device which returns good random numbers,
+suitable for cryptographic use.
+Note that this particular seeding
+procedure can generate states which are impossible to reproduce by
+calling
+.Fn srandom
+with any value, since the succeeding terms in the
+state buffer are no longer derived from the LC algorithm applied to
+a fixed seed.
+.Pp
+The
+.Fn initstate
+routine allows a state array, passed in as an argument, to be initialized
+for future use.
+The size of the state array (in bytes) is used by
+.Fn initstate
+to decide how sophisticated a random number generator it should use \(em the
+more state, the better the random numbers will be.
+(Current "optimal" values for the amount of state information are
+8, 32, 64, 128, and 256 bytes; other amounts will be rounded down to
+the nearest known amount.
+Using less than 8 bytes will cause an error.)
+The seed for the initialization (which specifies a starting point for
+the random number sequence, and provides for restarting at the same
+point) is also an argument.
+The
+.Fn initstate
+function
+returns a pointer to the previous state information array.
+.Pp
+Once a state has been initialized, the
+.Fn setstate
+routine provides for rapid switching between states.
+The
+.Fn setstate
+function
+returns a pointer to the previous state array; its
+argument state array is used for further random number generation
+until the next call to
+.Fn initstate
+or
+.Fn setstate .
+.Pp
+Once a state array has been initialized, it may be restarted at a
+different point either by calling
+.Fn initstate
+(with the desired seed, the state array, and its size) or by calling
+both
+.Fn setstate
+(with the state array) and
+.Fn srandom
+(with the desired seed).
+The advantage of calling both
+.Fn setstate
+and
+.Fn srandom
+is that the size of the state array does not have to be remembered after
+it is initialized.
+.Pp
+With 256 bytes of state information, the period of the random number
+generator is greater than
+.if t 2\u\s769\s10\d,
+.if n 2**69
+which should be sufficient for most purposes.
+.Sh DIAGNOSTICS
+If
+.Fn initstate
+is called with less than 8 bytes of state information, or if
+.Fn setstate
+detects that the state information has been garbled, error
+messages are printed on the standard error output.
+.Sh SEE ALSO
+.Xr arc4random 3 ,
+.Xr rand 3 ,
+.Xr srand 3 ,
+.Xr random 4
+.Sh HISTORY
+These
+functions appeared in
+.Bx 4.2 .
+.Sh AUTHORS
+.An Earl T. Cohen
+.Sh BUGS
+About 2/3 the speed of
+.Xr rand 3 .
+.Pp
+The historical implementation used to have a very weak seeding; the
+random sequence did not vary much with the seed.
+The current implementation employs a better pseudo-random number
+generator for the initial state calculation.
+.Pp
+Applications requiring cryptographic quality randomness should use
+.Xr arc4random 3 .
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c
new file mode 100644
index 0000000..f7be4a7
--- /dev/null
+++ b/lib/libc/stdlib/random.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/time.h> /* for srandomdev() */
+#include <fcntl.h> /* for srandomdev() */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* for srandomdev() */
+#include "un-namespace.h"
+
+/*
+ * random.c:
+ *
+ * An improved random number generation package. In addition to the standard
+ * rand()/srand() like interface, this package also has a special state info
+ * interface. The initstate() routine is called with a seed, an array of
+ * bytes, and a count of how many bytes are being passed in; this array is
+ * then initialized to contain information for random number generation with
+ * that much state information. Good sizes for the amount of state
+ * information are 32, 64, 128, and 256 bytes. The state can be switched by
+ * calling the setstate() routine with the same array as was initiallized
+ * with initstate(). By default, the package runs with 128 bytes of state
+ * information and generates far better random numbers than a linear
+ * congruential generator. If the amount of state information is less than
+ * 32 bytes, a simple linear congruential R.N.G. is used.
+ *
+ * Internally, the state information is treated as an array of uint32_t's; the
+ * zeroeth element of the array is the type of R.N.G. being used (small
+ * integer); the remainder of the array is the state information for the
+ * R.N.G. Thus, 32 bytes of state information will give 7 ints worth of
+ * state information, which will allow a degree seven polynomial. (Note:
+ * the zeroeth word of state information also has some other information
+ * stored in it -- see setstate() for details).
+ *
+ * The random number generation technique is a linear feedback shift register
+ * approach, employing trinomials (since there are fewer terms to sum up that
+ * way). In this approach, the least significant bit of all the numbers in
+ * the state table will act as a linear feedback shift register, and will
+ * have period 2^deg - 1 (where deg is the degree of the polynomial being
+ * used, assuming that the polynomial is irreducible and primitive). The
+ * higher order bits will have longer periods, since their values are also
+ * influenced by pseudo-random carries out of the lower bits. The total
+ * period of the generator is approximately deg*(2**deg - 1); thus doubling
+ * the amount of state information has a vast influence on the period of the
+ * generator. Note: the deg*(2**deg - 1) is an approximation only good for
+ * large deg, when the period of the shift is the dominant factor.
+ * With deg equal to seven, the period is actually much longer than the
+ * 7*(2**7 - 1) predicted by this formula.
+ *
+ * Modified 28 December 1994 by Jacob S. Rosenberg.
+ * The following changes have been made:
+ * All references to the type u_int have been changed to unsigned long.
+ * All references to type int have been changed to type long. Other
+ * cleanups have been made as well. A warning for both initstate and
+ * setstate has been inserted to the effect that on Sparc platforms
+ * the 'arg_state' variable must be forced to begin on word boundaries.
+ * This can be easily done by casting a long integer array to char *.
+ * The overall logic has been left STRICTLY alone. This software was
+ * tested on both a VAX and Sun SpacsStation with exactly the same
+ * results. The new version and the original give IDENTICAL results.
+ * The new version is somewhat faster than the original. As the
+ * documentation says: "By default, the package runs with 128 bytes of
+ * state information and generates far better random numbers than a linear
+ * congruential generator. If the amount of state information is less than
+ * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
+ * 128 bytes, this new version runs about 19 percent faster and for a 16
+ * byte buffer it is about 5 percent faster.
+ */
+
+/*
+ * For each of the currently supported random number generators, we have a
+ * break value on the amount of state information (you need at least this
+ * many bytes of state info to support this random number generator), a degree
+ * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
+ * the separation between the two lower order coefficients of the trinomial.
+ */
+#define TYPE_0 0 /* linear congruential */
+#define BREAK_0 8
+#define DEG_0 0
+#define SEP_0 0
+
+#define TYPE_1 1 /* x**7 + x**3 + 1 */
+#define BREAK_1 32
+#define DEG_1 7
+#define SEP_1 3
+
+#define TYPE_2 2 /* x**15 + x + 1 */
+#define BREAK_2 64
+#define DEG_2 15
+#define SEP_2 1
+
+#define TYPE_3 3 /* x**31 + x**3 + 1 */
+#define BREAK_3 128
+#define DEG_3 31
+#define SEP_3 3
+
+#define TYPE_4 4 /* x**63 + x + 1 */
+#define BREAK_4 256
+#define DEG_4 63
+#define SEP_4 1
+
+/*
+ * Array versions of the above information to make code run faster --
+ * relies on fact that TYPE_i == i.
+ */
+#define MAX_TYPES 5 /* max number of types above */
+
+#ifdef USE_WEAK_SEEDING
+#define NSHUFF 0
+#else /* !USE_WEAK_SEEDING */
+#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */
+#endif /* !USE_WEAK_SEEDING */
+
+static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
+static const int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
+
+/*
+ * Initially, everything is set up as if from:
+ *
+ * initstate(1, randtbl, 128);
+ *
+ * Note that this initialization takes advantage of the fact that srandom()
+ * advances the front and rear pointers 10*rand_deg times, and hence the
+ * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+ * element of the state information, which contains info about the current
+ * position of the rear pointer is just
+ *
+ * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
+ */
+
+static uint32_t randtbl[DEG_3 + 1] = {
+ TYPE_3,
+#ifdef USE_WEAK_SEEDING
+/* Historic implementation compatibility */
+/* The random sequences do not vary much with the seed */
+ 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
+ 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
+ 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
+ 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
+ 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
+ 0x27fb47b9,
+#else /* !USE_WEAK_SEEDING */
+ 0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05,
+ 0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454,
+ 0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471,
+ 0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1,
+ 0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41,
+ 0xf3bec5da
+#endif /* !USE_WEAK_SEEDING */
+};
+
+/*
+ * fptr and rptr are two pointers into the state info, a front and a rear
+ * pointer. These two pointers are always rand_sep places aparts, as they
+ * cycle cyclically through the state information. (Yes, this does mean we
+ * could get away with just one pointer, but the code for random() is more
+ * efficient this way). The pointers are left positioned as they would be
+ * from the call
+ *
+ * initstate(1, randtbl, 128);
+ *
+ * (The position of the rear pointer, rptr, is really 0 (as explained above
+ * in the initialization of randtbl) because the state table pointer is set
+ * to point to randtbl[1] (as explained below).
+ */
+static uint32_t *fptr = &randtbl[SEP_3 + 1];
+static uint32_t *rptr = &randtbl[1];
+
+/*
+ * The following things are the pointer to the state information table, the
+ * type of the current generator, the degree of the current polynomial being
+ * used, and the separation between the two pointers. Note that for efficiency
+ * of random(), we remember the first location of the state information, not
+ * the zeroeth. Hence it is valid to access state[-1], which is used to
+ * store the type of the R.N.G. Also, we remember the last location, since
+ * this is more efficient than indexing every time to find the address of
+ * the last element to see if the front and rear pointers have wrapped.
+ */
+static uint32_t *state = &randtbl[1];
+static int rand_type = TYPE_3;
+static int rand_deg = DEG_3;
+static int rand_sep = SEP_3;
+static uint32_t *end_ptr = &randtbl[DEG_3 + 1];
+
+static inline uint32_t good_rand(int32_t);
+
+static inline uint32_t good_rand (x)
+ int32_t x;
+{
+#ifdef USE_WEAK_SEEDING
+/*
+ * Historic implementation compatibility.
+ * The random sequences do not vary much with the seed,
+ * even with overflowing.
+ */
+ return (1103515245 * x + 12345);
+#else /* !USE_WEAK_SEEDING */
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * wihout overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ int32_t hi, lo;
+
+ /* Can't be initialized with 0, so use another value. */
+ if (x == 0)
+ x = 123459876;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ return (x);
+#endif /* !USE_WEAK_SEEDING */
+}
+
+/*
+ * srandom:
+ *
+ * Initialize the random number generator based on the given seed. If the
+ * type is the trivial no-state-information type, just remember the seed.
+ * Otherwise, initializes state[] based on the given "seed" via a linear
+ * congruential generator. Then, the pointers are set to known locations
+ * that are exactly rand_sep places apart. Lastly, it cycles the state
+ * information a given number of times to get rid of any initial dependencies
+ * introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
+ * for default usage relies on values produced by this routine.
+ */
+void
+srandom(x)
+ unsigned long x;
+{
+ int i, lim;
+
+ state[0] = (uint32_t)x;
+ if (rand_type == TYPE_0)
+ lim = NSHUFF;
+ else {
+ for (i = 1; i < rand_deg; i++)
+ state[i] = good_rand(state[i - 1]);
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ lim = 10 * rand_deg;
+ }
+ for (i = 0; i < lim; i++)
+ (void)random();
+}
+
+/*
+ * srandomdev:
+ *
+ * Many programs choose the seed value in a totally predictable manner.
+ * This often causes problems. We seed the generator using the much more
+ * secure random(4) interface. Note that this particular seeding
+ * procedure can generate states which are impossible to reproduce by
+ * calling srandom() with any value, since the succeeding terms in the
+ * state buffer are no longer derived from the LC algorithm applied to
+ * a fixed seed.
+ */
+void
+srandomdev()
+{
+ int fd, done;
+ size_t len;
+
+ if (rand_type == TYPE_0)
+ len = sizeof state[0];
+ else
+ len = rand_deg * sizeof state[0];
+
+ done = 0;
+ fd = _open("/dev/random", O_RDONLY, 0);
+ if (fd >= 0) {
+ if (_read(fd, (void *) state, len) == (ssize_t) len)
+ done = 1;
+ _close(fd);
+ }
+
+ if (!done) {
+ struct timeval tv;
+ unsigned long junk;
+
+ gettimeofday(&tv, NULL);
+ srandom((getpid() << 16) ^ tv.tv_sec ^ tv.tv_usec ^ junk);
+ return;
+ }
+
+ if (rand_type != TYPE_0) {
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ }
+}
+
+/*
+ * initstate:
+ *
+ * Initialize the state information in the given array of n bytes for future
+ * random number generation. Based on the number of bytes we are given, and
+ * the break values for the different R.N.G.'s, we choose the best (largest)
+ * one we can and set things up for it. srandom() is then called to
+ * initialize the state information.
+ *
+ * Note that on return from srandom(), we set state[-1] to be the type
+ * multiplexed with the current value of the rear pointer; this is so
+ * successive calls to initstate() won't lose this information and will be
+ * able to restart with setstate().
+ *
+ * Note: the first thing we do is save the current state, if any, just like
+ * setstate() so that it doesn't matter when initstate is called.
+ *
+ * Returns a pointer to the old state.
+ *
+ * Note: The Sparc platform requires that arg_state begin on an int
+ * word boundary; otherwise a bus error will occur. Even so, lint will
+ * complain about mis-alignment, but you should disregard these messages.
+ */
+char *
+initstate(seed, arg_state, n)
+ unsigned long seed; /* seed for R.N.G. */
+ char *arg_state; /* pointer to state array */
+ long n; /* # bytes of state info */
+{
+ char *ostate = (char *)(&state[-1]);
+ uint32_t *int_arg_state = (uint32_t *)arg_state;
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ if (n < BREAK_0) {
+ (void)fprintf(stderr,
+ "random: not enough state (%ld bytes); ignored.\n", n);
+ return(0);
+ }
+ if (n < BREAK_1) {
+ rand_type = TYPE_0;
+ rand_deg = DEG_0;
+ rand_sep = SEP_0;
+ } else if (n < BREAK_2) {
+ rand_type = TYPE_1;
+ rand_deg = DEG_1;
+ rand_sep = SEP_1;
+ } else if (n < BREAK_3) {
+ rand_type = TYPE_2;
+ rand_deg = DEG_2;
+ rand_sep = SEP_2;
+ } else if (n < BREAK_4) {
+ rand_type = TYPE_3;
+ rand_deg = DEG_3;
+ rand_sep = SEP_3;
+ } else {
+ rand_type = TYPE_4;
+ rand_deg = DEG_4;
+ rand_sep = SEP_4;
+ }
+ state = int_arg_state + 1; /* first location */
+ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
+ srandom(seed);
+ if (rand_type == TYPE_0)
+ int_arg_state[0] = rand_type;
+ else
+ int_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
+ return(ostate);
+}
+
+/*
+ * setstate:
+ *
+ * Restore the state from the given state array.
+ *
+ * Note: it is important that we also remember the locations of the pointers
+ * in the current state information, and restore the locations of the pointers
+ * from the old state information. This is done by multiplexing the pointer
+ * location into the zeroeth word of the state information.
+ *
+ * Note that due to the order in which things are done, it is OK to call
+ * setstate() with the same state as the current state.
+ *
+ * Returns a pointer to the old state information.
+ *
+ * Note: The Sparc platform requires that arg_state begin on an int
+ * word boundary; otherwise a bus error will occur. Even so, lint will
+ * complain about mis-alignment, but you should disregard these messages.
+ */
+char *
+setstate(arg_state)
+ char *arg_state; /* pointer to state array */
+{
+ uint32_t *new_state = (uint32_t *)arg_state;
+ uint32_t type = new_state[0] % MAX_TYPES;
+ uint32_t rear = new_state[0] / MAX_TYPES;
+ char *ostate = (char *)(&state[-1]);
+
+ if (rand_type == TYPE_0)
+ state[-1] = rand_type;
+ else
+ state[-1] = MAX_TYPES * (rptr - state) + rand_type;
+ switch(type) {
+ case TYPE_0:
+ case TYPE_1:
+ case TYPE_2:
+ case TYPE_3:
+ case TYPE_4:
+ rand_type = type;
+ rand_deg = degrees[type];
+ rand_sep = seps[type];
+ break;
+ default:
+ (void)fprintf(stderr,
+ "random: state info corrupted; not changed.\n");
+ }
+ state = new_state + 1;
+ if (rand_type != TYPE_0) {
+ rptr = &state[rear];
+ fptr = &state[(rear + rand_sep) % rand_deg];
+ }
+ end_ptr = &state[rand_deg]; /* set end_ptr too */
+ return(ostate);
+}
+
+/*
+ * random:
+ *
+ * If we are using the trivial TYPE_0 R.N.G., just do the old linear
+ * congruential bit. Otherwise, we do our fancy trinomial stuff, which is
+ * the same in all the other cases due to all the global variables that have
+ * been set up. The basic operation is to add the number at the rear pointer
+ * into the one at the front pointer. Then both pointers are advanced to
+ * the next location cyclically in the table. The value returned is the sum
+ * generated, reduced to 31 bits by throwing away the "least random" low bit.
+ *
+ * Note: the code takes advantage of the fact that both the front and
+ * rear pointers can't wrap on the same call by not testing the rear
+ * pointer if the front one has wrapped.
+ *
+ * Returns a 31-bit random number.
+ */
+long
+random()
+{
+ uint32_t i;
+ uint32_t *f, *r;
+
+ if (rand_type == TYPE_0) {
+ i = state[0];
+ state[0] = i = (good_rand(i)) & 0x7fffffff;
+ } else {
+ /*
+ * Use local variables rather than static variables for speed.
+ */
+ f = fptr; r = rptr;
+ *f += *r;
+ i = (*f >> 1) & 0x7fffffff; /* chucking least random bit */
+ if (++f >= end_ptr) {
+ f = state;
+ ++r;
+ }
+ else if (++r >= end_ptr) {
+ r = state;
+ }
+
+ fptr = f; rptr = r;
+ }
+ return((long)i);
+}
diff --git a/lib/libc/stdlib/reallocf.c b/lib/libc/stdlib/reallocf.c
new file mode 100644
index 0000000..5320926
--- /dev/null
+++ b/lib/libc/stdlib/reallocf.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 1998, M. Warner Losh <imp@freebsd.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+
+void *
+reallocf(void *ptr, size_t size)
+{
+ void *nptr;
+
+ nptr = realloc(ptr, size);
+ if (!nptr && ptr)
+ free(ptr);
+ return (nptr);
+}
diff --git a/lib/libc/stdlib/realpath.3 b/lib/libc/stdlib/realpath.3
new file mode 100644
index 0000000..4205a3d
--- /dev/null
+++ b/lib/libc/stdlib/realpath.3
@@ -0,0 +1,120 @@
+.\" Copyright (c) 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)realpath.3 8.2 (Berkeley) 2/16/94
+.\" $FreeBSD$
+.\"
+.Dd February 16, 1994
+.Dt REALPATH 3
+.Os
+.Sh NAME
+.Nm realpath
+.Nd returns the canonicalized absolute pathname
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In stdlib.h
+.Ft "char *"
+.Fn realpath "const char *pathname" "char resolved_path[PATH_MAX]"
+.Sh DESCRIPTION
+The
+.Fn realpath
+function resolves all symbolic links, extra
+.Dq /
+characters and references to
+.Pa /./
+and
+.Pa /../
+in
+.Fa pathname ,
+and copies the resulting absolute pathname into
+the memory referenced by
+.Fa resolved_path .
+The
+.Fa resolved_path
+argument
+.Em must
+refer to a buffer capable of storing at least
+.Dv PATH_MAX
+characters.
+.Pp
+The
+.Fn realpath
+function will resolve both absolute and relative paths
+and return the absolute pathname corresponding to
+.Fa pathname .
+All but the last component of
+.Fa pathname
+must exist when
+.Fn realpath
+is called.
+.Sh "RETURN VALUES"
+The
+.Fn realpath
+function returns
+.Fa resolved_path
+on success.
+If an error occurs,
+.Fn realpath
+returns
+.Dv NULL ,
+and
+.Fa resolved_path
+contains the pathname which caused the problem.
+.Sh ERRORS
+The function
+.Fn realpath
+may fail and set the external variable
+.Va errno
+for any of the errors specified for the library functions
+.Xr lstat 2 ,
+.Xr readlink 2
+and
+.Xr getcwd 3 .
+.Sh CAVEATS
+This implementation of
+.Fn realpath
+differs slightly from the Solaris implementation.
+The
+.Bx 4.4
+version always returns absolute pathnames,
+whereas the Solaris implementation will,
+under certain circumstances, return a relative
+.Fa resolved_path
+when given a relative
+.Fa pathname .
+.Sh "SEE ALSO"
+.Xr getcwd 3
+.Sh HISTORY
+The
+.Fn realpath
+function first appeared in
+.Bx 4.4 .
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
new file mode 100644
index 0000000..3082f5f
--- /dev/null
+++ b/lib/libc/stdlib/realpath.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+ *
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+/*
+ * char *realpath(const char *path, char resolved[PATH_MAX]);
+ *
+ * Find the real name of path, by removing all ".", ".." and symlink
+ * components. Returns (resolved) on success, or (NULL) on failure,
+ * in which case the path which caused trouble is left in (resolved).
+ */
+char *
+realpath(const char *path, char resolved[PATH_MAX])
+{
+ struct stat sb;
+ char *p, *q, *s;
+ size_t left_len, resolved_len;
+ unsigned symlinks;
+ int serrno, slen;
+ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
+
+ serrno = errno;
+ symlinks = 0;
+ if (path[0] == '/') {
+ resolved[0] = '/';
+ resolved[1] = '\0';
+ if (path[1] == '\0')
+ return (resolved);
+ resolved_len = 1;
+ left_len = strlcpy(left, path + 1, sizeof(left));
+ } else {
+ if (getcwd(resolved, PATH_MAX) == NULL) {
+ strlcpy(resolved, ".", PATH_MAX);
+ return (NULL);
+ }
+ resolved_len = strlen(resolved);
+ left_len = strlcpy(left, path, sizeof(left));
+ }
+ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+
+ /*
+ * Iterate over path components in `left'.
+ */
+ while (left_len != 0) {
+ /*
+ * Extract the next path component and adjust `left'
+ * and its length.
+ */
+ p = strchr(left, '/');
+ s = p ? p : left + left_len;
+ if (s - left >= sizeof(next_token)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ memcpy(next_token, left, s - left);
+ next_token[s - left] = '\0';
+ left_len -= s - left;
+ if (p != NULL)
+ memmove(left, s + 1, left_len + 1);
+ if (resolved[resolved_len - 1] != '/') {
+ if (resolved_len + 1 >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ resolved[resolved_len++] = '/';
+ resolved[resolved_len] = '\0';
+ }
+ if (next_token[0] == '\0')
+ continue;
+ else if (strcmp(next_token, ".") == 0)
+ continue;
+ else if (strcmp(next_token, "..") == 0) {
+ /*
+ * Strip the last path component except when we have
+ * single "/"
+ */
+ if (resolved_len > 1) {
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+ continue;
+ }
+
+ /*
+ * Append the next path component and lstat() it. If
+ * lstat() fails we still can return successfully if
+ * there are no more path components left.
+ */
+ resolved_len = strlcat(resolved, next_token, PATH_MAX);
+ if (resolved_len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ if (lstat(resolved, &sb) != 0) {
+ if (errno == ENOENT && p == NULL) {
+ errno = serrno;
+ return (resolved);
+ }
+ return (NULL);
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ if (symlinks++ > MAXSYMLINKS) {
+ errno = ELOOP;
+ return (NULL);
+ }
+ slen = readlink(resolved, symlink, sizeof(symlink) - 1);
+ if (slen < 0)
+ return (NULL);
+ symlink[slen] = '\0';
+ if (symlink[0] == '/') {
+ resolved[1] = 0;
+ resolved_len = 1;
+ } else if (resolved_len > 1) {
+ /* Strip the last path component. */
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+
+ /*
+ * If there are any path components left, then
+ * append them to symlink. The result is placed
+ * in `left'.
+ */
+ if (p != NULL) {
+ if (symlink[slen - 1] != '/') {
+ if (slen + 1 >= sizeof(symlink)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ symlink[slen] = '/';
+ symlink[slen + 1] = 0;
+ }
+ left_len = strlcat(symlink, left, sizeof(left));
+ if (left_len >= sizeof(left)) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ }
+ left_len = strlcpy(left, symlink, sizeof(left));
+ }
+ }
+
+ /*
+ * Remove trailing slash except when the resolved pathname
+ * is a single "/".
+ */
+ if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
+ resolved[resolved_len - 1] = '\0';
+ return (resolved);
+}
diff --git a/lib/libc/stdlib/remque.c b/lib/libc/stdlib/remque.c
new file mode 100644
index 0000000..0a2f28f
--- /dev/null
+++ b/lib/libc/stdlib/remque.c
@@ -0,0 +1,30 @@
+/*
+ * Initial implementation:
+ * Copyright (c) 2002 Robert Drehmel
+ * All rights reserved.
+ *
+ * As long as the above copyright statement and this notice remain
+ * unchanged, you can do what ever you want with this file.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h> /* for NULL */
+
+void
+remque(void *element)
+{
+ struct que_elem *prev, *next, *elem;
+
+ elem = (struct que_elem *)element;
+
+ prev = elem->prev;
+ next = elem->next;
+
+ if (prev != NULL)
+ prev->next = next;
+ if (next != NULL)
+ next->prev = prev;
+}
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
new file mode 100644
index 0000000..202c022
--- /dev/null
+++ b/lib/libc/stdlib/setenv.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *__findenv(const char *, int *);
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+int
+setenv(name, value, rewrite)
+ const char *name;
+ const char *value;
+ int rewrite;
+{
+ extern char **environ;
+ static char **alloced; /* if allocated space before */
+ char *c;
+ int l_value, offset;
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = __findenv(name, &offset))) { /* find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /* old larger; copy over */
+ while ( (*c++ = *value++) );
+ return (0);
+ }
+ } else { /* create new slot */
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced == environ) { /* just increase size */
+ p = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ alloced = environ = p;
+ }
+ else { /* get new space */
+ /* copy old entries into it */
+ p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ bcopy(environ, p, cnt * sizeof(char *));
+ alloced = environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; (*c++ = *value++); );
+ return (0);
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+ const char *name;
+{
+ extern char **environ;
+ char **p;
+ int offset;
+
+ while (__findenv(name, &offset)) /* if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
diff --git a/lib/libc/stdlib/strfmon.3 b/lib/libc/stdlib/strfmon.3
new file mode 100644
index 0000000..11b8e21
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.3
@@ -0,0 +1,167 @@
+.\" Copyright (c) 2001 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org>
+.\" 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 REGENTS 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 REGENTS 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$
+.\"
+.Dd October 12, 2002
+.Dt STRFMON 3
+.Os
+.Sh NAME
+.Nm strfmon
+.Nd convert monetary value to string
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In monetary.h
+.Ft ssize_t
+.Fn strfmon "char * restrict s" "size_t maxsize" "const char * restrict format" "..."
+.Sh DESCRIPTION
+The
+.Fn strfmon
+function places characters into the array pointed to by
+.Fa s
+as controlled by the string pointed to by
+.Fa format .
+No more than
+.Fa maxsize
+bytes are placed into the array.
+.Pp
+The format string is composed of zero or more directives:
+ordinary characters (not
+.Cm % ) ,
+which are copied unchanged to the output stream; and conversion
+specifications, each of which results in fetching zero or more subsequent
+arguments.
+Each conversion specification is introduced by the
+.Cm %
+character.
+After the
+.Cm % ,
+the following appear in sequence:
+.Bl -bullet
+.It
+Zero or more of the following flags:
+.Bl -tag -width "XXX"
+.It Cm = Ns Ar f
+A
+.Sq Cm =
+character followed by another character
+.Ar f
+which is used as the numeric fill character.
+.It Cm ^
+Do not use grouping characters, regardless of the current locale default.
+.It Cm +
+Represent positive values by prefixing them with a positive sign,
+and negative values by prefixing them with a negative sign.
+This is the default.
+.It Cm \&(
+Enclose negative values in parentheses.
+.It Cm \&!
+Do not include a currency symbol in the output.
+.It Cm \-
+Left justify the result.
+Only valid when a field width is specified.
+.El
+.It
+An optional minimum field width as a decimal number.
+By default, there is no minimum width.
+.It
+A
+.Sq Cm #
+sign followed by a decimal number specifying the maximum
+expected number of digits after the radix character.
+.It
+A
+.Sq Cm \&.
+character followed by a decimal number specifying the number
+the number of digits after the radix character.
+.It
+One of the following conversion specifiers:
+.Bl -tag -width "XXX"
+.It Cm i
+The
+.Vt double
+argument is formatted as an international monetary amount.
+.It Cm n
+The
+.Vt double
+argument is formatted as a national monetary amount.
+.It Cm %
+A
+.Sq Li %
+character is written.
+.El
+.El
+.Sh RETURN VALUES
+If the total number of resulting bytes including the terminating
+.Dv NULL
+byte is not more than
+.Fa maxsize ,
+.Fn strfmon
+returns the number of bytes placed into the array pointed to by
+.Fa s ,
+not including the terminating
+.Dv NULL
+byte.
+Otherwise, \-1 is returned,
+the contents of the array are indeterminate,
+and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn strfmon
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er E2BIG
+Conversion stopped due to lack of space in the buffer.
+.It Bq Er EINVAL
+The format string is invalid.
+.It Bq Er ENOMEM
+Not enough memory for temporary buffers.
+.El
+.Sh SEE ALSO
+.Xr localeconv 3
+.Sh STANDARDS
+The
+.Fn strfmon
+function
+conforms to
+.St -p1003.1-2001 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Fn strfmon
+function was implemented by
+.An Alexey Zelkin Aq phantom@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Jeroen Ruigrok van der Werven Aq asmodai@FreeBSD.org
+based on the standards' text.
+.Sh BUGS
+The
+.Fn strfmon
+function does not correctly handle multibyte characters in the
+.Fa format
+argument.
diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c
new file mode 100644
index 0000000..db78232
--- /dev/null
+++ b/lib/libc/stdlib/strfmon.c
@@ -0,0 +1,604 @@
+/*-
+ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <monetary.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* internal flags */
+#define NEED_GROUPING 0x01 /* print digits grouped (default) */
+#define SIGN_POSN_USED 0x02 /* '+' or '(' usage flag */
+#define LOCALE_POSN 0x04 /* use locale defined +/- (default) */
+#define PARENTH_POSN 0x08 /* enclose negative amount in () */
+#define SUPRESS_CURR_SYMBOL 0x10 /* supress the currency from output */
+#define LEFT_JUSTIFY 0x20 /* left justify */
+#define USE_INTL_CURRENCY 0x40 /* use international currency symbol */
+#define IS_NEGATIVE 0x80 /* is argument value negative ? */
+
+/* internal macros */
+#define PRINT(CH) do { \
+ if (dst >= s + maxsize) \
+ goto e2big_error; \
+ *dst++ = CH; \
+} while (0)
+
+#define PRINTS(STR) do { \
+ char *tmps = STR; \
+ while (*tmps != '\0') \
+ PRINT(*tmps++); \
+} while (0)
+
+#define GET_NUMBER(VAR) do { \
+ VAR = 0; \
+ while (isdigit((unsigned char)*fmt)) { \
+ VAR *= 10; \
+ VAR += *fmt - '0'; \
+ fmt++; \
+ } \
+} while (0)
+
+#define GRPCPY(howmany) do { \
+ int i = howmany; \
+ while (i-- > 0) { \
+ avalue_size--; \
+ *--bufend = *(avalue+avalue_size+padded); \
+ } \
+} while (0)
+
+#define GRPSEP do { \
+ *--bufend = thousands_sep; \
+ groups++; \
+} while (0)
+
+static void __setup_vars(int, char *, char *, char *, char **);
+static int __calc_left_pad(int, char *);
+static char *__format_grouped_double(double, int *, int, int, int);
+
+ssize_t
+strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
+ ...)
+{
+ va_list ap;
+ char *dst; /* output destination pointer */
+ const char *fmt; /* current format poistion pointer */
+ struct lconv *lc; /* pointer to lconv structure */
+ char *asciivalue; /* formatted double pointer */
+
+ int flags; /* formatting options */
+ int pad_char; /* padding character */
+ int pad_size; /* pad size */
+ int width; /* field width */
+ int left_prec; /* left precision */
+ int right_prec; /* right precision */
+ double value; /* just value */
+ char space_char = ' '; /* space after currency */
+
+ char cs_precedes, /* values gathered from struct lconv */
+ sep_by_space,
+ sign_posn,
+ *signstr,
+ *currency_symbol;
+
+ char *tmpptr; /* temporary vars */
+ int sverrno;
+
+ va_start(ap, format);
+
+ lc = localeconv();
+ dst = s;
+ fmt = format;
+ asciivalue = NULL;
+ currency_symbol = NULL;
+ pad_size = 0;
+
+ while (*fmt) {
+ /* pass nonformating characters AS IS */
+ if (*fmt != '%')
+ goto literal;
+
+ /* '%' found ! */
+
+ /* "%%" mean just '%' */
+ if (*(fmt+1) == '%') {
+ fmt++;
+ literal:
+ PRINT(*fmt++);
+ continue;
+ }
+
+ /* set up initial values */
+ flags = (NEED_GROUPING|LOCALE_POSN);
+ pad_char = ' '; /* padding character is "space" */
+ left_prec = -1; /* no left precision specified */
+ right_prec = -1; /* no right precision specified */
+ width = -1; /* no width specified */
+ value = 0; /* we have no value to print now */
+
+ /* Flags */
+ while (1) {
+ switch (*++fmt) {
+ case '=': /* fill character */
+ pad_char = *++fmt;
+ if (pad_char == '\0')
+ goto format_error;
+ continue;
+ case '^': /* not group currency */
+ flags &= ~(NEED_GROUPING);
+ continue;
+ case '+': /* use locale defined signs */
+ if (flags & SIGN_POSN_USED)
+ goto format_error;
+ flags |= (SIGN_POSN_USED|LOCALE_POSN);
+ continue;
+ case '(': /* enclose negatives with () */
+ if (flags & SIGN_POSN_USED)
+ goto format_error;
+ flags |= (SIGN_POSN_USED|PARENTH_POSN);
+ continue;
+ case '!': /* suppress currency symbol */
+ flags |= SUPRESS_CURR_SYMBOL;
+ continue;
+ case '-': /* alignment (left) */
+ flags |= LEFT_JUSTIFY;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* field Width */
+ if (isdigit((unsigned char)*fmt)) {
+ GET_NUMBER(width);
+ /* Do we have enough space to put number with
+ * required width ?
+ */
+ if (dst + width >= s + maxsize)
+ goto e2big_error;
+ }
+
+ /* Left precision */
+ if (*fmt == '#') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(left_prec);
+ }
+
+ /* Right precision */
+ if (*fmt == '.') {
+ if (!isdigit((unsigned char)*++fmt))
+ goto format_error;
+ GET_NUMBER(right_prec);
+ }
+
+ /* Conversion Characters */
+ switch (*fmt++) {
+ case 'i': /* use internaltion currency format */
+ flags |= USE_INTL_CURRENCY;
+ break;
+ case 'n': /* use national currency format */
+ flags &= ~(USE_INTL_CURRENCY);
+ break;
+ default: /* required character is missing or
+ premature EOS */
+ goto format_error;
+ }
+
+ if (flags & USE_INTL_CURRENCY) {
+ currency_symbol = strdup(lc->int_curr_symbol);
+ if (currency_symbol != NULL)
+ space_char = *(currency_symbol+3);
+ } else
+ currency_symbol = strdup(lc->currency_symbol);
+
+ if (currency_symbol == NULL)
+ goto end_error; /* ENOMEM. */
+
+ /* value itself */
+ value = va_arg(ap, double);
+
+ /* detect sign */
+ if (value < 0) {
+ flags |= IS_NEGATIVE;
+ value = -value;
+ }
+
+ /* fill left_prec with amount of padding chars */
+ if (left_prec >= 0) {
+ pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
+ currency_symbol) -
+ __calc_left_pad(flags, currency_symbol);
+ if (pad_size < 0)
+ pad_size = 0;
+ }
+
+ asciivalue = __format_grouped_double(value, &flags,
+ left_prec, right_prec, pad_char);
+ if (asciivalue == NULL)
+ goto end_error; /* errno already set */
+ /* to ENOMEM by malloc() */
+
+ /* set some variables for later use */
+ __setup_vars(flags, &cs_precedes, &sep_by_space,
+ &sign_posn, &signstr);
+
+ /*
+ * Description of some LC_MONETARY's values:
+ *
+ * p_cs_precedes & n_cs_precedes
+ *
+ * = 1 - $currency_symbol precedes the value
+ * for a monetary quantity with a non-negative value
+ * = 0 - symbol succeeds the value
+ *
+ * p_sep_by_space & n_sep_by_space
+ *
+ * = 0 - no space separates $currency_symbol
+ * from the value for a monetary quantity with a
+ * non-negative value
+ * = 1 - space separates the symbol from the value
+ * = 2 - space separates the symbol and the sign string,
+ * if adjacent.
+ *
+ * p_sign_posn & n_sign_posn
+ *
+ * = 0 - parentheses enclose the quantity and the
+ * $currency_symbol
+ * = 1 - the sign string precedes the quantity and the
+ * $currency_symbol
+ * = 2 - the sign string succeeds the quantity and the
+ * $currency_symbol
+ * = 3 - the sign string precedes the $currency_symbol
+ * = 4 - the sign string succeeds the $currency_symbol
+ *
+ */
+
+ tmpptr = dst;
+
+ while (pad_size-- > 0)
+ PRINT(' ');
+
+ if (sign_posn == 0 && (flags & IS_NEGATIVE))
+ PRINT('(');
+
+ if (cs_precedes == 1) {
+ if (sign_posn == 1 || sign_posn == 3) {
+ PRINTS(signstr);
+ if (sep_by_space == 2) /* XXX: ? */
+ PRINT(' ');
+ }
+
+ if (!(flags & SUPRESS_CURR_SYMBOL)) {
+ PRINTS(currency_symbol);
+
+ if (sign_posn == 4) {
+ if (sep_by_space == 2)
+ PRINT(space_char);
+ PRINTS(signstr);
+ if (sep_by_space == 1)
+ PRINT(' ');
+ } else if (sep_by_space == 1)
+ PRINT(space_char);
+ }
+ } else if (sign_posn == 1)
+ PRINTS(signstr);
+
+ PRINTS(asciivalue);
+
+ if (cs_precedes == 0) {
+ if (sign_posn == 3) {
+ if (sep_by_space == 1)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+
+ if (!(flags & SUPRESS_CURR_SYMBOL)) {
+ if ((sign_posn == 3 && sep_by_space == 2)
+ || (sep_by_space == 1
+ && (sign_posn == 0
+ || sign_posn == 1
+ || sign_posn == 2
+ || sign_posn == 4)))
+ PRINT(space_char);
+ PRINTS(currency_symbol); /* XXX: len */
+ if (sign_posn == 4) {
+ if (sep_by_space == 2)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+ }
+ }
+
+ if (sign_posn == 2) {
+ if (sep_by_space == 2)
+ PRINT(' ');
+ PRINTS(signstr);
+ }
+
+ if (sign_posn == 0 && (flags & IS_NEGATIVE))
+ PRINT(')');
+
+ if (dst - tmpptr < width) {
+ if (flags & LEFT_JUSTIFY) {
+ while (dst - tmpptr < width)
+ PRINT(' ');
+ } else {
+ pad_size = dst-tmpptr;
+ memmove(tmpptr + width-pad_size, tmpptr,
+ pad_size);
+ memset(tmpptr, ' ', width-pad_size);
+ dst += width-pad_size;
+ }
+ }
+ }
+
+ PRINT('\0');
+ va_end(ap);
+ free(asciivalue);
+ free(currency_symbol);
+ return (dst - s - 1); /* return size of put data except trailing '\0' */
+
+e2big_error:
+ errno = E2BIG;
+ goto end_error;
+
+format_error:
+ errno = EINVAL;
+
+end_error:
+ sverrno = errno;
+ if (asciivalue != NULL)
+ free(asciivalue);
+ if (currency_symbol != NULL)
+ free(currency_symbol);
+ errno = sverrno;
+ va_end(ap);
+ return (-1);
+}
+
+static void
+__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
+ char *sign_posn, char **signstr) {
+
+ struct lconv *lc = localeconv();
+
+ if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
+ *cs_precedes = lc->int_n_cs_precedes;
+ *sep_by_space = lc->int_n_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
+ *signstr = (lc->negative_sign == '\0') ? "-"
+ : lc->negative_sign;
+ } else if (flags & USE_INTL_CURRENCY) {
+ *cs_precedes = lc->int_p_cs_precedes;
+ *sep_by_space = lc->int_p_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
+ *signstr = lc->positive_sign;
+ } else if (flags & IS_NEGATIVE) {
+ *cs_precedes = lc->n_cs_precedes;
+ *sep_by_space = lc->n_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
+ *signstr = (lc->negative_sign == '\0') ? "-"
+ : lc->negative_sign;
+ } else {
+ *cs_precedes = lc->p_cs_precedes;
+ *sep_by_space = lc->p_sep_by_space;
+ *sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
+ *signstr = lc->positive_sign;
+ }
+
+ /* Set defult values for unspecified information. */
+ if (*cs_precedes != 0)
+ *cs_precedes = 1;
+ if (*sep_by_space == CHAR_MAX)
+ *sep_by_space = 0;
+ if (*sign_posn == CHAR_MAX)
+ *sign_posn = 0;
+}
+
+static int
+__calc_left_pad(int flags, char *cur_symb) {
+
+ char cs_precedes, sep_by_space, sign_posn, *signstr;
+ int left_chars = 0;
+
+ __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
+
+ if (cs_precedes != 0) {
+ left_chars += strlen(cur_symb);
+ if (sep_by_space != 0)
+ left_chars++;
+ }
+
+ switch (sign_posn) {
+ case 1:
+ left_chars += strlen(signstr);
+ break;
+ case 3:
+ case 4:
+ if (cs_precedes != 0)
+ left_chars += strlen(signstr);
+ }
+ return (left_chars);
+}
+
+static int
+get_groups(int size, char *grouping) {
+
+ int chars = 0;
+
+ if (*grouping == CHAR_MAX || *grouping <= 0) /* no grouping ? */
+ return (0);
+
+ while (size > (int)*grouping) {
+ chars++;
+ size -= (int)*grouping++;
+ /* no more grouping ? */
+ if (*grouping == CHAR_MAX)
+ break;
+ /* rest grouping with same value ? */
+ if (*grouping == 0) {
+ chars += (size - 1) / *(grouping - 1);
+ break;
+ }
+ }
+ return (chars);
+}
+
+/* convert double to ASCII */
+static char *
+__format_grouped_double(double value, int *flags,
+ int left_prec, int right_prec, int pad_char) {
+
+ char *rslt;
+ char *avalue;
+ int avalue_size;
+ char fmt[32];
+
+ size_t bufsize;
+ char *bufend;
+
+ int padded;
+
+ struct lconv *lc = localeconv();
+ char *grouping;
+ char decimal_point;
+ char thousands_sep;
+
+ int groups = 0;
+
+ grouping = lc->mon_grouping;
+ decimal_point = *lc->mon_decimal_point;
+ if (decimal_point == '\0')
+ decimal_point = *lc->decimal_point;
+ thousands_sep = *lc->mon_thousands_sep;
+ if (thousands_sep == '\0')
+ thousands_sep = *lc->thousands_sep;
+
+ /* fill left_prec with default value */
+ if (left_prec == -1)
+ left_prec = 0;
+
+ /* fill right_prec with default value */
+ if (right_prec == -1) {
+ if (*flags & USE_INTL_CURRENCY)
+ right_prec = lc->int_frac_digits;
+ else
+ right_prec = lc->frac_digits;
+
+ if (right_prec == CHAR_MAX) /* POSIX locale ? */
+ right_prec = 2;
+ }
+
+ if (*flags & NEED_GROUPING)
+ left_prec += get_groups(left_prec, grouping);
+
+ /* convert to string */
+ snprintf(fmt, sizeof(fmt), "%%%d.%df", left_prec + right_prec + 1,
+ right_prec);
+ avalue_size = asprintf(&avalue, fmt, value);
+ if (avalue_size < 0)
+ return (NULL);
+
+ /* make sure that we've enough space for result string */
+ bufsize = strlen(avalue)*2+1;
+ rslt = malloc(bufsize);
+ if (rslt == NULL) {
+ free(avalue);
+ return (NULL);
+ }
+ memset(rslt, 0, bufsize);
+ bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */
+
+ /* skip spaces at beggining */
+ padded = 0;
+ while (avalue[padded] == ' ') {
+ padded++;
+ avalue_size--;
+ }
+
+ if (right_prec > 0) {
+ bufend -= right_prec;
+ memcpy(bufend, avalue + avalue_size+padded-right_prec,
+ right_prec);
+ *--bufend = decimal_point;
+ avalue_size -= (right_prec + 1);
+ }
+
+ if ((*flags & NEED_GROUPING) &&
+ thousands_sep != '\0' && /* XXX: need investigation */
+ *grouping != CHAR_MAX &&
+ *grouping > 0) {
+ while (avalue_size > (int)*grouping) {
+ GRPCPY(*grouping);
+ GRPSEP;
+ grouping++;
+
+ /* no more grouping ? */
+ if (*grouping == CHAR_MAX)
+ break;
+
+ /* rest grouping with same value ? */
+ if (*grouping == 0) {
+ grouping--;
+ while (avalue_size > *grouping) {
+ GRPCPY(*grouping);
+ GRPSEP;
+ }
+ }
+ }
+ if (avalue_size != 0)
+ GRPCPY(avalue_size);
+ padded -= groups;
+
+ } else {
+ bufend -= avalue_size;
+ memcpy(bufend, avalue+padded, avalue_size);
+ if (right_prec == 0)
+ padded--; /* decrease assumed $decimal_point */
+ }
+
+ /* do padding with pad_char */
+ if (padded > 0) {
+ bufend -= padded;
+ memset(bufend, pad_char, padded);
+ }
+
+ bufsize = bufsize - (bufend - rslt) + 1;
+ memmove(rslt, bufend, bufsize);
+ free(avalue);
+ return (rslt);
+}
diff --git a/lib/libc/stdlib/strtod.3 b/lib/libc/stdlib/strtod.3
new file mode 100644
index 0000000..33dd452
--- /dev/null
+++ b/lib/libc/stdlib/strtod.3
@@ -0,0 +1,181 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)strtod.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd March 2, 2003
+.Dt STRTOD 3
+.Os
+.Sh NAME
+.Nm strtod , strtof , strtold
+.Nd convert
+.Tn ASCII
+string to floating point
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft double
+.Fn strtod "const char * restrict nptr" "char ** restrict endptr"
+.Ft float
+.Fn strtof "const char * restrict nptr" "char ** restrict endptr"
+.Ft "long double"
+.Fn strtold "const char * restrict nptr" "char ** restrict endptr"
+.Sh DESCRIPTION
+These conversion
+functions convert the initial portion of the string
+pointed to by
+.Fa nptr
+to
+.Vt double ,
+.Vt float ,
+and
+.Vt "long double"
+representation, respectively.
+.Pp
+The expected form of the string is an optional plus (``+'') or minus
+sign (``\-'') followed by either:
+.Bl -bullet
+.It
+a decimal significand consisting of a sequence of decimal digits
+optionally containing a decimal-point character, or
+.It
+a hexadecimal significand consisting of a ``0X'' or ``0x'' followed
+by a sequence of hexadecimal digits optionally containing a
+decimal-point character.
+.El
+.Pp
+In both cases, the significand may be optionally followed by an
+exponent.
+An exponent consists of an ``E'' or ``e'' (for decimal
+constants) or a ``P'' or ``p'' (for hexadecimal constants),
+followed by an optional plus or minus sign, followed by a
+sequence of decimal digits.
+For decimal constants, the exponent indicates the power of 10 by
+which the significand should be scaled.
+For hexadecimal constants, the scaling is instead done by powers
+of 2.
+.Pp
+Alternatively, if the portion of the string following the optional
+plus or minus sign begins with ``INFINITY'' or ``NAN'', ignoring
+case, it is interpreted as an infinity or a quiet NaN, respectively.
+.Pp
+In any of the above cases, leading white-space characters in the
+string (as defined by the
+.Xr isspace 3
+function) are skipped.
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Sh RETURN VALUES
+The
+.Fn strtod ,
+.Fn strtof ,
+and
+.Fn strtold
+functions return the converted value, if any.
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+a pointer to the character after the last character used
+in the conversion is stored in the location referenced by
+.Fa endptr .
+.Pp
+If no conversion is performed, zero is returned and the value of
+.Fa nptr
+is stored in the location referenced by
+.Fa endptr .
+.Pp
+If the correct value would cause overflow, plus or minus
+.Dv HUGE_VAL ,
+.Dv HUGE_VALF ,
+or
+.Dv HUGE_VALL
+is returned (according to the sign and type of the return value), and
+.Er ERANGE
+is stored in
+.Va errno .
+If the correct value would cause underflow, zero is
+returned and
+.Er ERANGE
+is stored in
+.Va errno .
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+Overflow or underflow occurred.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3 ,
+.Xr wcstod 3
+.Sh STANDARDS
+The
+.Fn strtod
+function
+conforms to
+.St -isoC-99 ,
+with the exception of the bug noted below.
+.Sh AUTHORS
+The author of this software is
+.An David M. Gay .
+.Pp
+.Bd -literal
+Copyright (c) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+.Ed
+.Sh BUGS
+These routines do not recognize the C99 ``NaN(...)'' syntax.
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
new file mode 100644
index 0000000..4f0063c
--- /dev/null
+++ b/lib/libc/stdlib/strtoimax.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+/*
+ * Convert a string to an intmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+intmax_t
+strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for intmax_t is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
+ : INTMAX_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? INTMAX_MIN : INTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3
new file mode 100644
index 0000000..02316f5
--- /dev/null
+++ b/lib/libc/stdlib/strtol.3
@@ -0,0 +1,222 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)strtol.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.Dt STRTOL 3
+.Os
+.Sh NAME
+.Nm strtol , strtoll , strtoimax , strtoq
+.Nd "convert a string value to a"
+.Vt long , "long long" , intmax_t
+or
+.Vt quad_t
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.In limits.h
+.Ft long
+.Fn strtol "const char * restrict nptr" "char ** restrict endptr" "int base"
+.Ft long long
+.Fn strtoll "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In inttypes.h
+.Ft intmax_t
+.Fn strtoimax "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In sys/types.h
+.In stdlib.h
+.In limits.h
+.Ft quad_t
+.Fn strtoq "const char *nptr" "char **endptr" "int base"
+.Sh DESCRIPTION
+The
+.Fn strtol
+function
+converts the string in
+.Fa nptr
+to a
+.Vt long
+value.
+The
+.Fn strtoll
+function
+converts the string in
+.Fa nptr
+to a
+.Vt "long long"
+value.
+The
+.Fn strtoimax
+function
+converts the string in
+.Fa nptr
+to an
+.Vt intmax_t
+value.
+The
+.Fn strtoq
+function
+converts the string in
+.Fa nptr
+to a
+.Vt quad_t
+value.
+The conversion is done according to the given
+.Fa base ,
+which must be between 2 and 36 inclusive,
+or be the special value 0.
+.Pp
+The string may begin with an arbitrary amount of white space
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+If
+.Fa base
+is zero or 16,
+the string may then include a
+.Dq Li 0x
+prefix,
+and the number will be read in base 16; otherwise, a zero
+.Fa base
+is taken as 10 (decimal) unless the next character is
+.Ql 0 ,
+in which case it is taken as 8 (octal).
+.Pp
+The remainder of the string is converted to a
+.Vt long , "long long" , intmax_t
+or
+.Vt quad_t
+value in the obvious manner,
+stopping at the first character which is not a valid digit
+in the given base.
+(In bases above 10, the letter
+.Ql A
+in either upper or lower case
+represents 10,
+.Ql B
+represents 11, and so forth, with
+.Ql Z
+representing 35.)
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+.Fn strtol
+stores the address of the first invalid character in
+.Fa *endptr .
+If there were no digits at all, however,
+.Fn strtol
+stores the original value of
+.Fa nptr
+in
+.Fa *endptr .
+(Thus, if
+.Fa *nptr
+is not
+.Ql \e0
+but
+.Fa **endptr
+is
+.Ql \e0
+on return, the entire string was valid.)
+.Sh RETURN VALUES
+The
+.Fn strtol ,
+.Fn strtoll ,
+.Fn strtoimax
+and
+.Fn strtoq
+functions
+return the result of the conversion,
+unless the value would underflow or overflow.
+If no conversion could be performed, 0 is returned and
+the global variable
+.Va errno
+is set to
+.Er EINVAL
+(the last feature is not portable across all platforms).
+If an overflow or underflow occurs,
+.Va errno
+is set to
+.Er ERANGE
+and the function return value is clamped according
+to the following table.
+.Bl -column -offset indent ".Fn strtoimax" ".Sy underflow" ".Sy overflow"
+.It Sy Function Ta Sy underflow Ta Sy overflow
+.It Fn strtol Ta Dv LONG_MIN Ta Dv LONG_MAX
+.It Fn strtoll Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.It Fn strtoimax Ta Dv INTMAX_MIN Ta Dv INTMAX_MAX
+.It Fn strtoq Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.El
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of
+.Fa base
+is not supported or
+no conversion could be performed
+(the last feature is not portable across all platforms).
+.It Bq Er ERANGE
+The given string was out of range; the value converted has been clamped.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr strtod 3 ,
+.Xr strtonum 3 ,
+.Xr strtoul 3 ,
+.Xr wcstol 3
+.Sh STANDARDS
+The
+.Fn strtol
+function
+conforms to
+.St -isoC .
+The
+.Fn strtoll
+and
+.Fn strtoimax
+functions
+conform to
+.St -isoC-99 .
+The
+.Bx
+.Fn strtoq
+function is deprecated.
diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c
new file mode 100644
index 0000000..0d6f736
--- /dev/null
+++ b/lib/libc/stdlib/strtol.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long
+strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
+ : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
new file mode 100644
index 0000000..2e5547d
--- /dev/null
+++ b/lib/libc/stdlib/strtoll.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long
+strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for quads is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
+ : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LLONG_MIN : LLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3
new file mode 100644
index 0000000..90f0b57
--- /dev/null
+++ b/lib/libc/stdlib/strtonum.3
@@ -0,0 +1,156 @@
+.\" Copyright (c) 2004 Ted Unangst
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $OpenBSD: strtonum.3,v 1.12 2005/10/26 11:37:58 jmc Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 29, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.In stdlib.h
+.In limits.h
+.Ft long long
+.Fo strtonum
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "long long maxval"
+.Fa "const char **errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn strtonum
+function converts the string in
+.Fa nptr
+to a
+.Vt "long long"
+value.
+The
+.Fn strtonum
+function was designed to facilitate safe, robust programming
+and overcome the shortcomings of the
+.Xr atoi 3
+and
+.Xr strtol 3
+family of interfaces.
+.Pp
+The string may begin with an arbitrary amount of whitespace
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+.Pp
+The remainder of the string is converted to a
+.Vt "long long"
+value according to base 10.
+.Pp
+The value obtained is then checked against the provided
+.Fa minval
+and
+.Fa maxval
+bounds.
+If
+.Fa errstr
+is non-null,
+.Fn strtonum
+stores an error string in
+.Fa *errstr
+indicating the failure.
+.Sh RETURN VALUES
+The
+.Fn strtonum
+function returns the result of the conversion,
+unless the value would exceed the provided bounds or is invalid.
+On error, 0 is returned,
+.Va errno
+is set, and
+.Fa errstr
+will point to an error message.
+On success,
+.Fa *errstr
+will be set to
+.Dv NULL ;
+this fact can be used to differentiate
+a successful return of 0 from an error.
+.Sh EXAMPLES
+Using
+.Fn strtonum
+correctly is meant to be simpler than the alternative functions.
+.Bd -literal -offset indent
+int iterations;
+const char *errstr;
+
+iterations = strtonum(optarg, 1, 64, &errstr);
+if (errstr)
+ errx(1, "number of iterations is %s: %s", errstr, optarg);
+.Ed
+.Pp
+The above example will guarantee that the value of iterations is between
+1 and 64 (inclusive).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The given string was out of range.
+.It Bq Er EINVAL
+The given string did not consist solely of digit characters.
+.It Bq Er EINVAL
+The supplied
+.Fa minval
+was larger than
+.Fa maxval .
+.El
+.Pp
+If an error occurs,
+.Fa errstr
+will be set to one of the following strings:
+.Pp
+.Bl -tag -width ".Li too large" -compact
+.It Li "too large"
+The result was larger than the provided maximum value.
+.It Li "too small"
+The result was smaller than the provided minimum value.
+.It Li invalid
+The string did not consist solely of digit characters.
+.El
+.Sh SEE ALSO
+.Xr atof 3 ,
+.Xr atoi 3 ,
+.Xr atol 3 ,
+.Xr atoll 3 ,
+.Xr sscanf 3 ,
+.Xr strtod 3 ,
+.Xr strtol 3 ,
+.Xr strtoul 3
+.Sh STANDARDS
+The
+.Fn strtonum
+function is a
+.Bx
+extension.
+The existing alternatives, such as
+.Xr atoi 3
+and
+.Xr strtol 3 ,
+are either impossible or difficult to use safely.
+.Sh HISTORY
+The
+.Fn strtonum
+function first appeared in
+.Ox 3.6 .
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
new file mode 100644
index 0000000..6dccd97
--- /dev/null
+++ b/lib/libc/stdlib/strtonum.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (errno == EINVAL || numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c
new file mode 100644
index 0000000..afad51f
--- /dev/null
+++ b/lib/libc/stdlib/strtoq.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/*
+ * Convert a string to a quad integer.
+ */
+quad_t
+strtoq(const char *nptr, char **endptr, int base)
+{
+
+ return strtoll(nptr, endptr, base);
+}
diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3
new file mode 100644
index 0000000..2c0f348
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.3
@@ -0,0 +1,224 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)strtoul.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd November 28, 2001
+.Dt STRTOUL 3
+.Os
+.Sh NAME
+.Nm strtoul , strtoull , strtoumax , strtouq
+.Nd "convert a string to an"
+.Vt "unsigned long" , "unsigned long long" , uintmax_t ,
+or
+.Vt u_quad_t
+integer
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.In limits.h
+.Ft "unsigned long"
+.Fn strtoul "const char * restrict nptr" "char ** restrict endptr" "int base"
+.Ft "unsigned long long"
+.Fn strtoull "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In inttypes.h
+.Ft uintmax_t
+.Fn strtoumax "const char * restrict nptr" "char ** restrict endptr" "int base"
+.In sys/types.h
+.In stdlib.h
+.In limits.h
+.Ft u_quad_t
+.Fn strtouq "const char *nptr" "char **endptr" "int base"
+.Sh DESCRIPTION
+The
+.Fn strtoul
+function
+converts the string in
+.Fa nptr
+to an
+.Vt "unsigned long"
+value.
+The
+.Fn strtoull
+function
+converts the string in
+.Fa nptr
+to an
+.Vt "unsigned long long"
+value.
+The
+.Fn strtoumax
+function
+converts the string in
+.Fa nptr
+to an
+.Vt uintmax_t
+value.
+The
+.Fn strtouq
+function
+converts the string in
+.Fa nptr
+to a
+.Vt u_quad_t
+value.
+The conversion is done according to the given
+.Fa base ,
+which must be between 2 and 36 inclusive,
+or be the special value 0.
+.Pp
+The string may begin with an arbitrary amount of white space
+(as determined by
+.Xr isspace 3 )
+followed by a single optional
+.Ql +
+or
+.Ql -
+sign.
+If
+.Fa base
+is zero or 16,
+the string may then include a
+.Dq Li 0x
+prefix,
+and the number will be read in base 16; otherwise, a zero
+.Fa base
+is taken as 10 (decimal) unless the next character is
+.Ql 0 ,
+in which case it is taken as 8 (octal).
+.Pp
+The remainder of the string is converted to an
+.Vt "unsigned long"
+value in the obvious manner,
+stopping at the end of the string
+or at the first character that does not produce a valid digit
+in the given base.
+(In bases above 10, the letter
+.Ql A
+in either upper or lower case
+represents 10,
+.Ql B
+represents 11, and so forth, with
+.Ql Z
+representing 35.)
+.Pp
+If
+.Fa endptr
+is not
+.Dv NULL ,
+.Fn strtoul
+stores the address of the first invalid character in
+.Fa *endptr .
+If there were no digits at all, however,
+.Fn strtoul
+stores the original value of
+.Fa nptr
+in
+.Fa *endptr .
+(Thus, if
+.Fa *nptr
+is not
+.Ql \e0
+but
+.Fa **endptr
+is
+.Ql \e0
+on return, the entire string was valid.)
+.Sh RETURN VALUES
+The
+.Fn strtoul ,
+.Fn strtoull ,
+.Fn strtoumax
+and
+.Fn strtouq
+functions
+return either the result of the conversion
+or, if there was a leading minus sign,
+the negation of the result of the conversion,
+unless the original (non-negated) value would overflow;
+in the latter case,
+.Fn strtoul
+returns
+.Dv ULONG_MAX ,
+.Fn strtoull
+returns
+.Dv ULLONG_MAX ,
+.Fn strtoumax
+returns
+.Dv UINTMAX_MAX ,
+and
+.Fn strtouq
+returns
+.Dv ULLONG_MAX .
+In all cases,
+.Va errno
+is set to
+.Er ERANGE .
+If no conversion could be performed, 0 is returned and
+the global variable
+.Va errno
+is set to
+.Er EINVAL
+(the last feature is not portable across all platforms).
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of
+.Fa base
+is not supported or
+no conversion could be performed
+(the last feature is not portable across all platforms).
+.It Bq Er ERANGE
+The given string was out of range; the value converted has been clamped.
+.El
+.Sh SEE ALSO
+.Xr strtol 3 ,
+.Xr strtonum 3 ,
+.Xr wcstoul 3
+.Sh STANDARDS
+The
+.Fn strtoul
+function
+conforms to
+.St -isoC .
+The
+.Fn strtoull
+and
+.Fn strtoumax
+functions
+conform to
+.St -isoC-99 .
+The
+.Bx
+.Fn strtouq
+function is deprecated.
diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c
new file mode 100644
index 0000000..e8d1e11
--- /dev/null
+++ b/lib/libc/stdlib/strtoul.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULONG_MAX / base;
+ cutlim = ULONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
new file mode 100644
index 0000000..f11910c
--- /dev/null
+++ b/lib/libc/stdlib/strtoull.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long long
+strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ unsigned long long acc;
+ char c;
+ unsigned long long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoq for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = ULLONG_MAX / base;
+ cutlim = ULLONG_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
new file mode 100644
index 0000000..23050c2
--- /dev/null
+++ b/lib/libc/stdlib/strtoumax.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+/*
+ * Convert a string to a uintmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uintmax_t
+strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
+{
+ const char *s;
+ uintmax_t acc;
+ char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') ||
+ (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f'))) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = UINTMAX_MAX / base;
+ cutlim = UINTMAX_MAX % base;
+ for ( ; ; c = *s++) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = UINTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c
new file mode 100644
index 0000000..9638c11
--- /dev/null
+++ b/lib/libc/stdlib/strtouq.c
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned quad integer.
+ */
+u_quad_t
+strtouq(const char *nptr, char **endptr, int base)
+{
+
+ return strtoull(nptr, endptr, base);
+}
diff --git a/lib/libc/stdlib/system.3 b/lib/libc/stdlib/system.3
new file mode 100644
index 0000000..27f5137
--- /dev/null
+++ b/lib/libc/stdlib/system.3
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the American National Standards Committee X3, on Information
+.\" Processing Systems.
+.\"
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\" @(#)system.3 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD$
+.\"
+.Dd June 4, 1993
+.Dt SYSTEM 3
+.Os
+.Sh NAME
+.Nm system
+.Nd pass a command to the shell
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fn system "const char *string"
+.Sh DESCRIPTION
+The
+.Fn system
+function
+hands the argument
+.Fa string
+to the command interpreter
+.Xr sh 1 .
+The calling process waits for the shell
+to finish executing the command,
+ignoring
+.Dv SIGINT
+and
+.Dv SIGQUIT ,
+and blocking
+.Dv SIGCHLD .
+.Pp
+If
+.Fa string
+is a
+.Dv NULL
+pointer,
+.Fn system
+will return non-zero if the command interpreter
+.Xr sh 1
+is available, and zero if it is not.
+.Pp
+The
+.Fn system
+function
+returns the exit status of the shell as returned by
+.Xr waitpid 2 ,
+or \-1 if an error occurred when invoking
+.Xr fork 2
+or
+.Xr waitpid 2 .
+A return value of 127 means the execution of the shell
+failed.
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr execve 2 ,
+.Xr fork 2 ,
+.Xr waitpid 2 ,
+.Xr popen 3
+.Sh STANDARDS
+The
+.Fn system
+function
+conforms to
+.St -isoC
+and is expected to be
+.St -p1003.2
+compatible.
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
new file mode 100644
index 0000000..08de630
--- /dev/null
+++ b/lib/libc/stdlib/system.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <paths.h>
+#include <errno.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+int
+__system(command)
+ const char *command;
+{
+ pid_t pid, savedpid;
+ int pstat;
+ struct sigaction ign, intact, quitact;
+ sigset_t newsigblock, oldsigblock;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ /*
+ * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
+ * existing signal dispositions.
+ */
+ ign.sa_handler = SIG_IGN;
+ (void)sigemptyset(&ign.sa_mask);
+ ign.sa_flags = 0;
+ (void)_sigaction(SIGINT, &ign, &intact);
+ (void)_sigaction(SIGQUIT, &ign, &quitact);
+ (void)sigemptyset(&newsigblock);
+ (void)sigaddset(&newsigblock, SIGCHLD);
+ (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
+ switch(pid = fork()) {
+ case -1: /* error */
+ break;
+ case 0: /* child */
+ /*
+ * Restore original signal dispositions and exec the command.
+ */
+ (void)_sigaction(SIGINT, &intact, NULL);
+ (void)_sigaction(SIGQUIT, &quitact, NULL);
+ (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
+ _exit(127);
+ default: /* parent */
+ savedpid = pid;
+ do {
+ pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
+ } while (pid == -1 && errno == EINTR);
+ break;
+ }
+ (void)_sigaction(SIGINT, &intact, NULL);
+ (void)_sigaction(SIGQUIT, &quitact, NULL);
+ (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
+ return(pid == -1 ? -1 : pstat);
+}
+
+__weak_reference(__system, system);
+__weak_reference(__system, _system);
diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c
new file mode 100644
index 0000000..c83afb8
--- /dev/null
+++ b/lib/libc/stdlib/tdelete.c
@@ -0,0 +1,71 @@
+/* $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+
+/*
+ * delete node with given key
+ *
+ * vkey: key to be deleted
+ * vrootp: address of the root of the tree
+ * compar: function to carry out node comparisons
+ */
+void *
+tdelete(const void * __restrict vkey, void ** __restrict vrootp,
+ int (*compar)(const void *, const void *))
+{
+ node_t **rootp = (node_t **)vrootp;
+ node_t *p, *q, *r;
+ int cmp;
+
+ if (rootp == NULL || (p = *rootp) == NULL)
+ return NULL;
+
+ while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
+ p = *rootp;
+ rootp = (cmp < 0) ?
+ &(*rootp)->llink : /* follow llink branch */
+ &(*rootp)->rlink; /* follow rlink branch */
+ if (*rootp == NULL)
+ return NULL; /* key not found */
+ }
+ r = (*rootp)->rlink; /* D1: */
+ if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
+ q = r;
+ else if (r != NULL) { /* Right link is NULL? */
+ if (r->llink == NULL) { /* D2: Find successor */
+ r->llink = q;
+ q = r;
+ } else { /* D3: Find NULL link */
+ for (q = r->llink; q->llink != NULL; q = r->llink)
+ r = q;
+ r->llink = q->rlink;
+ q->llink = (*rootp)->llink;
+ q->rlink = (*rootp)->rlink;
+ }
+ }
+ free(*rootp); /* D4: Free node */
+ *rootp = q; /* link parent to new node */
+ return p;
+}
diff --git a/lib/libc/stdlib/tfind.c b/lib/libc/stdlib/tfind.c
new file mode 100644
index 0000000..c5d66cf
--- /dev/null
+++ b/lib/libc/stdlib/tfind.c
@@ -0,0 +1,48 @@
+/* $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <stdlib.h>
+#include <search.h>
+
+/* find a node, or return 0 */
+void *
+tfind(vkey, vrootp, compar)
+ const void *vkey; /* key to be found */
+ void * const *vrootp; /* address of the tree root */
+ int (*compar)(const void *, const void *);
+{
+ node_t **rootp = (node_t **)vrootp;
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* key found */
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+ return NULL;
+}
diff --git a/lib/libc/stdlib/tsearch.3 b/lib/libc/stdlib/tsearch.3
new file mode 100644
index 0000000..7a204d0
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.3
@@ -0,0 +1,132 @@
+.\" $NetBSD$
+.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" 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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``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 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.
+.\"
+.\" OpenBSD: tsearch.3,v 1.2 1998/06/21 22:13:49 millert Exp
+.\" $FreeBSD$
+.\"
+.Dd June 15, 1997
+.Dt TSEARCH 3
+.Os
+.Sh NAME
+.Nm tsearch , tfind , tdelete , twalk
+.Nd manipulate binary search trees
+.Sh SYNOPSIS
+.In search.h
+.Ft void *
+.Fn tdelete "const void * restrict key" "void ** restrict rootp" "int (*compar) (const void *, const void *)"
+.Ft void *
+.Fn tfind "const void *key" "void * const *rootp" "int (*compar) (const void *, const void *)"
+.Ft void *
+.Fn tsearch "const void *key" "void **rootp" "int (*compar) (const void *, const void *)"
+.Ft void
+.Fn twalk "const void *root" "void (*action) (const void *, VISIT, int)"
+.Sh DESCRIPTION
+The
+.Fn tdelete ,
+.Fn tfind ,
+.Fn tsearch ,
+and
+.Fn twalk
+functions manage binary search trees based on algorithms T and D
+from Knuth (6.2.2).
+The comparison function passed in by
+the user has the same style of return values as
+.Xr strcmp 3 .
+.Pp
+The
+.Fn tfind
+function
+searches for the datum matched by the argument
+.Fa key
+in the binary tree rooted at
+.Fa rootp ,
+returning a pointer to the datum if it is found and NULL
+if it is not.
+.Pp
+The
+.Fn tsearch
+function
+is identical to
+.Fn tfind
+except that if no match is found,
+.Fa key
+is inserted into the tree and a pointer to it is returned.
+If
+.Fa rootp
+points to a NULL value a new binary search tree is created.
+.Pp
+The
+.Fn tdelete
+function
+deletes a node from the specified binary search tree and returns
+a pointer to the parent of the node to be deleted.
+It takes the same arguments as
+.Fn tfind
+and
+.Fn tsearch .
+If the node to be deleted is the root of the binary search tree,
+.Fa rootp
+will be adjusted.
+.Pp
+The
+.Fn twalk
+function
+walks the binary search tree rooted in
+.Fa root
+and calls the function
+.Fa action
+on each node.
+The
+.Fa action
+function
+is called with three arguments: a pointer to the current node,
+a value from the enum
+.Sy "typedef enum { preorder, postorder, endorder, leaf } VISIT;"
+specifying the traversal type, and a node level (where level
+zero is the root of the tree).
+.Sh RETURN VALUES
+The
+.Fn tsearch
+function returns NULL if allocation of a new node fails (usually
+due to a lack of free memory).
+.Pp
+The
+.Fn tfind ,
+.Fn tsearch ,
+and
+.Fn tdelete
+functions
+return NULL if
+.Fa rootp
+is NULL or the datum cannot be found.
+.Pp
+The
+.Fn twalk
+function returns no value.
+.Sh SEE ALSO
+.Xr bsearch 3 ,
+.Xr hsearch 3 ,
+.Xr lsearch 3
diff --git a/lib/libc/stdlib/tsearch.c b/lib/libc/stdlib/tsearch.c
new file mode 100644
index 0000000..149c2bb
--- /dev/null
+++ b/lib/libc/stdlib/tsearch.c
@@ -0,0 +1,58 @@
+/* $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+/* find or insert datum into search tree */
+void *
+tsearch(vkey, vrootp, compar)
+ const void *vkey; /* key to be located */
+ void **vrootp; /* address of tree root */
+ int (*compar)(const void *, const void *);
+{
+ node_t *q;
+ node_t **rootp = (node_t **)vrootp;
+
+ if (rootp == NULL)
+ return NULL;
+
+ while (*rootp != NULL) { /* Knuth's T1: */
+ int r;
+
+ if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
+ return *rootp; /* we found it! */
+
+ rootp = (r < 0) ?
+ &(*rootp)->llink : /* T3: follow left branch */
+ &(*rootp)->rlink; /* T4: follow right branch */
+ }
+
+ q = malloc(sizeof(node_t)); /* T5: key not found */
+ if (q != 0) { /* make new node */
+ *rootp = q; /* link new node to old */
+ /* LINTED const castaway ok */
+ q->key = (void *)vkey; /* initialize new node */
+ q->llink = q->rlink = NULL;
+ }
+ return q;
+}
diff --git a/lib/libc/stdlib/twalk.c b/lib/libc/stdlib/twalk.c
new file mode 100644
index 0000000..55f220f3
--- /dev/null
+++ b/lib/libc/stdlib/twalk.c
@@ -0,0 +1,58 @@
+/* $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $ */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+#endif
+__FBSDID("$FreeBSD$");
+
+#define _SEARCH_PRIVATE
+#include <search.h>
+#include <stdlib.h>
+
+static void trecurse(const node_t *,
+ void (*action)(const void *, VISIT, int), int level);
+
+/* Walk the nodes of a tree */
+static void
+trecurse(root, action, level)
+ const node_t *root; /* Root of the tree to be walked */
+ void (*action)(const void *, VISIT, int);
+ int level;
+{
+
+ if (root->llink == NULL && root->rlink == NULL)
+ (*action)(root, leaf, level);
+ else {
+ (*action)(root, preorder, level);
+ if (root->llink != NULL)
+ trecurse(root->llink, action, level + 1);
+ (*action)(root, postorder, level);
+ if (root->rlink != NULL)
+ trecurse(root->rlink, action, level + 1);
+ (*action)(root, endorder, level);
+ }
+}
+
+/* Walk the nodes of a tree */
+void
+twalk(vroot, action)
+ const void *vroot; /* Root of the tree to be walked */
+ void (*action)(const void *, VISIT, int);
+{
+ if (vroot != NULL && action != NULL)
+ trecurse(vroot, action, 0);
+}
OpenPOWER on IntegriCloud