123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * Copyright (C) 2000 Manuel Novoa III
- *
- * Notes:
- *
- * The primary objective of this implementation was minimal size.
- *
- * Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
- *
- * There are a couple of compile-time options below.
- *
- */
- /*****************************************************************************/
- /* OPTIONS */
- /*****************************************************************************/
- /* Set if we want errno set appropriately. */
- /* NOTE: Implies _STRTO_ENDPTR below */
- #define _STRTO_ERRNO 0
- /* Set if we want support for the endptr arg. */
- /* Implied by _STRTO_ERRNO. */
- #define _STRTO_ENDPTR 1
- /*****************************************************************************/
- /* Don't change anything that follows. */
- /*****************************************************************************/
- #if _STRTO_ERRNO
- #undef _STRTO_ENDPTR
- #define _STRTO_ENDPTR 1
- #endif
- /*****************************************************************************/
- /* Are there actually any machines where this might fail? */
- #if 'A' > 'a'
- #error ordering assumption violated : 'A' > 'a'
- #endif
- #include <stdlib.h>
- #define __USE_GNU
- #include <limits.h>
- #include <ctype.h>
- #if _STRTO_ERRNO
- #include <errno.h>
- #endif
- unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag);
- #if L_strto_ll
- /*
- * This is the main work fuction which handles both strtol (uflag = 0) and
- * strtoul (uflag = 1).
- */
- unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag)
- {
- unsigned long long number = 0;
- unsigned long long cutoff;
- char *pos = (char *) str;
- #if _STRTO_ENDPTR
- char *fail_char = (char *) str;
- #endif
- int digit, cutoff_digit;
- int negative;
- while (isspace(*pos)) { /* skip leading whitespace */
- ++pos;
- }
- /* handle optional sign */
- negative = 0;
- switch(*pos) {
- case '-': negative = 1; /* fall through to increment pos */
- case '+': ++pos;
- }
- if ((base == 16) && (*pos == '0')) { /* handle option prefix */
- ++pos;
- #if _STRTO_ENDPTR
- fail_char = pos;
- #endif
- if ((*pos == 'x') || (*pos == 'X')) {
- ++pos;
- }
- }
-
- if (base == 0) { /* dynamic base */
- base = 10; /* default is 10 */
- if (*pos == '0') {
- ++pos;
- base -= 2; /* now base is 8 (or 16) */
- #if _STRTO_ENDPTR
- fail_char = pos;
- #endif
- if ((*pos == 'x') || (*pos == 'X')) {
- base += 8; /* base is 16 */
- ++pos;
- }
- }
- }
- if ((base < 2) || (base > 36)) { /* illegal base */
- goto DONE;
- }
- cutoff_digit = ULONG_LONG_MAX % base;
- cutoff = ULONG_LONG_MAX / base;
- while (1) {
- digit = 40;
- if ((*pos >= '0') && (*pos <= '9')) {
- digit = (*pos - '0');
- } else if (*pos >= 'a') {
- digit = (*pos - 'a' + 10);
- } else if (*pos >= 'A') {
- digit = (*pos - 'A' + 10);
- } else break;
- if (digit >= base) {
- break;
- }
- ++pos;
- #if _STRTO_ENDPTR
- fail_char = pos;
- #endif
- /* adjust number, with overflow check */
- if ((number > cutoff)
- || ((number == cutoff) && (digit > cutoff_digit))) {
- number = ULONG_LONG_MAX;
- if (uflag) {
- negative = 0; /* since unsigned returns ULONG_LONG_MAX */
- }
- #if _STRTO_ERRNO
- __set_errno(ERANGE);
- #endif
- } else {
- number = number * base + digit;
- }
- }
- DONE:
- #if _STRTO_ENDPTR
- if (endptr) {
- *endptr = fail_char;
- }
- #endif
- if (negative) {
- if (!uflag && (number > ((unsigned long long)(-(1+LONG_LONG_MIN)))+1)) {
- #if _STRTO_ERRNO
- __set_errno(ERANGE);
- #endif
- return (unsigned long long) LONG_LONG_MIN;
- }
- return (unsigned long long)(-((long long)number));
- } else {
- if (!uflag && (number > (unsigned long long) LONG_LONG_MAX)) {
- #if _STRTO_ERRNO
- __set_errno(ERANGE);
- #endif
- return LONG_LONG_MAX;
- }
- return number;
- }
- }
- #endif
- #if L_strtoull
- unsigned long long strtoull(const char *str, char **endptr, int base)
- {
- return _strto_ll(str, endptr, base, 1);
- }
- #endif
- #if L_strtoll
- long long strtoll(const char *str, char **endptr, int base)
- {
- return _strto_ll(str, endptr, base, 0);
- }
- #endif
- #ifdef L_atoll
- long long atoll(const char *str)
- {
- return(_strto_ll((str),(char**)0,10,0));
- }
- #endif
|