Impliment the ISO-C99 strto[u]ll()

and rewrite strto[u]q() in terms of it.
This commit is contained in:
David E. O'Brien 2001-02-27 13:33:07 +00:00
parent 1b0dabf0c0
commit 4c0440cb86
8 changed files with 115 additions and 175 deletions

View File

@ -104,8 +104,12 @@ void *realloc __P((void *, size_t));
void srand __P((unsigned));
double strtod __P((const char *, char **));
long strtol __P((const char *, char **, int));
long long
strtoll __P((const char *, char **, int));
unsigned long
strtoul __P((const char *, char **, int));
unsigned long long
strtoull __P((const char *, char **, int));
int system __P((const char *));
int mblen __P((const char *, size_t));

View File

@ -7,8 +7,9 @@
MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c bsearch.c calloc.c div.c \
exit.c getenv.c getopt.c getsubopt.c heapsort.c labs.c ldiv.c \
malloc.c merge.c putenv.c qsort.c radixsort.c rand.c random.c \
reallocf.c realpath.c setenv.c strhash.c strtol.c strtoq.c strtoul.c \
strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
reallocf.c realpath.c setenv.c strhash.c strtol.c strtoll.c strtoq.c \
strtoul.c strtoull.c strtouq.c system.c tdelete.c tfind.c tsearch.c \
twalk.c
.if ${MACHINE_ARCH} == "alpha"
# XXX Temporary until the assumption that a long is 32-bits is resolved
@ -33,7 +34,7 @@ MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3
MLINKS+=rand.3 rand_r.3 rand.3 srand.3
MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
random.3 srandomdev.3
MLINKS+=strtol.3 strtoq.3
MLINKS+=strtoul.3 strtouq.3
MLINKS+=strtol.3 strtoll.3 strtol.3 strtoq.3
MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.3
MLINKS+=malloc.3 calloc.3 malloc.3 free.3 malloc.3 realloc.3 malloc.3 reallocf.3
.endif

View File

@ -40,8 +40,8 @@
.Dt STRTOL 3
.Os
.Sh NAME
.Nm strtol , strtoq
.Nd convert string value to a long or quad_t integer
.Nm strtol , strtoll , strtoq
.Nd convert string value to a long , long long , or quad_t integer
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@ -49,6 +49,8 @@
.Fd #include <limits.h>
.Ft long
.Fn strtol "const char *nptr" "char **endptr" "int base"
.Ft long long
.Fn strtoll "const char *nptr" "char **endptr" "int base"
.Fd #include <sys/types.h>
.Fd #include <stdlib.h>
.Fd #include <limits.h>
@ -64,6 +66,14 @@ to a
.Em long
value.
The
.Fn strtoll
function
converts the string in
.Fa nptr
to a
.Em long long
value.
The
.Fn strtoq
function
converts the string in
@ -145,7 +155,20 @@ If an overflow occurs,
.Fn strtol
returns
.Dv LONG_MAX .
In both cases,
The
.Fn strtoll
function
returns the result of the conversion,
unless the value would underflow or overflow.
If an underflow occurs,
.Fn strtoll
returns
.Dv LLONG_MIN .
If an overflow occurs,
.Fn strtoll
returns
.Dv LLONG_MAX .
In all cases,
.Va errno
is set to
.Er ERANGE .
@ -166,5 +189,13 @@ The
function
conforms to
.St -isoC .
The
.Fn strtoll
function
conforms to
.St -isoC-99 .
The BSD
.Fn strtoq
function is deprecated.
.Sh BUGS
Ignores the current locale.

View File

@ -35,6 +35,11 @@
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif
#include <sys/types.h>
#include <limits.h>
@ -43,21 +48,21 @@ static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#include <stdlib.h>
/*
* Convert a string to a quad integer.
* Convert a string to a long long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
quad_t
strtoq(nptr, endptr, base)
long long
strtoll(nptr, endptr, base)
const char *nptr;
char **endptr;
register int base;
{
register const char *s;
register u_quad_t acc;
register unsigned long long acc;
register unsigned char c;
register u_quad_t qbase, cutoff;
register unsigned long long qbase, cutoff;
register int neg, any, cutlim;
/*
@ -105,7 +110,8 @@ strtoq(nptr, endptr, base)
* overflow.
*/
qbase = (unsigned)base;
cutoff = neg ? (u_quad_t)-(QUAD_MIN + QUAD_MAX) + QUAD_MAX : QUAD_MAX;
cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
: LLONG_MAX;
cutlim = cutoff % qbase;
cutoff /= qbase;
for (acc = 0, any = 0;; c = *s++) {
@ -128,7 +134,7 @@ strtoq(nptr, endptr, base)
}
}
if (any < 0) {
acc = neg ? QUAD_MIN : QUAD_MAX;
acc = neg ? LLONG_MIN : LLONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;

View File

@ -35,11 +35,11 @@
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
/*
@ -52,87 +52,8 @@ quad_t
strtoq(nptr, endptr, base)
const char *nptr;
char **endptr;
register int base;
int base;
{
register const char *s;
register u_quad_t acc;
register unsigned char c;
register u_quad_t qbase, cutoff;
register 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;
/*
* 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.
*/
qbase = (unsigned)base;
cutoff = neg ? (u_quad_t)-(QUAD_MIN + QUAD_MAX) + QUAD_MAX : QUAD_MAX;
cutlim = cutoff % qbase;
cutoff /= qbase;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (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 *= qbase;
acc += c;
}
}
if (any < 0) {
acc = neg ? QUAD_MIN : QUAD_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
return strtoll(nptr, endptr, base);
}

View File

@ -40,8 +40,8 @@
.Dt STRTOUL 3
.Os
.Sh NAME
.Nm strtoul , strtouq
.Nd "convert a string to an unsigned long or uquad_t integer"
.Nm strtoul , strtoull , strtouq
.Nd "convert a string to an unsigned long , unsigned long long , or uquad_t integer"
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@ -49,6 +49,8 @@
.Fd #include <limits.h>
.Ft unsigned long
.Fn strtoul "const char *nptr" "char **endptr" "int base"
.Ft unsigned long long
.Fn strtoull "const char *nptr" "char **endptr" "int base"
.Fd #include <sys/types.h>
.Fd #include <stdlib.h>
.Fd #include <limits.h>
@ -64,6 +66,14 @@ to an
.Em unsigned long
value.
The
.Fn strtoull
function
converts the string in
.Fa nptr
to an
.Em unsigned long long
value.
The
.Fn strtouq
function
converts the string in
@ -143,10 +153,21 @@ unless the original (non-negated) value would overflow;
in the latter case,
.Fn strtoul
returns
.Dv ULONG_MAX
and sets the global variable
.Dv ULONG_MAX .
The
.Fn strtoull
function
returns 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 strtoull
returns
.Dv ULLONG_MAX .
In all cases,
.Va errno
to
is set to
.Er ERANGE .
.Sh ERRORS
.Bl -tag -width Er
@ -161,5 +182,13 @@ The
function
conforms to
.St -isoC .
The
.Fn strtoull
function
conforms to
.St -isoC-99 .
The BSD
.Fn strtoq
function is deprecated.
.Sh BUGS
Ignores the current locale.

View File

@ -35,6 +35,11 @@
static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif
#include <sys/types.h>
#include <limits.h>
@ -43,21 +48,21 @@ static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#include <stdlib.h>
/*
* Convert a string to an unsigned quad integer.
* Convert a string to an unsigned long long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
u_quad_t
strtouq(nptr, endptr, base)
unsigned long long
strtoull(nptr, endptr, base)
const char *nptr;
char **endptr;
register int base;
{
register const char *s = nptr;
register u_quad_t acc;
register unsigned long long acc;
register unsigned char c;
register u_quad_t qbase, cutoff;
register unsigned long long qbase, cutoff;
register int neg, any, cutlim;
/*
@ -84,8 +89,8 @@ strtouq(nptr, endptr, base)
if (base == 0)
base = c == '0' ? 8 : 10;
qbase = (unsigned)base;
cutoff = (u_quad_t)UQUAD_MAX / qbase;
cutlim = (u_quad_t)UQUAD_MAX % qbase;
cutoff = (unsigned long long)ULLONG_MAX / qbase;
cutlim = (unsigned long long)ULLONG_MAX % qbase;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
@ -106,7 +111,7 @@ strtouq(nptr, endptr, base)
}
}
if (any < 0) {
acc = UQUAD_MAX;
acc = ULLONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;

View File

@ -35,11 +35,11 @@
static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
/*
@ -52,65 +52,8 @@ u_quad_t
strtouq(nptr, endptr, base)
const char *nptr;
char **endptr;
register int base;
int base;
{
register const char *s = nptr;
register u_quad_t acc;
register unsigned char c;
register u_quad_t qbase, cutoff;
register int neg, any, cutlim;
/*
* See strtoq 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;
qbase = (unsigned)base;
cutoff = (u_quad_t)UQUAD_MAX / qbase;
cutlim = (u_quad_t)UQUAD_MAX % qbase;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (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 *= qbase;
acc += c;
}
}
if (any < 0) {
acc = UQUAD_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
return strtoull(nptr, endptr, base);
}