/* * An implementation of strtoull() for compilers that do not have this * function, e.g. MSVC. * See also http://www.opengroup.org/onlinepubs/000095399/functions/strtoul.html * for more information about strtoull(). */ /* * For MSVC, disable the warning "unary minus operator applied to unsigned * type, result still unsigned" */ #ifdef _MSC_VER #pragma warning (disable: 4146) #endif #define __STDC_CONSTANT_MACROS /* Enable UINT64_C in */ #define __STDC_FORMAT_MACROS /* Enable PRIu64 in */ #include #ifndef HAVE_STRTOULL #include #include #include #ifdef HAVE_INTTYPES_H #include #endif #include #include /* * UINT64_C: C99 macro for the suffix for uint64_t constants. */ #ifndef UINT64_C #ifdef _MSC_VER #define UINT64_C(c) c##ui64 #else #define UINT64_C(c) c##ULL #endif #endif /* * According to the C99 standard, the constant ULLONG_MAX must be defined in * . Define it here for pre-C99 compilers. */ #ifndef ULLONG_MAX #define ULLONG_MAX UINT64_C(0xffffffffffffffff) #endif uint64_t strtoull(const char *nptr, char **endptr, int base) { uint64_t result = 0; const char *p; const char *first_nonspace; const char *digits_start; int sign = 1; int out_of_range = 0; if (base != 0 && (base < 2 || base > 36)) goto invalid_input; p = nptr; /* * Process the initial, possibly empty, sequence of white-space characters. */ while (isspace((unsigned char) (*p))) p++; first_nonspace = p; /* * Determine sign. */ if (*p == '+') p++; else if (*p == '-') { p++; sign = -1; } if (base == 0) { /* * Determine base. */ if (*p == '0') { if ((p[1] == 'x' || p[1] == 'X')) { if (isxdigit((unsigned char)(p[2]))) { base = 16; p += 2; } else { /* * Special case: treat the string "0x" without any further * hex digits as a decimal number. */ base = 10; } } else { base = 8; p++; } } else { base = 10; } } else if (base == 16) { /* * For base 16, skip the optional "0x" / "0X" prefix. */ if (*p == '0' && (p[1] == 'x' || p[1] == 'X') && isxdigit((unsigned char)(p[2]))) { p += 2; } } digits_start = p; for (; *p; p++) { int digit; digit = ('0' <= *p && *p <= '9') ? *p - '0' : ('a' <= *p && *p <= 'z') ? (*p - 'a' + 10) : ('A' <= *p && *p <= 'Z') ? (*p - 'A' + 10) : 36; if (digit < base) { if (! out_of_range) { if (result > ULLONG_MAX / base || result * base > ULLONG_MAX - digit) { out_of_range = 1; } result = result * base + digit; } } else break; } if (p > first_nonspace && p == digits_start) goto invalid_input; if (p == first_nonspace) p = nptr; if (endptr) *endptr = (char *) p; if (out_of_range) { errno = ERANGE; return ULLONG_MAX; } return sign > 0 ? result : -result; invalid_input: errno = EINVAL; if (endptr) *endptr = (char *) nptr; return 0; } #endif /* HAVE_STRTOULL */