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