1994-05-27 05:00:24 +00:00
|
|
|
/*-
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
|
|
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
|
|
|
|
#endif /* LIBC_SCCS and not lint */
|
2002-03-22 21:53:29 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
1994-05-27 05:00:24 +00:00
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
/*
|
2001-02-27 13:33:07 +00:00
|
|
|
* Convert a string to a long long integer.
|
1994-05-27 05:00:24 +00:00
|
|
|
*
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
* Assumes that the upper and lower case
|
1994-05-27 05:00:24 +00:00
|
|
|
* alphabets and digits are each contiguous.
|
|
|
|
*/
|
2001-02-27 13:33:07 +00:00
|
|
|
long long
|
|
|
|
strtoll(nptr, endptr, base)
|
1994-05-27 05:00:24 +00:00
|
|
|
const char *nptr;
|
|
|
|
char **endptr;
|
2001-11-28 00:48:11 +00:00
|
|
|
int base;
|
1994-05-27 05:00:24 +00:00
|
|
|
{
|
2001-11-28 00:48:11 +00:00
|
|
|
const char *s;
|
|
|
|
unsigned long long acc;
|
2001-12-07 16:33:47 +00:00
|
|
|
char c;
|
2001-11-28 00:48:11 +00:00
|
|
|
unsigned long long cutoff;
|
2001-12-07 16:33:47 +00:00
|
|
|
int neg, any, cutlim;
|
1994-05-27 05:00:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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++;
|
2001-12-07 16:33:47 +00:00
|
|
|
} while (isspace((unsigned char)c));
|
1994-05-27 05:00:24 +00:00
|
|
|
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;
|
2001-09-04 17:12:15 +00:00
|
|
|
acc = any = 0;
|
2001-11-28 02:35:35 +00:00
|
|
|
if (base < 2 || base > 36)
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
goto noconv;
|
1994-05-27 05:00:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
* Set 'any' if any `digits' consumed; make it negative to indicate
|
1994-05-27 05:00:24 +00:00
|
|
|
* overflow.
|
|
|
|
*/
|
2001-11-28 00:48:11 +00:00
|
|
|
cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
|
2001-02-27 13:33:07 +00:00
|
|
|
: LLONG_MAX;
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
cutlim = cutoff % base;
|
|
|
|
cutoff /= base;
|
2001-09-04 17:12:15 +00:00
|
|
|
for ( ; ; c = *s++) {
|
2001-12-07 16:33:47 +00:00
|
|
|
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;
|
1994-05-27 05:00:24 +00:00
|
|
|
else
|
|
|
|
break;
|
2001-12-07 16:33:47 +00:00
|
|
|
if (c >= base)
|
1994-05-27 05:00:24 +00:00
|
|
|
break;
|
2001-12-07 16:33:47 +00:00
|
|
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
1994-05-27 05:00:24 +00:00
|
|
|
any = -1;
|
|
|
|
else {
|
|
|
|
any = 1;
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
acc *= base;
|
2001-12-07 16:33:47 +00:00
|
|
|
acc += c;
|
1994-05-27 05:00:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (any < 0) {
|
2001-02-27 13:33:07 +00:00
|
|
|
acc = neg ? LLONG_MIN : LLONG_MAX;
|
1994-05-27 05:00:24 +00:00
|
|
|
errno = ERANGE;
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
} else if (!any) {
|
|
|
|
noconv:
|
|
|
|
errno = EINVAL;
|
1994-05-27 05:00:24 +00:00
|
|
|
} else if (neg)
|
|
|
|
acc = -acc;
|
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage.
strtol(): fix non-portable 'cutoff' calculation using the same method as
in strtoll().
Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to
make all functions looks the same.
Implement EINVAL reaction per POSIX, document it in manpage, corresponding
POSIX example quotes here:
------------------------------------------------
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of str is stored in the object pointed
to by endptr, provided that endptr is not a null pointer.
If no conversion could be performed, 0 shall be returned and errno may be
set to [EINVAL].
[EINVAL] The value of base is not supported.
Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are
returned on error and are also valid returns on success, an application
wishing to check for error situations should set errno to 0, then call
strtol( ) or strtoll ( ), then check errno.
-----------------------------------------------------
2001-09-04 16:39:11 +00:00
|
|
|
if (endptr != NULL)
|
1994-05-27 05:00:24 +00:00
|
|
|
*endptr = (char *)(any ? s - 1 : nptr);
|
|
|
|
return (acc);
|
|
|
|
}
|