atoi.c (3550B)
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 <limits.h> 14 #include <stdlib.h> 15 #include <ctype.h> 16 #include <errno.h> 17 18 #define LONG_IS_INT 1 19 20 static int hexval(char c) { 21 if (c >= '0' && c <= '9') 22 return c - '0'; 23 else if (c >= 'a' && c <= 'f') 24 return c - 'a' + 10; 25 else if (c >= 'A' && c <= 'F') 26 return c - 'A' + 10; 27 28 return 0; 29 } 30 31 int atoi(const char *num) { 32 #if !LONG_IS_INT 33 // XXX fail 34 #else 35 return atol(num); 36 #endif 37 } 38 39 unsigned int atoui(const char *num) { 40 #if !LONG_IS_INT 41 // XXX fail 42 #else 43 return atoul(num); 44 #endif 45 } 46 47 long atol(const char *num) { 48 long value = 0; 49 int neg = 0; 50 51 if (num[0] == '0' && num[1] == 'x') { 52 // hex 53 num += 2; 54 while (*num && isxdigit(*num)) 55 value = value * 16 + hexval(*num++); 56 } else { 57 // decimal 58 if (num[0] == '-') { 59 neg = 1; 60 num++; 61 } 62 while (*num && isdigit(*num)) 63 value = value * 10 + *num++ - '0'; 64 } 65 66 if (neg) 67 value = -value; 68 69 return value; 70 } 71 72 unsigned long atoul(const char *num) { 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 88 unsigned long long atoull(const char *num) { 89 unsigned long long value = 0; 90 if (num[0] == '0' && num[1] == 'x') { 91 // hex 92 num += 2; 93 while (*num && isxdigit(*num)) 94 value = value * 16 + hexval(*num++); 95 } else { 96 // decimal 97 while (*num && isdigit(*num)) 98 value = value * 10 + *num++ - '0'; 99 } 100 101 return value; 102 } 103 104 unsigned long strtoul(const char *nptr, char **endptr, int base) { 105 int neg = 0; 106 unsigned long ret = 0; 107 108 if (base < 0 || base == 1 || base > 36) { 109 errno = EINVAL; 110 return 0; 111 } 112 113 while (isspace(*nptr)) { 114 nptr++; 115 } 116 117 if (*nptr == '+') { 118 nptr++; 119 } else if (*nptr == '-') { 120 neg = 1; 121 nptr++; 122 } 123 124 if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') { 125 base = 16; 126 nptr += 2; 127 } else if (base == 0 && nptr[0] == '0') { 128 base = 8; 129 nptr++; 130 } else if (base == 0) { 131 base = 10; 132 } 133 134 for (;;) { 135 char c = *nptr; 136 int v = -1; 137 unsigned long new_ret; 138 139 if (c >= 'A' && c <= 'Z') { 140 v = c - 'A' + 10; 141 } else if (c >= 'a' && c <= 'z') { 142 v = c - 'a' + 10; 143 } else if (c >= '0' && c <= '9') { 144 v = c - '0'; 145 } 146 147 if (v < 0 || v >= base) { 148 if (endptr) { 149 *endptr = (char *) nptr; 150 } 151 break; 152 } 153 154 new_ret = ret * base; 155 if (new_ret / base != ret || 156 new_ret + v < new_ret || 157 ret == ULONG_MAX) { 158 ret = ULONG_MAX; 159 errno = ERANGE; 160 } else { 161 ret = new_ret + v; 162 } 163 164 nptr++; 165 } 166 167 if (neg && ret != ULONG_MAX) { 168 ret = -ret; 169 } 170 171 return ret; 172 }