blob: 63ac102b5b2e729e836760863a98593c2c934c11 [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>
35
36template <typename T, T Min, T Max> T StrToI(const char* nptr, char** endptr, int base) {
37 // Ensure that base is between 2 and 36 inclusive, or the special value of 0.
38 if (base < 0 || base == 1 || base > 36) {
39 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
40 errno = EINVAL;
41 return 0;
42 }
43
44 // Skip white space and pick up leading +/- sign if any.
45 // If base is 0, allow 0x for hex and 0 for octal, else
46 // assume decimal; if base is already 16, allow 0x.
47 const char* s = nptr;
48 int c;
49 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -080050 c = *s++;
Elliott Hughesbf03c012020-02-05 11:38:29 -080051 } while (isspace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -080052 int neg;
53 if (c == '-') {
54 neg = 1;
55 c = *s++;
56 } else {
57 neg = 0;
58 if (c == '+') c = *s++;
59 }
Elliott Hughesbf03c012020-02-05 11:38:29 -080060 if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080061 c = s[1];
62 s += 2;
63 base = 16;
64 }
65 if (base == 0) base = (c == '0') ? 8 : 10;
66
Elliott Hughescb239bd2017-12-20 17:37:11 -080067 // We always work in the negative space because the most negative value has a
68 // larger magnitude than the most positive value.
69 T cutoff = Min / base;
70 int cutlim = -(Min % base);
71 // Non-zero if any digits consumed; negative to indicate overflow/underflow.
Elliott Hughes1921dce2017-12-19 10:27:27 -080072 int any = 0;
73 T acc = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -080074 for (; ; c = *s++) {
Elliott Hughesbf03c012020-02-05 11:38:29 -080075 if (isdigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080076 c -= '0';
Elliott Hughesbf03c012020-02-05 11:38:29 -080077 } else if (isalpha(c)) {
78 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -080079 } else {
80 break;
81 }
82 if (c >= base) break;
83 if (any < 0) continue;
Elliott Hughescb239bd2017-12-20 17:37:11 -080084 if (acc < cutoff || (acc == cutoff && c > cutlim)) {
85 any = -1;
86 acc = Min;
87 errno = ERANGE;
Elliott Hughes1921dce2017-12-19 10:27:27 -080088 } else {
Elliott Hughescb239bd2017-12-20 17:37:11 -080089 any = 1;
90 acc *= base;
91 acc -= c;
Elliott Hughes1921dce2017-12-19 10:27:27 -080092 }
93 }
94 if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
Elliott Hughescb239bd2017-12-20 17:37:11 -080095 if (!neg) {
96 if (acc == Min) {
97 errno = ERANGE;
98 acc = Max;
99 } else {
100 acc = -acc;
101 }
102 }
Elliott Hughes1921dce2017-12-19 10:27:27 -0800103 return acc;
104}
105
106template <typename T, T Max> T StrToU(const char* nptr, char** endptr, int base) {
107 if (base < 0 || base == 1 || base > 36) {
108 if (endptr != nullptr) *endptr = const_cast<char*>(nptr);
109 errno = EINVAL;
110 return 0;
111 }
112
113 const char* s = nptr;
114 int c;
115 do {
Elliott Hughes1133fec2017-12-19 16:30:55 -0800116 c = *s++;
Elliott Hughesbf03c012020-02-05 11:38:29 -0800117 } while (isspace(c));
Elliott Hughes1921dce2017-12-19 10:27:27 -0800118 int neg;
119 if (c == '-') {
120 neg = 1;
121 c = *s++;
122 } else {
123 neg = 0;
124 if (c == '+') c = *s++;
125 }
Elliott Hughesbf03c012020-02-05 11:38:29 -0800126 if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') && isxdigit(s[1])) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800127 c = s[1];
128 s += 2;
129 base = 16;
130 }
131 if (base == 0) base = (c == '0') ? 8 : 10;
132
133 T cutoff = Max / static_cast<T>(base);
134 int cutlim = Max % static_cast<T>(base);
135 T acc = 0;
136 int any = 0;
Elliott Hughes1133fec2017-12-19 16:30:55 -0800137 for (; ; c = *s++) {
Elliott Hughesbf03c012020-02-05 11:38:29 -0800138 if (isdigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -0800139 c -= '0';
Elliott Hughesbf03c012020-02-05 11:38:29 -0800140 } else if (isalpha(c)) {
141 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800142 } else {
143 break;
144 }
145 if (c >= base) break;
146 if (any < 0) continue;
147 if (acc > cutoff || (acc == cutoff && c > cutlim)) {
148 any = -1;
149 acc = Max;
150 errno = ERANGE;
151 } else {
152 any = 1;
Elliott Hughescb239bd2017-12-20 17:37:11 -0800153 acc *= base;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800154 acc += c;
155 }
156 }
157 if (neg && any > 0) acc = -acc;
158 if (endptr != nullptr) *endptr = const_cast<char*>(any ? s - 1 : nptr);
159 return acc;
160}
161
162int atoi(const char* s) {
163 return strtol(s, nullptr, 10);
164}
165
166long atol(const char* s) {
167 return strtol(s, nullptr, 10);
168}
169
170long long atoll(const char* s) {
171 return strtoll(s, nullptr, 10);
172}
173
174intmax_t strtoimax(const char* s, char** end, int base) {
175 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX>(s, end, base);
176}
177
178long strtol(const char* s, char** end, int base) {
179 return StrToI<long, LONG_MIN, LONG_MAX>(s, end, base);
180}
181
182long long strtoll(const char* s, char** end, int base) {
183 return StrToI<long long, LLONG_MIN, LLONG_MAX>(s, end, base);
184}
185
186// Public API since L, but not in any header.
187extern "C" long long strtoq(const char* s, char** end, int base) {
188 return strtoll(s, end, base);
189}
190
191unsigned long strtoul(const char* s, char** end, int base) {
192 return StrToU<unsigned long, ULONG_MAX>(s, end, base);
193}
194
195unsigned long long strtoull(const char* s, char** end, int base) {
196 return StrToU<unsigned long long, ULLONG_MAX>(s, end, base);
197}
198
199uintmax_t strtoumax(const char* s, char** end, int base) {
200 return StrToU<uintmax_t, UINTMAX_MAX>(s, end, base);
201}
202
203// Public API since L, but not in any header.
204extern "C" unsigned long long strtouq(const char* s, char** end, int base) {
205 return strtoull(s, end, base);
206}