blob: def792107bf183462cb72c78b7975bbcbdef9886 [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>
Elliott Hughesca89b332023-12-12 14:05:03 -080038__attribute__((always_inline)) T StrToI(const CharT* s, CharT** end_ptr, 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 Hughesca89b332023-12-12 14:05:03 -080041 if (end_ptr != nullptr) *end_ptr = const_cast<CharT*>(s);
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.
Elliott Hughesca89b332023-12-12 14:05:03 -080047 const CharT* p = s;
Elliott Hughes1921dce2017-12-19 10:27:27 -080048 int c;
Elliott Hughesca89b332023-12-12 14:05:03 -080049 while (isspace(c = *p++)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080050 }
Elliott Hughesca89b332023-12-12 14:05:03 -080051 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;
Elliott Hughes1921dce2017-12-19 10:27:27 -080063 base = 16;
64 }
Elliott Hughesca89b332023-12-12 14:05:03 -080065 // 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;
Elliott Hughes1f462de2022-08-05 22:51:05 +000069 base = 2;
70 }
Elliott Hughesca89b332023-12-12 14:05:03 -080071 // If base is 0, allow "0" prefix for octal, otherwise base is 10.
Elliott Hughes1921dce2017-12-19 10:27:27 -080072 if (base == 0) base = (c == '0') ? 8 : 10;
73
Elliott Hughesca89b332023-12-12 14:05:03 -080074 constexpr bool is_signed = (Min != 0);
75 T acc = 0;
Elliott Hughescb239bd2017-12-20 17:37:11 -080076 // Non-zero if any digits consumed; negative to indicate overflow/underflow.
Elliott Hughes1921dce2017-12-19 10:27:27 -080077 int any = 0;
Elliott Hughesca89b332023-12-12 14:05:03 -080078 for (;; c = *p++) {
Elliott Hughesbf03c012020-02-05 11:38:29 -080079 if (isdigit(c)) {
Elliott Hughes1921dce2017-12-19 10:27:27 -080080 c -= '0';
Elliott Hughesbf03c012020-02-05 11:38:29 -080081 } else if (isalpha(c)) {
Elliott Hughesca89b332023-12-12 14:05:03 -080082 c = 10 + (_tolower(c) - 'a');
Elliott Hughes1921dce2017-12-19 10:27:27 -080083 } else {
84 break;
85 }
86 if (c >= base) break;
87 if (any < 0) continue;
Elliott Hughesca89b332023-12-12 14:05:03 -080088 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 }
Elliott Hughes1921dce2017-12-19 10:27:27 -080095 } else {
Elliott Hughesca89b332023-12-12 14:05:03 -080096 if (__builtin_mul_overflow(acc, base, &acc) || __builtin_add_overflow(acc, c, &acc)) {
97 any = -1;
98 continue;
99 }
Elliott Hughes1921dce2017-12-19 10:27:27 -0800100 }
Elliott Hughesca89b332023-12-12 14:05:03 -0800101 any = 1;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800102 }
103
Elliott Hughesca89b332023-12-12 14:05:03 -0800104 if (end_ptr != nullptr) *end_ptr = const_cast<CharT*>(any ? p - 1 : s);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800105
Elliott Hughesca89b332023-12-12 14:05:03 -0800106 // Detected overflow/underflow in the loop?
107 if (any == -1) {
108 errno = ERANGE;
109 return (is_signed && neg) ? Min : Max;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800110 }
Elliott Hughesca89b332023-12-12 14:05:03 -0800111
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;
Elliott Hughes1921dce2017-12-19 10:27:27 -0800120}
121
122int atoi(const char* s) {
123 return strtol(s, nullptr, 10);
124}
125
126long atol(const char* s) {
127 return strtol(s, nullptr, 10);
128}
129
130long long atoll(const char* s) {
131 return strtoll(s, nullptr, 10);
132}
133
134intmax_t strtoimax(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000135 return StrToI<intmax_t, INTMAX_MIN, INTMAX_MAX, char>(s, end, base);
136}
137
138intmax_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);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800140}
141
142long strtol(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000143 return StrToI<long, LONG_MIN, LONG_MAX, char>(s, end, base);
144}
145
146long wcstol(const wchar_t* s, wchar_t** end, int base) {
147 return StrToI<long, LONG_MIN, LONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800148}
149
150long long strtoll(const char* s, char** end, int base) {
Elliott Hughes1f462de2022-08-05 22:51:05 +0000151 return StrToI<long long, LLONG_MIN, LLONG_MAX, char>(s, end, base);
152}
153
154long 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);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800156}
157
Elliott Hughes1921dce2017-12-19 10:27:27 -0800158unsigned long strtoul(const char* s, char** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800159 return StrToI<unsigned long, 0, ULONG_MAX, char>(s, end, base);
Elliott Hughes1f462de2022-08-05 22:51:05 +0000160}
161
162unsigned long wcstoul(const wchar_t* s, wchar_t** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800163 return StrToI<unsigned long, 0, ULONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800164}
165
166unsigned long long strtoull(const char* s, char** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800167 return StrToI<unsigned long long, 0, ULLONG_MAX, char>(s, end, base);
Elliott Hughes1f462de2022-08-05 22:51:05 +0000168}
169
170unsigned long long wcstoull(const wchar_t* s, wchar_t** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800171 return StrToI<unsigned long long, 0, ULLONG_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800172}
173
174uintmax_t strtoumax(const char* s, char** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800175 return StrToI<uintmax_t, 0, UINTMAX_MAX, char>(s, end, base);
Elliott Hughes1f462de2022-08-05 22:51:05 +0000176}
177
178uintmax_t wcstoumax(const wchar_t* s, wchar_t** end, int base) {
Elliott Hughesca89b332023-12-12 14:05:03 -0800179 return StrToI<uintmax_t, 0, UINTMAX_MAX, wchar_t>(s, end, base);
Elliott Hughes1921dce2017-12-19 10:27:27 -0800180}