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