diff options
Diffstat (limited to 'lib/libc/stdlib')
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); +} |