1// Copyright 2016 The Fuchsia Authors 2// Copyright (c) 2008 Travis Geiselbrecht 3// 4// Use of this source code is governed by a MIT-style 5// license that can be found in the LICENSE file or at 6// https://opensource.org/licenses/MIT 7 8 9#include <stdlib.h> 10#include <ctype.h> 11#include <errno.h> 12 13#define LONG_IS_INT 1 14 15static int hexval(char c) 16{ 17 if (c >= '0' && c <= '9') 18 return c - '0'; 19 else if (c >= 'a' && c <= 'f') 20 return c - 'a' + 10; 21 else if (c >= 'A' && c <= 'F') 22 return c - 'A' + 10; 23 24 return 0; 25} 26 27int atoi(const char *num) 28{ 29#if !LONG_IS_INT 30 // XXX fail 31#else 32 return atol(num); 33#endif 34} 35 36unsigned int atoui(const char *num) 37{ 38#if !LONG_IS_INT 39 // XXX fail 40#else 41 return atoul(num); 42#endif 43} 44 45long atol(const char *num) 46{ 47 long value = 0; 48 int neg = 0; 49 50 if (num[0] == '0' && num[1] == 'x') { 51 // hex 52 num += 2; 53 while (*num && isxdigit(*num)) 54 value = value * 16 + hexval(*num++); 55 } else { 56 // decimal 57 if (num[0] == '-') { 58 neg = 1; 59 num++; 60 } 61 while (*num && isdigit(*num)) 62 value = value * 10 + *num++ - '0'; 63 } 64 65 if (neg) 66 value = -value; 67 68 return value; 69} 70 71unsigned long atoul(const char *num) 72{ 73 unsigned long value = 0; 74 if (num[0] == '0' && num[1] == 'x') { 75 // hex 76 num += 2; 77 while (*num && isxdigit(*num)) 78 value = value * 16 + hexval(*num++); 79 } else { 80 // decimal 81 while (*num && isdigit(*num)) 82 value = value * 10 + *num++ - '0'; 83 } 84 85 return value; 86} 87 88unsigned long long atoull(const char *num) 89{ 90 unsigned long long value = 0; 91 if (num[0] == '0' && num[1] == 'x') { 92 // hex 93 num += 2; 94 while (*num && isxdigit(*num)) 95 value = value * 16 + hexval(*num++); 96 } else { 97 // decimal 98 while (*num && isdigit(*num)) 99 value = value * 10 + *num++ - '0'; 100 } 101 102 return value; 103} 104 105unsigned long strtoul(const char *nptr, char **endptr, int base) 106{ 107 int neg = 0; 108 unsigned long ret = 0; 109 110 if (base < 0 || base == 1 || base > 36) { 111 errno = EINVAL; 112 return 0; 113 } 114 115 while (isspace(*nptr)) { 116 nptr++; 117 } 118 119 if (*nptr == '+') { 120 nptr++; 121 } else if (*nptr == '-') { 122 neg = 1; 123 nptr++; 124 } 125 126 if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') { 127 base = 16; 128 nptr += 2; 129 } else if (base == 0 && nptr[0] == '0') { 130 base = 8; 131 nptr++; 132 } else if (base == 0) { 133 base = 10; 134 } 135 136 for (;;) { 137 char c = *nptr; 138 int v = -1; 139 unsigned long new_ret; 140 141 if (c >= 'A' && c <= 'Z') { 142 v = c - 'A' + 10; 143 } else if (c >= 'a' && c <= 'z') { 144 v = c - 'a' + 10; 145 } else if (c >= '0' && c <= '9') { 146 v = c - '0'; 147 } 148 149 if (v < 0 || v >= base) { 150 if (endptr) { 151 *endptr = (char *) nptr; 152 } 153 break; 154 } 155 156 new_ret = ret * base; 157 if (new_ret / base != ret || 158 new_ret + v < new_ret || 159 ret == ULONG_MAX) { 160 ret = ULONG_MAX; 161 errno = ERANGE; 162 } else { 163 ret = new_ret + v; 164 } 165 166 nptr++; 167 } 168 169 if (neg && ret != ULONG_MAX) { 170 ret = -ret; 171 } 172 173 return ret; 174} 175