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)19 static 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)30 int 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)38 unsigned 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)46 long 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)79 unsigned 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)95 unsigned 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)111 unsigned 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