[libc-commits] [libc] d52f0ae - [libc] Add strtol, strtoul, and strtoull
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Tue Aug 17 14:05:41 PDT 2021
Author: Michael Jones
Date: 2021-08-17T21:05:37Z
New Revision: d52f0aeca5dbde61aadbcd20e1b8cfaf15a84a65
URL: https://github.com/llvm/llvm-project/commit/d52f0aeca5dbde61aadbcd20e1b8cfaf15a84a65
DIFF: https://github.com/llvm/llvm-project/commit/d52f0aeca5dbde61aadbcd20e1b8cfaf15a84a65.diff
LOG: [libc] Add strtol, strtoul, and strtoull
Updates the internal string conversion function so that it
uses the new Limits.h added in a previous commit for max and min values,
and has a templated type. This makes implementing the other strto*
functions very simple.
Reviewed By: sivachandra
Differential Revision: https://reviews.llvm.org/D107999
Added:
libc/src/stdlib/strtol.cpp
libc/src/stdlib/strtol.h
libc/src/stdlib/strtoul.cpp
libc/src/stdlib/strtoul.h
libc/src/stdlib/strtoull.cpp
libc/src/stdlib/strtoull.h
libc/test/src/stdlib/strtol_test.cpp
libc/test/src/stdlib/strtoul_test.cpp
libc/test/src/stdlib/strtoull_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/spec.td
libc/spec/stdc.td
libc/src/__support/CMakeLists.txt
libc/src/__support/str_conv_utils.h
libc/src/stdlib/CMakeLists.txt
libc/src/stdlib/strtoll.cpp
libc/test/src/stdlib/CMakeLists.txt
libc/test/src/stdlib/strtoll_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 90346b4b3461..6e163c11c909 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -158,7 +158,10 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdlib.abs
libc.src.stdlib.labs
libc.src.stdlib.llabs
+ libc.src.stdlib.strtol
libc.src.stdlib.strtoll
+ libc.src.stdlib.strtoul
+ libc.src.stdlib.strtoull
# signal.h entrypoints
libc.src.signal.raise
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index e49c759c1f79..242303de8e3b 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -40,7 +40,9 @@ def VarArgType : Type {}
def VoidType : NamedType<"void">;
def IntType : NamedType<"int">;
def LongType : NamedType<"long">;
+def UnsignedLongType : NamedType<"unsigned long">;
def LongLongType : NamedType<"long long">;
+def UnsignedLongLongType : NamedType<"unsigned long long">;
def FloatType : NamedType<"float">;
def DoubleType : NamedType<"double">;
def LongDoubleType : NamedType<"long double">;
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index eb0ffdfe2e9d..6aa68a3e30c1 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -478,7 +478,10 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"abs", RetValSpec<IntType>, [ArgSpec<IntType>]>,
FunctionSpec<"labs", RetValSpec<LongType>, [ArgSpec<LongType>]>,
FunctionSpec<"llabs", RetValSpec<LongLongType>, [ArgSpec<LongLongType>]>,
+ FunctionSpec<"strtol", RetValSpec<LongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
FunctionSpec<"strtoll", RetValSpec<LongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
+ FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
+ FunctionSpec<"strtoull", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
FunctionSpec<"_Exit", RetValSpec<NoReturn>, [ArgSpec<IntType>]>,
]
>;
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index dce6cb871ec5..a09ca4bcee6f 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -20,6 +20,7 @@ add_header_library(
.ctype_utils
libc.include.errno
libc.src.errno.__errno_location
+ libc.utils.CPP.standalone_cpp
)
add_header_library(
diff --git a/libc/src/__support/str_conv_utils.h b/libc/src/__support/str_conv_utils.h
index 6a83fa6799a7..adde15823ef6 100644
--- a/libc/src/__support/str_conv_utils.h
+++ b/libc/src/__support/str_conv_utils.h
@@ -10,6 +10,7 @@
#define LIBC_SRC_STDLIB_STDLIB_UTILS_H
#include "src/__support/ctype_utils.h"
+#include "utils/CPP/Limits.h"
#include <errno.h>
#include <limits.h>
@@ -50,8 +51,9 @@ static inline int infer_base(const char *__restrict *__restrict src) {
// Takes a pointer to a string, a pointer to a string pointer, and the base to
// convert to. This function is used as the backend for all of the string to int
// functions.
-static inline long long strtoll(const char *__restrict src,
- char **__restrict str_end, int base) {
+template <class T>
+static inline T strtointeger(const char *__restrict src,
+ char **__restrict str_end, int base) {
unsigned long long result = 0;
if (base < 0 || base == 1 || base > 36) {
@@ -73,36 +75,56 @@ static inline long long strtoll(const char *__restrict src,
src = src + 2;
}
+ constexpr bool is_unsigned = (__llvm_libc::cpp::NumericLimits<T>::min() == 0);
+ const bool is_positive = (result_sign == '+');
+ unsigned long long constexpr NEGATIVE_MAX =
+ !is_unsigned ? static_cast<unsigned long long>(
+ __llvm_libc::cpp::NumericLimits<T>::max()) +
+ 1
+ : __llvm_libc::cpp::NumericLimits<T>::max();
unsigned long long const ABS_MAX =
- (result_sign == '+' ? LLONG_MAX
- : static_cast<unsigned long long>(LLONG_MAX) + 1);
+ (is_positive ? __llvm_libc::cpp::NumericLimits<T>::max() : NEGATIVE_MAX);
unsigned long long const ABS_MAX_DIV_BY_BASE = ABS_MAX / base;
while (isalnum(*src)) {
int cur_digit = b36_char_to_int(*src);
if (cur_digit >= base)
break;
+
+ ++src;
+
+ // If the number has already hit the maximum value for the current type then
+ // the result cannot change, but we still need to advance src to the end of
+ // the number.
+ if (result == ABS_MAX) {
+ errno = ERANGE; // NOLINT
+ continue;
+ }
+
if (result > ABS_MAX_DIV_BY_BASE) {
result = ABS_MAX;
errno = ERANGE; // NOLINT
- break;
+ } else {
+ result = result * base;
}
- result = result * base;
if (result > ABS_MAX - cur_digit) {
result = ABS_MAX;
errno = ERANGE; // NOLINT
- break;
+ } else {
+ result = result + cur_digit;
}
- result = result + cur_digit;
-
- ++src;
}
if (str_end != nullptr)
*str_end = const_cast<char *>(src);
- if (result_sign == '+')
- return result;
- else
- return -result;
+
+ if (result == ABS_MAX) {
+ if (is_positive || is_unsigned)
+ return __llvm_libc::cpp::NumericLimits<T>::max();
+ else // T is signed and there is a negative overflow
+ return __llvm_libc::cpp::NumericLimits<T>::min();
+ }
+
+ return is_positive ? static_cast<T>(result) : -static_cast<T>(result);
}
} // namespace internal
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 8457310897f5..642202dde1bd 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -51,6 +51,16 @@ add_entrypoint_object(
libc.src.__support.integer_operations
)
+add_entrypoint_object(
+ strtol
+ SRCS
+ strtol.cpp
+ HDRS
+ strtol.h
+ DEPENDS
+ libc.src.__support.str_conv_utils
+)
+
add_entrypoint_object(
strtoll
SRCS
@@ -60,3 +70,23 @@ add_entrypoint_object(
DEPENDS
libc.src.__support.str_conv_utils
)
+
+add_entrypoint_object(
+ strtoul
+ SRCS
+ strtoul.cpp
+ HDRS
+ strtoul.h
+ DEPENDS
+ libc.src.__support.str_conv_utils
+)
+
+add_entrypoint_object(
+ strtoull
+ SRCS
+ strtoull.cpp
+ HDRS
+ strtoull.h
+ DEPENDS
+ libc.src.__support.str_conv_utils
+)
diff --git a/libc/src/stdlib/strtol.cpp b/libc/src/stdlib/strtol.cpp
new file mode 100644
index 000000000000..1c744c929e28
--- /dev/null
+++ b/libc/src/stdlib/strtol.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strtol ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtol.h"
+#include "src/__support/common.h"
+#include "src/__support/str_conv_utils.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(long, strtol,
+ (const char *__restrict str, char **__restrict str_end,
+ int base)) {
+ return internal::strtointeger<long>(str, str_end, base);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdlib/strtol.h b/libc/src/stdlib/strtol.h
new file mode 100644
index 000000000000..741c4e802814
--- /dev/null
+++ b/libc/src/stdlib/strtol.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for strtol ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOL_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOL_H
+
+namespace __llvm_libc {
+
+long strtol(const char *__restrict str, char **__restrict str_end, int base);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOL_H
diff --git a/libc/src/stdlib/strtoll.cpp b/libc/src/stdlib/strtoll.cpp
index c99106d7c423..e2fc37f8bf82 100644
--- a/libc/src/stdlib/strtoll.cpp
+++ b/libc/src/stdlib/strtoll.cpp
@@ -15,7 +15,7 @@ namespace __llvm_libc {
LLVM_LIBC_FUNCTION(long long, strtoll,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::strtoll(str, str_end, base);
+ return internal::strtointeger<long long>(str, str_end, base);
}
} // namespace __llvm_libc
diff --git a/libc/src/stdlib/strtoul.cpp b/libc/src/stdlib/strtoul.cpp
new file mode 100644
index 000000000000..eab264f33347
--- /dev/null
+++ b/libc/src/stdlib/strtoul.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strtoul -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoul.h"
+#include "src/__support/common.h"
+#include "src/__support/str_conv_utils.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(unsigned long, strtoul,
+ (const char *__restrict str, char **__restrict str_end,
+ int base)) {
+ return internal::strtointeger<unsigned long>(str, str_end, base);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdlib/strtoul.h b/libc/src/stdlib/strtoul.h
new file mode 100644
index 000000000000..6aee32f48f6e
--- /dev/null
+++ b/libc/src/stdlib/strtoul.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for strtoul -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOUL_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOUL_H
+
+namespace __llvm_libc {
+
+unsigned long strtoul(const char *__restrict str, char **__restrict str_end,
+ int base);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOUL_H
diff --git a/libc/src/stdlib/strtoull.cpp b/libc/src/stdlib/strtoull.cpp
new file mode 100644
index 000000000000..bece2787ba7e
--- /dev/null
+++ b/libc/src/stdlib/strtoull.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of strtoull ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoull.h"
+#include "src/__support/common.h"
+#include "src/__support/str_conv_utils.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
+ (const char *__restrict str, char **__restrict str_end,
+ int base)) {
+ return internal::strtointeger<unsigned long long>(str, str_end, base);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdlib/strtoull.h b/libc/src/stdlib/strtoull.h
new file mode 100644
index 000000000000..b64c7be1eb97
--- /dev/null
+++ b/libc/src/stdlib/strtoull.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for strtoull ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOULL_H
+
+namespace __llvm_libc {
+
+unsigned long long strtoull(const char *__restrict str,
+ char **__restrict str_end, int base);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOULL_H
diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index d95f95b8d79e..648d85552bed 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -55,6 +55,16 @@ add_libc_unittest(
libc.src.stdlib.llabs
)
+add_libc_unittest(
+ strtol_test
+ SUITE
+ libc_stdlib_unittests
+ SRCS
+ strtol_test.cpp
+ DEPENDS
+ libc.src.stdlib.strtol
+)
+
add_libc_unittest(
strtoll_test
SUITE
@@ -63,6 +73,24 @@ add_libc_unittest(
strtoll_test.cpp
DEPENDS
libc.src.stdlib.strtoll
- libc.include.errno
- libc.test.errno_setter_matcher
+)
+
+add_libc_unittest(
+ strtoul_test
+ SUITE
+ libc_stdlib_unittests
+ SRCS
+ strtoul_test.cpp
+ DEPENDS
+ libc.src.stdlib.strtoul
+)
+
+add_libc_unittest(
+ strtoull_test
+ SUITE
+ libc_stdlib_unittests
+ SRCS
+ strtoull_test.cpp
+ DEPENDS
+ libc.src.stdlib.strtoull
)
diff --git a/libc/test/src/stdlib/strtol_test.cpp b/libc/test/src/stdlib/strtol_test.cpp
new file mode 100644
index 000000000000..14a473537b39
--- /dev/null
+++ b/libc/test/src/stdlib/strtol_test.cpp
@@ -0,0 +1,289 @@
+//===-- Unittests for strtol ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtol.h"
+
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+
+TEST(LlvmLibcStrToLTest, InvalidBase) {
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(ten, nullptr, -1), 0l);
+ ASSERT_EQ(errno, EINVAL);
+}
+
+TEST(LlvmLibcStrToLTest, CleanBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(ten, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - ten, 2l);
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(ten, nullptr, 10), 10l);
+ ASSERT_EQ(errno, 0);
+
+ const char *hundred = "100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(hundred, &str_end, 10), 100l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - hundred, 3l);
+
+ const char *negative = "-100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(negative, &str_end, 10), -100l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - negative, 4l);
+
+ const char *big_number = "123456789012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(big_number, &str_end, 10), 123456789012345l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - big_number, 15l);
+
+ const char *big_negative_number = "-123456789012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(big_negative_number, &str_end, 10),
+ -123456789012345l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - big_negative_number, 16l);
+
+ const char *too_big_number = "123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(too_big_number, &str_end, 10), LONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_number, 21l);
+
+ const char *too_big_negative_number = "-123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(too_big_negative_number, &str_end, 10),
+ LONG_MIN);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_negative_number, 22l);
+
+ const char *long_number_range_test =
+ "10000000000000000000000000000000000000000000000000";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(long_number_range_test, &str_end, 10),
+ LONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - long_number_range_test, 50l);
+}
+
+TEST(LlvmLibcStrToLTest, MessyBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *spaces_before = " 10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(spaces_before, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_before, 7l);
+
+ const char *spaces_after = "10 ";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(spaces_after, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_after, 2l);
+
+ const char *word_before = "word10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(word_before, &str_end, 10), 0l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_before, 0l);
+
+ const char *word_after = "10word";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(word_after, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_after, 2l);
+
+ const char *two_numbers = "10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(two_numbers, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_numbers, 2l);
+
+ const char *two_signs = "--10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(two_signs, &str_end, 10), 0l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_signs, 1l);
+
+ const char *sign_before = "+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(sign_before, &str_end, 10), 2l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_before, 2l);
+
+ const char *sign_after = "2+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(sign_after, &str_end, 10), 2l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_after, 1l);
+
+ const char *tab_before = "\t10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(tab_before, &str_end, 10), 10l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - tab_before, 3l);
+
+ const char *all_together = "\t -12345and+67890";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(all_together, &str_end, 10), -12345l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - all_together, 9l);
+}
+
+static char int_to_b36_char(int input) {
+ if (input < 0 || input > 36)
+ return '0';
+ if (input < 10)
+ return '0' + input;
+ return 'A' + input - 10;
+}
+
+TEST(LlvmLibcStrToLTest, DecodeInOtherBases) {
+ char small_string[4] = {'\0', '\0', '\0', '\0'};
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (long second_digit = 0; second_digit <= 36; ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (long second_digit = 0; second_digit <= 36; ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ for (long third_digit = 0; third_digit <= 36; ++third_digit) {
+ small_string[2] = int_to_b36_char(third_digit);
+
+ if (first_digit < base && second_digit < base && third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ third_digit + (second_digit * base) +
+ (first_digit * base * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ // if the base is 16 there is a special case for the prefix 0X.
+ // The number is treated as a one digit hexadecimal.
+ if (base == 16 && first_digit == 0 && second_digit == 33) {
+ if (third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ third_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(small_string, nullptr, base), 0l);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+TEST(LlvmLibcStrToLTest, CleanBaseSixteenDecode) {
+ char *str_end = nullptr;
+
+ const char *no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(no_prefix, &str_end, 16), 0x123abcl);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - no_prefix, 6l);
+
+ const char *yes_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(yes_prefix, &str_end, 16), 0x456defl);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - yes_prefix, 8l);
+}
+
+TEST(LlvmLibcStrToLTest, AutomaticBaseSelection) {
+ char *str_end = nullptr;
+
+ const char *base_ten = "12345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(base_ten, &str_end, 0), 12345l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_ten, 5l);
+
+ const char *base_sixteen_no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(base_sixteen_no_prefix, &str_end, 0), 123l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);
+
+ const char *base_sixteen_with_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(base_sixteen_with_prefix, &str_end, 0),
+ 0x456defl);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);
+
+ const char *base_eight_with_prefix = "012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtol(base_eight_with_prefix, &str_end, 0), 012345l);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
+}
diff --git a/libc/test/src/stdlib/strtoll_test.cpp b/libc/test/src/stdlib/strtoll_test.cpp
index 437d42f5bab8..ca5467182b7d 100644
--- a/libc/test/src/stdlib/strtoll_test.cpp
+++ b/libc/test/src/stdlib/strtoll_test.cpp
@@ -57,18 +57,49 @@ TEST(LlvmLibcStrToLLTest, CleanBaseTenDecode) {
ASSERT_EQ(errno, 0);
EXPECT_EQ(str_end - big_negative_number, 16l);
+ const char *long_long_max_number = "9223372036854775807";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoll(long_long_max_number, &str_end, 10),
+ 9223372036854775807ll);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - long_long_max_number, 19l);
+
+ const char *long_long_min_number = "-9223372036854775808";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoll(long_long_min_number, &str_end, 10),
+ -9223372036854775807ll - 1ll);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - long_long_min_number, 20l);
+
const char *too_big_number = "123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(too_big_number, &str_end, 10), LLONG_MAX);
ASSERT_EQ(errno, ERANGE);
- EXPECT_EQ(str_end - too_big_number, 19l);
+ EXPECT_EQ(str_end - too_big_number, 21l);
const char *too_big_negative_number = "-123456789012345678901";
errno = 0;
ASSERT_EQ(__llvm_libc::strtoll(too_big_negative_number, &str_end, 10),
LLONG_MIN);
ASSERT_EQ(errno, ERANGE);
- EXPECT_EQ(str_end - too_big_negative_number, 20l);
+ EXPECT_EQ(str_end - too_big_negative_number, 22l);
+
+ const char *long_number_range_test =
+ "10000000000000000000000000000000000000000000000000";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoll(long_number_range_test, &str_end, 10),
+ LLONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - long_number_range_test, 50l);
+
+ const char *long_long_max_number_with_numbers_after =
+ "9223372036854775807123";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoll(long_long_max_number_with_numbers_after,
+ &str_end, 10),
+ LLONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - long_long_max_number_with_numbers_after, 22l);
}
TEST(LlvmLibcStrToLLTest, MessyBaseTenDecode) {
@@ -145,7 +176,7 @@ static char int_to_b36_char(int input) {
TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
char small_string[4] = {'\0', '\0', '\0', '\0'};
- for (int base = 2; base <= 36; ++base) {
+ for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
if (first_digit < base) {
@@ -161,7 +192,7 @@ TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
}
}
- for (int base = 2; base <= 36; ++base) {
+ for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long long second_digit = 0; second_digit <= 36; ++second_digit) {
@@ -185,7 +216,7 @@ TEST(LlvmLibcStrToLLTest, DecodeInOtherBases) {
}
}
- for (int base = 2; base <= 36; ++base) {
+ for (unsigned int base = 2; base <= 36; ++base) {
for (long long first_digit = 0; first_digit <= 36; ++first_digit) {
small_string[0] = int_to_b36_char(first_digit);
for (long long second_digit = 0; second_digit <= 36; ++second_digit) {
diff --git a/libc/test/src/stdlib/strtoul_test.cpp b/libc/test/src/stdlib/strtoul_test.cpp
new file mode 100644
index 000000000000..cff208618f50
--- /dev/null
+++ b/libc/test/src/stdlib/strtoul_test.cpp
@@ -0,0 +1,284 @@
+//===-- Unittests for strtoul ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoul.h"
+
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+
+TEST(LlvmLibcStrToULTest, InvalidBase) {
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, -1), 0ul);
+ ASSERT_EQ(errno, EINVAL);
+}
+
+TEST(LlvmLibcStrToULTest, CleanBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(ten, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - ten, 2l);
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(ten, nullptr, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+
+ const char *hundred = "100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(hundred, &str_end, 10), 100ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - hundred, 3l);
+
+ const char *negative = "-100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(negative, &str_end, 10), -(100ul));
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - negative, 4l);
+
+ const char *big_number = "123456789012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(big_number, &str_end, 10), 123456789012345ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - big_number, 15l);
+
+ const char *too_big_number = "123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(too_big_number, &str_end, 10), ULONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_number, 21l);
+
+ const char *too_big_negative_number = "-123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(too_big_negative_number, &str_end, 10),
+ ULONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_negative_number, 22l);
+
+ const char *long_number_range_test =
+ "10000000000000000000000000000000000000000000000000";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(long_number_range_test, &str_end, 10),
+ ULONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - long_number_range_test, 50l);
+}
+
+TEST(LlvmLibcStrToULTest, MessyBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *spaces_before = " 10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(spaces_before, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_before, 7l);
+
+ const char *spaces_after = "10 ";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(spaces_after, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_after, 2l);
+
+ const char *word_before = "word10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(word_before, &str_end, 10), 0ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_before, 0l);
+
+ const char *word_after = "10word";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(word_after, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_after, 2l);
+
+ const char *two_numbers = "10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(two_numbers, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_numbers, 2l);
+
+ const char *two_signs = "--10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(two_signs, &str_end, 10), 0ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_signs, 1l);
+
+ const char *sign_before = "+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(sign_before, &str_end, 10), 2ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_before, 2l);
+
+ const char *sign_after = "2+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(sign_after, &str_end, 10), 2ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_after, 1l);
+
+ const char *tab_before = "\t10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(tab_before, &str_end, 10), 10ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - tab_before, 3l);
+
+ const char *all_together = "\t -12345and+67890";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(all_together, &str_end, 10), -(12345ul));
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - all_together, 9l);
+}
+
+static char int_to_b36_char(int input) {
+ if (input < 0 || input > 36)
+ return '0';
+ if (input < 10)
+ return '0' + input;
+ return 'A' + input - 10;
+}
+
+TEST(LlvmLibcStrToULTest, DecodeInOtherBases) {
+ char small_string[4] = {'\0', '\0', '\0', '\0'};
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (unsigned long second_digit = 0; second_digit <= 36; ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ for (unsigned long third_digit = 0; third_digit <= 36; ++third_digit) {
+ small_string[2] = int_to_b36_char(third_digit);
+
+ if (first_digit < base && second_digit < base && third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ third_digit + (second_digit * base) +
+ (first_digit * base * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ // if the base is 16 there is a special case for the prefix 0X.
+ // The number is treated as a one digit hexadecimal.
+ if (base == 16 && first_digit == 0 && second_digit == 33) {
+ if (third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ third_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ 0ul);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(small_string, nullptr, base), 0ul);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+TEST(LlvmLibcStrToULTest, CleanBaseSixteenDecode) {
+ char *str_end = nullptr;
+
+ const char *no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(no_prefix, &str_end, 16), 0x123abcul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - no_prefix, 6l);
+
+ const char *yes_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(yes_prefix, &str_end, 16), 0x456deful);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - yes_prefix, 8l);
+}
+
+TEST(LlvmLibcStrToULTest, AutomaticBaseSelection) {
+ char *str_end = nullptr;
+
+ const char *base_ten = "12345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(base_ten, &str_end, 0), 12345ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_ten, 5l);
+
+ const char *base_sixteen_no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_no_prefix, &str_end, 0), 123ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);
+
+ const char *base_sixteen_with_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(base_sixteen_with_prefix, &str_end, 0),
+ 0x456deful);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);
+
+ const char *base_eight_with_prefix = "012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoul(base_eight_with_prefix, &str_end, 0),
+ 012345ul);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
+}
diff --git a/libc/test/src/stdlib/strtoull_test.cpp b/libc/test/src/stdlib/strtoull_test.cpp
new file mode 100644
index 000000000000..e6b52c92432a
--- /dev/null
+++ b/libc/test/src/stdlib/strtoull_test.cpp
@@ -0,0 +1,295 @@
+//===-- Unittests for strtoull --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdlib/strtoull.h"
+
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+
+TEST(LlvmLibcStrToULLTest, InvalidBase) {
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(ten, nullptr, -1), 0ull);
+ ASSERT_EQ(errno, EINVAL);
+}
+
+TEST(LlvmLibcStrToULLTest, CleanBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *ten = "10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(ten, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - ten, 2l);
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(ten, nullptr, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+
+ const char *hundred = "100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(hundred, &str_end, 10), 100ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - hundred, 3l);
+
+ const char *negative = "-100";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(negative, &str_end, 10), -(100ull));
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - negative, 4l);
+
+ const char *big_number = "123456789012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(big_number, &str_end, 10),
+ 123456789012345ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - big_number, 15l);
+
+ const char *unsigned_long_long_max_number = "18446744073709551615";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(unsigned_long_long_max_number, &str_end, 10),
+ 18446744073709551615ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - unsigned_long_long_max_number, 20l);
+
+ const char *too_big_number = "123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(too_big_number, &str_end, 10), ULLONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_number, 21l);
+
+ const char *too_big_negative_number = "-123456789012345678901";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(too_big_negative_number, &str_end, 10),
+ ULLONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - too_big_negative_number, 22l);
+
+ const char *long_number_range_test =
+ "10000000000000000000000000000000000000000000000000";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(long_number_range_test, &str_end, 10),
+ ULLONG_MAX);
+ ASSERT_EQ(errno, ERANGE);
+ EXPECT_EQ(str_end - long_number_range_test, 50l);
+}
+
+TEST(LlvmLibcStrToULLTest, MessyBaseTenDecode) {
+ char *str_end = nullptr;
+
+ const char *spaces_before = " 10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(spaces_before, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_before, 7l);
+
+ const char *spaces_after = "10 ";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(spaces_after, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - spaces_after, 2l);
+
+ const char *word_before = "word10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(word_before, &str_end, 10), 0ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_before, 0l);
+
+ const char *word_after = "10word";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(word_after, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - word_after, 2l);
+
+ const char *two_numbers = "10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(two_numbers, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_numbers, 2l);
+
+ const char *two_signs = "--10 999";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(two_signs, &str_end, 10), 0ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - two_signs, 1l);
+
+ const char *sign_before = "+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(sign_before, &str_end, 10), 2ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_before, 2l);
+
+ const char *sign_after = "2+2=4";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(sign_after, &str_end, 10), 2ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - sign_after, 1l);
+
+ const char *tab_before = "\t10";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(tab_before, &str_end, 10), 10ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - tab_before, 3l);
+
+ const char *all_together = "\t -12345and+67890";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(all_together, &str_end, 10), -(12345ull));
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - all_together, 9l);
+}
+
+static char int_to_b36_char(int input) {
+ if (input < 0 || input > 36)
+ return '0';
+ if (input < 10)
+ return '0' + input;
+ return 'A' + input - 10;
+}
+
+TEST(LlvmLibcStrToULLTest, DecodeInOtherBases) {
+ char small_string[4] = {'\0', '\0', '\0', '\0'};
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (unsigned long long second_digit = 0; second_digit <= 36;
+ ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+
+ for (unsigned int base = 2; base <= 36; ++base) {
+ for (unsigned long long first_digit = 0; first_digit <= 36; ++first_digit) {
+ small_string[0] = int_to_b36_char(first_digit);
+ for (unsigned long long second_digit = 0; second_digit <= 36;
+ ++second_digit) {
+ small_string[1] = int_to_b36_char(second_digit);
+ for (unsigned long long third_digit = 0; third_digit <= 36;
+ ++third_digit) {
+ small_string[2] = int_to_b36_char(third_digit);
+
+ if (first_digit < base && second_digit < base && third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ third_digit + (second_digit * base) +
+ (first_digit * base * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base && second_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ second_digit + (first_digit * base));
+ ASSERT_EQ(errno, 0);
+ } else if (first_digit < base) {
+ // if the base is 16 there is a special case for the prefix 0X.
+ // The number is treated as a one digit hexadecimal.
+ if (base == 16 && first_digit == 0 && second_digit == 33) {
+ if (third_digit < base) {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ third_digit);
+ ASSERT_EQ(errno, 0);
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ 0ull);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base),
+ first_digit);
+ ASSERT_EQ(errno, 0);
+ }
+ } else {
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(small_string, nullptr, base), 0ull);
+ ASSERT_EQ(errno, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+TEST(LlvmLibcStrToULLTest, CleanBaseSixteenDecode) {
+ char *str_end = nullptr;
+
+ const char *no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(no_prefix, &str_end, 16), 0x123abcull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - no_prefix, 6l);
+
+ const char *yes_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(yes_prefix, &str_end, 16), 0x456defull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - yes_prefix, 8l);
+}
+
+TEST(LlvmLibcStrToULLTest, AutomaticBaseSelection) {
+ char *str_end = nullptr;
+
+ const char *base_ten = "12345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(base_ten, &str_end, 0), 12345ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_ten, 5l);
+
+ const char *base_sixteen_no_prefix = "123abc";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(base_sixteen_no_prefix, &str_end, 0), 123ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_no_prefix, 3l);
+
+ const char *base_sixteen_with_prefix = "0x456def";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(base_sixteen_with_prefix, &str_end, 0),
+ 0x456defull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_sixteen_with_prefix, 8l);
+
+ const char *base_eight_with_prefix = "012345";
+ errno = 0;
+ ASSERT_EQ(__llvm_libc::strtoull(base_eight_with_prefix, &str_end, 0),
+ 012345ull);
+ ASSERT_EQ(errno, 0);
+ EXPECT_EQ(str_end - base_eight_with_prefix, 6l);
+}
More information about the libc-commits
mailing list