blob: f4c8c5f1e020e07d293d7208d019362988b3753c [file] [log] [blame]
Elliott Hughes1921dce2017-12-19 10:27:27 -08001/*
2 * Copyright (c) 1992 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Elliott Hughes1921dce2017-12-19 10:27:27 -080030#include <errno.h>
31#include <inttypes.h>
32#include <limits.h>
33#include <stdlib.h>
34
Elliott Hughes1133fec2017-12-19 16:30:55 -080035#include <private/bionic_ctype.h>
36
Elliott Hughes1921dce2017-12-19 10:27:27 -080037template <typename T, T Min, T Max> T StrToI(const char* nptr, char** endptr, int base) {
38 // Ensure that base is between 2 and 36 inclusive, or the special value of 0.
39 if (base < 0 || base == 1 || base > 36) {
40 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
41 errno = EINVAL;
42 return 0;
43 }
44
45 // Skip white space and pick up leading +/- sign if any.
46 // If base is 0, allow 0x for hex and 0 for octal, else
47 // assume decimal; if base is already 16, allow 0x.
48 const char* s = nptr;
49 int c;
50 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -080051 c = *s++;
52 } while (IsSpace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -080053 int neg;
54 if (c == '-') {
55 neg = 1;
56 c = *s++;
57 } else {
58 neg = 0;
59 if (c == '+') c = *s++;
60 }
61 if ((base == 0 || base == 16) && c == '0' &&
Elliott Hughes1133fec2017-12-19 16:30:55 -080062 (*s == 'x' || *s == 'X') && IsXDigit(s[1])) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080063 c = s[1];
64 s += 2;
65 base = 16;
66 }
67 if (base == 0) base = (c == '0') ? 8 : 10;
68
69 // Compute the cutoff value between legal numbers and illegal
70 // numbers. That is the largest legal value, divided by the
71 // base. An input number that is greater than this value, if
72 // followed by a legal input character, is too big. One that
73 // is equal to this value may be valid or not; the limit
74 // between valid and invalid numbers is then based on the last
75 // digit. For instance, if the range for intmax_t is
76 // [-9223372036854775808..9223372036854775807] and the input base
77 // is 10, cutoff will be set to 922337203685477580 and cutlim to
78 // either 7 (neg==0) or 8 (neg==1), meaning that if we have
79 // accumulated a value > 922337203685477580, or equal but the
80 // next digit is > 7 (or 8), the number is too big, and we will
81 // return a range error.
82 T cutoff = neg ? Min : Max;
83 int cutlim = cutoff % base;
84 cutoff /= base;
85 if (neg) {
86 if (cutlim > 0) {
87 cutlim -= base;
88 cutoff += 1;
89 }
90 cutlim = -cutlim;
91 }
92
93 // Set `any` if any digits consumed; make it negative to indicate overflow.
94 int any = 0;
95 T acc = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -080096 for (; ; c = *s++) {
97 if (IsDigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080098 c -= '0';
Elliott Hughes1133fec2017-12-19 16:30:55 -080099 } else if (IsAlpha(c)) {
100 c -= IsUpper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800101 } else {
102 break;
103 }
104 if (c >= base) break;
105 if (any < 0) continue;
106 if (neg) {
107 if (acc < cutoff || (acc == cutoff && c > cutlim)) {
108 any = -1;
109 acc = Min;
110 errno = ERANGE;
111 } else {
112 any = 1;
113 acc *= base;
114 acc -= c;
115 }
116 } else {
117 if (acc > cutoff || (acc == cutoff && c > cutlim)) {
118 any = -1;
119 acc = Max;
120 errno = ERANGE;
121 } else {
122 any = 1;
123 acc *= base;
124 acc += c;
125 }
126 }
127 }
128 if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
129 return acc;
130}
131
132template <typename T, T Max> T StrToU(const char* nptr, char** endptr, int base) {
133 if (base < 0 || base == 1 || base > 36) {
134 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
135 errno = EINVAL;
136 return 0;
137 }
138
139 const char* s = nptr;
140 int c;
141 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -0800142 c = *s++;
143 } while (IsSpace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -0800144 int neg;
145 if (c == '-') {
146 neg = 1;
147 c = *s++;
148 } else {
149 neg = 0;
150 if (c == '+') c = *s++;
151 }
152 if ((base == 0 || base == 16) && c == '0' &&
Elliott Hughes1133fec2017-12-19 16:30:55 -0800153 (*s == 'x' || *s == 'X') && IsXDigit(s[1])) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800154 c = s[1];
155 s += 2;
156 base = 16;
157 }
158 if (base == 0) base = (c == '0') ? 8 : 10;
159
160 T cutoff = Max / static_cast<T>(base);
161 int cutlim = Max % static_cast<T>(base);
162 T acc = 0;
163 int any = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800164 for (; ; c = *s++) {
165 if (IsDigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800166 c -= '0';
Elliott Hughes1133fec2017-12-19 16:30:55 -0800167 } else if (IsAlpha(c)) {
168 c -= IsUpper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800169 } else {
170 break;
171 }
172 if (c >= base) break;
173 if (any < 0) continue;
174 if (acc > cutoff || (acc == cutoff && c > cutlim)) {
175 any = -1;
176 acc = Max;
177 errno = ERANGE;
178 } else {
179 any = 1;
180 acc *= static_cast<T>(base);
181 acc += c;
182 }
183 }
184 if (neg && any > 0) acc = -acc;
185 if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
186 return acc;
187}
188
189int atoi(const char* s) {
190 return strtol(s, nullptr, 10);
191}
192
193long atol(const char* s) {
194 return strtol(s, nullptr, 10);
195}
196
197long long atoll(const char* s) {
198 return strtoll(s, nullptr, 10);
199}
200
201intmax_t strtoimax(const char* s, char** end, int base) {
202 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX>(s, end, base);
203}
204
205long strtol(const char* s, char** end, int base) {
206 return StrToI<long, LONG_MIN, LONG_MAX>(s, end, base);
207}
208
209long long strtoll(const char* s, char** end, int base) {
210 return StrToI<long long, LLONG_MIN, LLONG_MAX>(s, end, base);
211}
212
213// Public API since L, but not in any header.
214extern "C" long long strtoq(const char* s, char** end, int base) {
215 return strtoll(s, end, base);
216}
217
218unsigned long strtoul(const char* s, char** end, int base) {
219 return StrToU<unsigned long, ULONG_MAX>(s, end, base);
220}
221
222unsigned long long strtoull(const char* s, char** end, int base) {
223 return StrToU<unsigned long long, ULLONG_MAX>(s, end, base);
224}
225
226uintmax_t strtoumax(const char* s, char** end, int base) {
227 return StrToU<uintmax_t, UINTMAX_MAX>(s, end, base);
228}
229
230// Public API since L, but not in any header.
231extern "C" unsigned long long strtouq(const char* s, char** end, int base) {
232 return strtoull(s, end, base);
233}