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 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 
atoul(const char * num)71 unsigned long atoul(const char *num) {
72     unsigned long value = 0;
73     if (num[0] == '0' && num[1] == 'x') {
74         // hex
75         num += 2;
76         while (*num && isxdigit(*num))
77             value = value * 16 + hexval(*num++);
78     } else {
79         // decimal
80         while (*num && isdigit(*num))
81             value = value * 10 + *num++  - '0';
82     }
83 
84     return value;
85 }
86 
atoull(const char * num)87 unsigned long long atoull(const char *num) {
88     unsigned long long value = 0;
89     if (num[0] == '0' && num[1] == 'x') {
90         // hex
91         num += 2;
92         while (*num && isxdigit(*num))
93             value = value * 16 + hexval(*num++);
94     } else {
95         // decimal
96         while (*num && isdigit(*num))
97             value = value * 10 + *num++  - '0';
98     }
99 
100     return value;
101 }
102 
strtoul(const char * nptr,char ** endptr,int base)103 unsigned long strtoul(const char *nptr, char **endptr, int base) {
104     int neg = 0;
105     unsigned long ret = 0;
106 
107     if (base < 0 || base == 1 || base > 36) {
108         errno = EINVAL;
109         return 0;
110     }
111 
112     while (isspace(*nptr)) {
113         nptr++;
114     }
115 
116     if (*nptr == '+') {
117         nptr++;
118     } else if (*nptr == '-') {
119         neg = 1;
120         nptr++;
121     }
122 
123     if ((base == 0 || base == 16) && nptr[0] == '0' && nptr[1] == 'x') {
124         base = 16;
125         nptr += 2;
126     } else if (base == 0 && nptr[0] == '0') {
127         base = 8;
128         nptr++;
129     } else if (base == 0) {
130         base = 10;
131     }
132 
133     for (;;) {
134         char c = *nptr;
135         int v = -1;
136         unsigned long new_ret;
137 
138         if (c >= 'A' && c <= 'Z') {
139             v = c - 'A' + 10;
140         } else if (c >= 'a' && c <= 'z') {
141             v = c - 'a' + 10;
142         } else if (c >= '0' && c <= '9') {
143             v = c - '0';
144         }
145 
146         if (v < 0 || v >= base) {
147             if (endptr) {
148                 *endptr = (char *) nptr;
149             }
150             break;
151         }
152 
153         new_ret = ret * base;
154         if (new_ret / base != ret ||
155                 new_ret + v < new_ret ||
156                 ret == ULONG_MAX) {
157             ret = ULONG_MAX;
158             errno = ERANGE;
159         } else {
160             ret = new_ret + v;
161         }
162 
163         nptr++;
164     }
165 
166     if (neg && ret != ULONG_MAX) {
167         ret = -ret;
168     }
169 
170     return ret;
171 }
172