1 /*
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
30 #include <ctype.h>
31 #include <errno.h>
32 #include <inttypes.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <wchar.h>
36
37 template <typename T, T Min, T Max, typename CharT>
StrToI(const CharT * s,CharT ** end_ptr,int base)38 __attribute__((always_inline)) T StrToI(const CharT* s, CharT** end_ptr, int base) {
39 // Ensure that base is between 2 and 36 inclusive, or the special value of 0.
40 if (base < 0 || base == 1 || base > 36) {
41 if (end_ptr != nullptr) *end_ptr = const_cast<CharT*>(s);
42 errno = EINVAL;
43 return 0;
44 }
45
46 // Skip white space and pick up leading +/- sign if any.
47 const CharT* p = s;
48 int c;
49 while (isspace(c = *p++)) {
50 }
51 bool neg = false;
52 if (c == '-') {
53 neg = true;
54 c = *p++;
55 } else if (c == '+') {
56 c = *p++;
57 }
58
59 // If base is 0 or 16, allow "0x" prefix for hex.
60 if ((base == 0 || base == 16) && c == '0' && (*p == 'x' || *p == 'X') && isxdigit(p[1])) {
61 c = p[1];
62 p += 2;
63 base = 16;
64 }
65 // If base is 0 or 2, allow "0b" prefix for binary.
66 if ((base == 0 || base == 2) && c == '0' && (*p == 'b' || *p == 'B') && isdigit(p[1])) {
67 c = p[1];
68 p += 2;
69 base = 2;
70 }
71 // If base is 0, allow "0" prefix for octal, otherwise base is 10.
72 if (base == 0) base = (c == '0') ? 8 : 10;
73
74 constexpr bool is_signed = (Min != 0);
75 T acc = 0;
76 // Non-zero if any digits consumed; negative to indicate overflow/underflow.
77 int any = 0;
78 for (;; c = *p++) {
79 if (isdigit(c)) {
80 c -= '0';
81 } else if (isalpha(c)) {
82 c = 10 + (_tolower(c) - 'a');
83 } else {
84 break;
85 }
86 if (c >= base) break;
87 if (any < 0) continue;
88 if (is_signed) {
89 // We work in the negative space because the most negative value has a
90 // larger magnitude than the most positive value.
91 if (__builtin_mul_overflow(acc, base, &acc) || __builtin_sub_overflow(acc, c, &acc)) {
92 any = -1;
93 continue;
94 }
95 } else {
96 if (__builtin_mul_overflow(acc, base, &acc) || __builtin_add_overflow(acc, c, &acc)) {
97 any = -1;
98 continue;
99 }
100 }
101 any = 1;
102 }
103
104 if (end_ptr != nullptr) *end_ptr = const_cast<CharT*>(any ? p - 1 : s);
105
106 // Detected overflow/underflow in the loop?
107 if (any == -1) {
108 errno = ERANGE;
109 return (is_signed && neg) ? Min : Max;
110 }
111
112 // Will we overflow by trying to negate the most negative value?
113 if (any > 0 && is_signed && !neg && acc == Min) {
114 errno = ERANGE;
115 return Max;
116 }
117
118 if (is_signed) return neg ? acc : -acc;
119 return neg ? -acc : acc;
120 }
121
atoi(const char * s)122 int atoi(const char* s) {
123 return strtol(s, nullptr, 10);
124 }
125
atol(const char * s)126 long atol(const char* s) {
127 return strtol(s, nullptr, 10);
128 }
129
atoll(const char * s)130 long long atoll(const char* s) {
131 return strtoll(s, nullptr, 10);
132 }
133
strtoimax(const char * s,char ** end,int base)134 intmax_t strtoimax(const char* s, char** end, int base) {
135 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX, char>(s, end, base);
136 }
137
wcstoimax(const wchar_t * s,wchar_t ** end,int base)138 intmax_t wcstoimax(const wchar_t* s, wchar_t** end, int base) {
139 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX, wchar_t>(s, end, base);
140 }
141
strtol(const char * s,char ** end,int base)142 long strtol(const char* s, char** end, int base) {
143 return StrToI<long, LONG_MIN, LONG_MAX, char>(s, end, base);
144 }
145
wcstol(const wchar_t * s,wchar_t ** end,int base)146 long wcstol(const wchar_t* s, wchar_t** end, int base) {
147 return StrToI<long, LONG_MIN, LONG_MAX, wchar_t>(s, end, base);
148 }
149
strtoll(const char * s,char ** end,int base)150 long long strtoll(const char* s, char** end, int base) {
151 return StrToI<long long, LLONG_MIN, LLONG_MAX, char>(s, end, base);
152 }
153
wcstoll(const wchar_t * s,wchar_t ** end,int base)154 long long wcstoll(const wchar_t* s, wchar_t** end, int base) {
155 return StrToI<long long, LLONG_MIN, LLONG_MAX, wchar_t>(s, end, base);
156 }
157
strtoul(const char * s,char ** end,int base)158 unsigned long strtoul(const char* s, char** end, int base) {
159 return StrToI<unsigned long, 0, ULONG_MAX, char>(s, end, base);
160 }
161
wcstoul(const wchar_t * s,wchar_t ** end,int base)162 unsigned long wcstoul(const wchar_t* s, wchar_t** end, int base) {
163 return StrToI<unsigned long, 0, ULONG_MAX, wchar_t>(s, end, base);
164 }
165
strtoull(const char * s,char ** end,int base)166 unsigned long long strtoull(const char* s, char** end, int base) {
167 return StrToI<unsigned long long, 0, ULLONG_MAX, char>(s, end, base);
168 }
169
wcstoull(const wchar_t * s,wchar_t ** end,int base)170 unsigned long long wcstoull(const wchar_t* s, wchar_t** end, int base) {
171 return StrToI<unsigned long long, 0, ULLONG_MAX, wchar_t>(s, end, base);
172 }
173
strtoumax(const char * s,char ** end,int base)174 uintmax_t strtoumax(const char* s, char** end, int base) {
175 return StrToI<uintmax_t, 0, UINTMAX_MAX, char>(s, end, base);
176 }
177
wcstoumax(const wchar_t * s,wchar_t ** end,int base)178 uintmax_t wcstoumax(const wchar_t* s, wchar_t** end, int base) {
179 return StrToI<uintmax_t, 0, UINTMAX_MAX, wchar_t>(s, end, base);
180 }
181