| // Copyright 2016 The Fuchsia Authors |
| // Copyright (c) 2008 Travis Geiselbrecht |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <errno.h> |
| |
| #define LONG_IS_INT 1 |
| |
| static int hexval(char c) |
| { |
| if (c >= '0' && c <= '9') |
| return c - '0'; |
| else if (c >= 'a' && c <= 'f') |
| return c - 'a' + 10; |
| else if (c >= 'A' && c <= 'F') |
| return c - 'A' + 10; |
| |
| return 0; |
| } |
| |
| int atoi(const char *num) |
| { |
| #if !LONG_IS_INT |
| // XXX fail |
| #else |
| return atol(num); |
| #endif |
| } |
| |
| unsigned int atoui(const char *num) |
| { |
| #if !LONG_IS_INT |
| // XXX fail |
| #else |
| return atoul(num); |
| #endif |
| } |
| |
| long atol(const char *num) |
| { |
| long value = 0; |
| int neg = 0; |
| |
| if (num[0] == '0' && num[1] == 'x') { |
| // hex |
| num += 2; |
| while (*num && isxdigit(*num)) |
| value = value * 16 + hexval(*num++); |
| } else { |
| // decimal |
| if (num[0] == '-') { |
| neg = 1; |
| num++; |
| } |
| while (*num && isdigit(*num)) |
| value = value * 10 + *num++ - '0'; |
| } |
| |
| if (neg) |
| value = -value; |
| |
| return value; |
| } |
| |
| unsigned long atoul(const char *num) |
| { |
| unsigned long value = 0; |
| if (num[0] == '0' && num[1] == 'x') { |
| // hex |
| num += 2; |
| while (*num && isxdigit(*num)) |
| value = value * 16 + hexval(*num++); |
| } else { |
| // decimal |
| while (*num && isdigit(*num)) |
| value = value * 10 + *num++ - '0'; |
| } |
| |
| return value; |
| } |
| |
| unsigned long long atoull(const char *num) |
| { |
| unsigned long long value = 0; |
| if (num[0] == '0' && num[1] == 'x') { |
| // hex |
| num += 2; |
| while (*num && isxdigit(*num)) |
| value = value * 16 + hexval(*num++); |
| } else { |
| // decimal |
| while (*num && isdigit(*num)) |
| value = value * 10 + *num++ - '0'; |
| } |
| |
| return value; |
| } |
| |
| unsigned long strtoul(const char *nptr, char **endptr, int base) |
| { |
| int neg = 0; |
| unsigned long ret = 0; |
| |
| if (base < 0 || base == 1 || base > 36) { |
| errno = EINVAL; |
| return 0; |
| } |
| |
| while (isspace(*nptr)) { |
| nptr++; |
| } |
| |
| if (*nptr == '+') { |
| nptr++; |
| } else if (*nptr == '-') { |
| neg = 1; |
| nptr++; |
| } |
| |
| if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') { |
| base = 16; |
| nptr += 2; |
| } else if (base == 0 && nptr[0] == '0') { |
| base = 8; |
| nptr++; |
| } else if (base == 0) { |
| base = 10; |
| } |
| |
| for (;;) { |
| char c = *nptr; |
| int v = -1; |
| unsigned long new_ret; |
| |
| if (c >= 'A' && c <= 'Z') { |
| v = c - 'A' + 10; |
| } else if (c >= 'a' && c <= 'z') { |
| v = c - 'a' + 10; |
| } else if (c >= '0' && c <= '9') { |
| v = c - '0'; |
| } |
| |
| if (v < 0 || v >= base) { |
| if (endptr) { |
| *endptr = (char *) nptr; |
| } |
| break; |
| } |
| |
| new_ret = ret * base; |
| if (new_ret / base != ret || |
| new_ret + v < new_ret || |
| ret == ULONG_MAX) { |
| ret = ULONG_MAX; |
| errno = ERANGE; |
| } else { |
| ret = new_ret + v; |
| } |
| |
| nptr++; |
| } |
| |
| if (neg && ret != ULONG_MAX) { |
| ret = -ret; |
| } |
| |
| return ret; |
| } |