blob: ec72b09e09fdfaf10a7857d8937ba67c02b90f9f [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 Hughesbf03c012020-02-05 11:38:29 -080030#include <ctype.h>
Elliott Hughes1921dce2017-12-19 10:27:27 -080031#include <errno.h>
32#include <inttypes.h>
33#include <limits.h>
34#include <stdlib.h>
Elliott Hughes1f462de2022-08-05 22:51:05 +000035#include <wchar.h>
Elliott Hughes1921dce2017-12-19 10:27:27 -080036
Elliott Hughes1f462de2022-08-05 22:51:05 +000037template <typename T, T Min, T Max, typename CharT>
38T StrToI(const CharT* nptr, CharT** endptr, int base) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080039 // Ensure that base is between 2 and 36 inclusive, or the special value of 0.
40 if (base < 0 || base == 1 || base > 36) {
Elliott Hughes1f462de2022-08-05 22:51:05 +000041 if (endptr != nullptr) *endptr = const_cast<CharT*>(nptr);
Elliott Hughes1921dce2017-12-19 10:27:27 -080042 errno = EINVAL;
43 return 0;
44 }
45
46 // Skip white space and pick up leading +/- sign if any.
47 // If base is 0, allow 0x for hex and 0 for octal, else
48 // assume decimal; if base is already 16, allow 0x.
Elliott Hughes1f462de2022-08-05 22:51:05 +000049 const CharT* s = nptr;
Elliott Hughes1921dce2017-12-19 10:27:27 -080050 int c;
51 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -080052 c = *s++;
Elliott Hughesbf03c012020-02-05 11:38:29 -080053 } while (isspace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -080054 int neg;
55 if (c == '-') {
56 neg = 1;
57 c = *s++;
58 } else {
59 neg = 0;
60 if (c == '+') c = *s++;
61 }
Elliott Hughesbf03c012020-02-05 11:38:29 -080062 if ((base == 0 || base == 16) && c == '0' && (*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 }
Elliott Hughes1f462de2022-08-05 22:51:05 +000067 if ((base == 0 || base == 2) && c == '0' && (*s == 'b' || *s == 'B') && isdigit(s[1])) {
68 c = s[1];
69 s += 2;
70 base = 2;
71 }
Elliott Hughes1921dce2017-12-19 10:27:27 -080072 if (base == 0) base = (c == '0') ? 8 : 10;
73
Elliott Hughescb239bd2017-12-20 17:37:11 -080074 // We always work in the negative space because the most negative value has a
75 // larger magnitude than the most positive value.
76 T cutoff = Min / base;
77 int cutlim = -(Min % base);
78 // Non-zero if any digits consumed; negative to indicate overflow/underflow.
Elliott Hughes1921dce2017-12-19 10:27:27 -080079 int any = 0;
80 T acc = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -080081 for (; ; c = *s++) {
Elliott Hughesbf03c012020-02-05 11:38:29 -080082 if (isdigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080083 c -= '0';
Elliott Hughesbf03c012020-02-05 11:38:29 -080084 } else if (isalpha(c)) {
85 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -080086 } else {
87 break;
88 }
89 if (c >= base) break;
90 if (any < 0) continue;
Elliott Hughescb239bd2017-12-20 17:37:11 -080091 if (acc < cutoff || (acc == cutoff && c > cutlim)) {
92 any = -1;
93 acc = Min;
94 errno = ERANGE;
Elliott Hughes1921dce2017-12-19 10:27:27 -080095 } else {
Elliott Hughescb239bd2017-12-20 17:37:11 -080096 any = 1;
97 acc *= base;
98 acc -= c;
Elliott Hughes1921dce2017-12-19 10:27:27 -080099 }
100 }
Elliott Hughes1f462de2022-08-05 22:51:05 +0000101 if (endptr != nullptr) *endptr = const_cast<CharT*>(any ? s - 1 : nptr);
Elliott Hughescb239bd2017-12-20 17:37:11 -0800102 if (!neg) {
103 if (acc == Min) {
104 errno = ERANGE;
105 acc = Max;
106 } else {
107 acc = -acc;
108 }
109 }
Elliott Hughes1921dce2017-12-19 10:27:27 -0800110 return acc;
111}
112
Elliott Hughes1f462de2022-08-05 22:51:05 +0000113template <typename T, T Max, typename CharT>
114T StrToU(const CharT* nptr, CharT** endptr, int base) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800115 if (base < 0 || base == 1 || base > 36) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000116 if (endptr != nullptr) *endptr = const_cast<CharT*>(nptr);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800117 errno = EINVAL;
118 return 0;
119 }
120
Elliott Hughes1f462de2022-08-05 22:51:05 +0000121 const CharT* s = nptr;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800122 int c;
123 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -0800124 c = *s++;
Elliott Hughesbf03c012020-02-05 11:38:29 -0800125 } while (isspace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -0800126 int neg;
127 if (c == '-') {
128 neg = 1;
129 c = *s++;
130 } else {
131 neg = 0;
132 if (c == '+') c = *s++;
133 }
Elliott Hughesbf03c012020-02-05 11:38:29 -0800134 if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800135 c = s[1];
136 s += 2;
137 base = 16;
138 }
Elliott Hughes1f462de2022-08-05 22:51:05 +0000139 if ((base == 0 || base == 2) && c == '0' && (*s == 'b' || *s == 'B') && isdigit(s[1])) {
140 c = s[1];
141 s += 2;
142 base = 2;
143 }
Elliott Hughes1921dce2017-12-19 10:27:27 -0800144 if (base == 0) base = (c == '0') ? 8 : 10;
145
146 T cutoff = Max / static_cast<T>(base);
147 int cutlim = Max % static_cast<T>(base);
148 T acc = 0;
149 int any = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800150 for (; ; c = *s++) {
Elliott Hughesbf03c012020-02-05 11:38:29 -0800151 if (isdigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800152 c -= '0';
Elliott Hughesbf03c012020-02-05 11:38:29 -0800153 } else if (isalpha(c)) {
154 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800155 } else {
156 break;
157 }
158 if (c >= base) break;
159 if (any < 0) continue;
160 if (acc > cutoff || (acc == cutoff && c > cutlim)) {
161 any = -1;
162 acc = Max;
163 errno = ERANGE;
164 } else {
165 any = 1;
Elliott Hughescb239bd2017-12-20 17:37:11 -0800166 acc *= base;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800167 acc += c;
168 }
169 }
170 if (neg && any > 0) acc = -acc;
Elliott Hughes1f462de2022-08-05 22:51:05 +0000171 if (endptr != nullptr) *endptr = const_cast<CharT*>(any ? s - 1 : nptr);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800172 return acc;
173}
174
175int atoi(const char* s) {
176 return strtol(s, nullptr, 10);
177}
178
179long atol(const char* s) {
180 return strtol(s, nullptr, 10);
181}
182
183long long atoll(const char* s) {
184 return strtoll(s, nullptr, 10);
185}
186
187intmax_t strtoimax(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000188 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX, char>(s, end, base);
189}
190
191intmax_t wcstoimax(const wchar_t* s, wchar_t** end, int base) {
192 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800193}
194
195long strtol(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000196 return StrToI<long, LONG_MIN, LONG_MAX, char>(s, end, base);
197}
198
199long wcstol(const wchar_t* s, wchar_t** end, int base) {
200 return StrToI<long, LONG_MIN, LONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800201}
202
203long long strtoll(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000204 return StrToI<long long, LLONG_MIN, LLONG_MAX, char>(s, end, base);
205}
206
207long long wcstoll(const wchar_t* s, wchar_t** end, int base) {
208 return StrToI<long long, LLONG_MIN, LLONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800209}
210
211// Public API since L, but not in any header.
Elliott Hughes7cebf832020-08-12 14:25:41 -0700212__strong_alias(strtoq, strtoll);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800213
214unsigned long strtoul(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000215 return StrToU<unsigned long, ULONG_MAX, char>(s, end, base);
216}
217
218unsigned long wcstoul(const wchar_t* s, wchar_t** end, int base) {
219 return StrToU<unsigned long, ULONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800220}
221
222unsigned long long strtoull(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000223 return StrToU<unsigned long long, ULLONG_MAX, char>(s, end, base);
224}
225
226unsigned long long wcstoull(const wchar_t* s, wchar_t** end, int base) {
227 return StrToU<unsigned long long, ULLONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800228}
229
230uintmax_t strtoumax(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000231 return StrToU<uintmax_t, UINTMAX_MAX, char>(s, end, base);
232}
233
234uintmax_t wcstoumax(const wchar_t* s, wchar_t** end, int base) {
235 return StrToU<uintmax_t, UINTMAX_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800236}
237
238// Public API since L, but not in any header.
Elliott Hughes7cebf832020-08-12 14:25:41 -0700239__strong_alias(strtouq, strtoull);