diff options
Diffstat (limited to 'lib/libc/stdlib')
| -rw-r--r-- | lib/libc/stdlib/Makefile.inc | 16 | ||||
| -rw-r--r-- | lib/libc/stdlib/strtoimax.c | 142 | ||||
| -rw-r--r-- | lib/libc/stdlib/strtol.3 | 62 | ||||
| -rw-r--r-- | lib/libc/stdlib/strtoul.3 | 39 | ||||
| -rw-r--r-- | lib/libc/stdlib/strtoumax.c | 120 | 
5 files changed, 337 insertions, 42 deletions
| diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index d93c20e5121c..ed88554f4d0a 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -5,12 +5,12 @@  .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/stdlib ${.CURDIR}/../libc/stdlib  MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ -	bsearch.c calloc.c div.c \ -	exit.c getenv.c getopt.c getsubopt.c hcreate.c heapsort.c \ -	imaxabs.c imaxdiv.c labs.c ldiv.c llabs.c lldiv.c \ -	malloc.c merge.c putenv.c qsort.c radixsort.c rand.c random.c \ -	reallocf.c realpath.c setenv.c strfmon.c strhash.c strtol.c \ -	strtoll.c strtoq.c strtoul.c strtoull.c strtouq.c system.c \ +	bsearch.c calloc.c div.c exit.c getenv.c getopt.c \ +	getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \ +	labs.c ldiv.c llabs.c lldiv.c malloc.c merge.c putenv.c \ +	qsort.c radixsort.c rand.c random.c reallocf.c realpath.c \ +	setenv.c strfmon.c strhash.c strtoimax.c strtol.c strtoll.c \ +	strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c system.c \  	tdelete.c tfind.c tsearch.c twalk.c  .if ${MACHINE_ARCH} == "alpha" @@ -41,8 +41,8 @@ MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.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+=strtol.3 strtoll.3 strtol.3 strtoq.3 -MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.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 realloc.3 malloc.3 reallocf.3  MLINKS+=tsearch.3 tdelete.3 tsearch.3 tfind.3 tsearch.3 twalk.3  .endif diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c new file mode 100644 index 000000000000..f8ff09bf3cb0 --- /dev/null +++ b/lib/libc/stdlib/strtoimax.c @@ -0,0 +1,142 @@ +/*- + * 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. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by the University of + *	California, Berkeley and its contributors. + * 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. + *  + * $FreeBSD$ + */ + +#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 <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> + +/* + * Convert a string to a intmax_t integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +intmax_t +strtoimax(nptr, endptr, base) +	const char *nptr; +	char **endptr; +	int base; +{ +	const char *s; +	uintmax_t acc; +	unsigned 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(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')) { +		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 (isxdigit(c)) +			c = digittoint(c); +		else if (isascii(c) && isalpha(c)) +			c -= isupper(c) ? 'A' - 10 : '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 index d01d8ee28c61..c5eb2c85728d 100644 --- a/lib/libc/stdlib/strtol.3 +++ b/lib/libc/stdlib/strtol.3 @@ -40,8 +40,8 @@  .Dt STRTOL 3  .Os  .Sh NAME -.Nm strtol , strtoll , strtoq -.Nd "convert a string value to a long, long long, or quad_t integer" +.Nm strtol , strtoll , strtoimax , strtoq +.Nd "convert a string value to a long, long long, intmax_t or quad_t integer"  .Sh LIBRARY  .Lb libc  .Sh SYNOPSIS @@ -51,6 +51,9 @@  .Fn strtol "const char *nptr" "char **endptr" "int base"  .Ft long long  .Fn strtoll "const char *nptr" "char **endptr" "int base" +.In inttypes.h +.Ft intmax_t +.Fn strtoimax "const char *nptr" "char **endptr" "int base"  .In sys/types.h  .In stdlib.h  .In limits.h @@ -74,6 +77,14 @@ to a  .Em long long  value.  The +.Fn strtoimax +function +converts the string in +.Fa nptr +to an +.Em intmax_t +value. +The  .Fn strtoq  function  converts the string in @@ -107,7 +118,11 @@ is taken as 10 (decimal) unless the next character is  in which case it is taken as 8 (octal).  .Pp  The remainder of the string is converted to a -.Em long +.Em long , +.Em long long , +.Em intmax_t +or +.Em quad_t  value in the obvious manner,  stopping at the first character which is not a valid digit  in the given base. @@ -143,9 +158,11 @@ is  on return, the entire string was valid.)  .Sh RETURN VALUES  The -.Fn strtol +.Fn strtol , +.Fn strtoll , +.Fn strtoimax  or -.Fn strtoll +.Fn strtoq  function  returns the result of the conversion,  unless the value would underflow or overflow. @@ -154,26 +171,19 @@ the global variable  .Va errno  is set to  .Er EINVAL . -If an underflow occurs, -.Fn strtol -returns -.Dv LONG_MIN . -If an overflow occurs, -.Fn strtol -returns -.Dv LONG_MAX . -If an underflow occurs, -.Fn strtoll -returns -.Dv LLONG_MIN . -If an overflow occurs, -.Fn strtoll -returns -.Dv LLONG_MAX . -In all cases, +If an overflow or underflow occurs,  .Va errno  is set to -.Er ERANGE . +.Er ERANGE +and the function return value is clamped according +to the following table. +.Bl -column -offset indent ".Fn strtoimax" ".Sy overflow" ".Sy underflow" +.It Sy Function Ta Sy overflow Ta Sy underflow +.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 @@ -198,8 +208,10 @@ conforms to  .St -isoC .  The  .Fn strtoll -function -conforms to +and +.Fn strtoimax +functions +conform to  .St -isoC-99 .  The  .Bx diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3 index ff60016d0f44..00be953a55d7 100644 --- a/lib/libc/stdlib/strtoul.3 +++ b/lib/libc/stdlib/strtoul.3 @@ -40,8 +40,8 @@  .Dt STRTOUL 3  .Os  .Sh NAME -.Nm strtoul , strtoull , strtouq -.Nd "convert a string to an unsigned long, unsigned long long, or uquad_t integer" +.Nm strtoul , strtoull , strtoumax , strtouq +.Nd "convert a string to an unsigned long, unsigned long long, uintmax_t, or uquad_t integer"  .Sh LIBRARY  .Lb libc  .Sh SYNOPSIS @@ -51,6 +51,9 @@  .Fn strtoul "const char *nptr" "char **endptr" "int base"  .Ft unsigned long long  .Fn strtoull "const char *nptr" "char **endptr" "int base" +.In inttypes.h +.Ft uintmax_t +.Fn strtoumax "const char *nptr" "char **endptr" "int base"  .In sys/types.h  .In stdlib.h  .In limits.h @@ -74,6 +77,14 @@ to an  .Em unsigned long long  value.  The +.Fn strtoumax +function +converts the string in +.Fa nptr +to an +.Em uintmax_t +value. +The  .Fn strtouq  function  converts the string in @@ -144,9 +155,11 @@ is  on return, the entire string was valid.)  .Sh RETURN VALUES  The -.Fn strtoul +.Fn strtoul , +.Fn strtoull , +.Fn strtoumax  or -.Fn strtoull +.Fn strtouq  function  returns either the result of the conversion  or, if there was a leading minus sign, @@ -155,10 +168,16 @@ unless the original (non-negated) value would overflow;  in the latter case,  .Fn strtoul  returns -.Dv ULONG_MAX -and +.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 @@ -189,10 +208,12 @@ conforms to  .St -isoC .  The  .Fn strtoull -function -conforms to +and +.Fn strtoumax +functions +conform to  .St -isoC-99 .  The  .Bx -.Fn strtoq +.Fn strtouq  function is deprecated. diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c new file mode 100644 index 000000000000..ea592459b4b4 --- /dev/null +++ b/lib/libc/stdlib/strtoumax.c @@ -0,0 +1,120 @@ +/*- + * 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. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by the University of + *	California, Berkeley and its contributors. + * 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. + * + * $FreeBSD$ + */ + +#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 <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(nptr, endptr, base) +	const char *nptr; +	char **endptr; +	int base; +{ +	const char *s; +	uintmax_t acc; +	unsigned 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(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')) { +		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 (isxdigit(c)) +			c = digittoint(c); +		else if (isascii(c) && isalpha(c)) +			c -= isupper(c) ? 'A' - 10 : '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); +} | 
