mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Simplify error handling in parse_nonnegative_int
This commit is contained in:
@ -2099,9 +2099,9 @@ inline auto find<false, char>(const char* first, const char* last, char value,
|
|||||||
|
|
||||||
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
||||||
// that the range is non-empty and the first character is a digit.
|
// that the range is non-empty and the first character is a digit.
|
||||||
template <typename Char, typename ErrorHandler>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
|
FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
|
||||||
ErrorHandler&& eh) -> int {
|
int error_value) noexcept -> int {
|
||||||
FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
|
FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
|
||||||
unsigned value = 0, prev = 0;
|
unsigned value = 0, prev = 0;
|
||||||
auto p = begin;
|
auto p = begin;
|
||||||
@ -2115,13 +2115,11 @@ FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
|
|||||||
if (num_digits <= std::numeric_limits<int>::digits10)
|
if (num_digits <= std::numeric_limits<int>::digits10)
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
// Check for overflow.
|
// Check for overflow.
|
||||||
const unsigned big = to_unsigned((std::numeric_limits<int>::max)());
|
const unsigned max = to_unsigned((std::numeric_limits<int>::max)());
|
||||||
if (num_digits == std::numeric_limits<int>::digits10 + 1 &&
|
return num_digits == std::numeric_limits<int>::digits10 + 1 &&
|
||||||
prev * 10ull + unsigned(p[-1] - '0') <= big) {
|
prev * 10ull + unsigned(p[-1] - '0') <= max
|
||||||
return static_cast<int>(value);
|
? static_cast<int>(value)
|
||||||
}
|
: error_value;
|
||||||
eh.on_error("number is too big");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses fill and alignment.
|
// Parses fill and alignment.
|
||||||
@ -2177,7 +2175,8 @@ FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
|||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
if (c != '0')
|
if (c != '0')
|
||||||
index = parse_nonnegative_int(begin, end, handler);
|
index =
|
||||||
|
parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
|
||||||
else
|
else
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end || (*begin != '}' && *begin != ':'))
|
if (begin == end || (*begin != '}' && *begin != ':'))
|
||||||
@ -2226,7 +2225,11 @@ FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
|
|||||||
|
|
||||||
FMT_ASSERT(begin != end, "");
|
FMT_ASSERT(begin != end, "");
|
||||||
if ('0' <= *begin && *begin <= '9') {
|
if ('0' <= *begin && *begin <= '9') {
|
||||||
handler.on_width(parse_nonnegative_int(begin, end, handler));
|
int width = parse_nonnegative_int(begin, end, -1);
|
||||||
|
if (width != -1)
|
||||||
|
handler.on_width(width);
|
||||||
|
else
|
||||||
|
handler.on_error("number is too big");
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
|
if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
|
||||||
@ -2257,7 +2260,11 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
|||||||
++begin;
|
++begin;
|
||||||
auto c = begin != end ? *begin : Char();
|
auto c = begin != end ? *begin : Char();
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
handler.on_precision(parse_nonnegative_int(begin, end, handler));
|
auto precision = parse_nonnegative_int(begin, end, -1);
|
||||||
|
if (precision != -1)
|
||||||
|
handler.on_precision(precision);
|
||||||
|
else
|
||||||
|
handler.on_error("number is too big");
|
||||||
} else if (c == '{') {
|
} else if (c == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin != end)
|
if (begin != end)
|
||||||
|
@ -334,16 +334,16 @@ int parse_header(const Char*& it, const Char* end,
|
|||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
// Parse an argument index (if followed by '$') or a width possibly
|
// Parse an argument index (if followed by '$') or a width possibly
|
||||||
// preceded with '0' flag(s).
|
// preceded with '0' flag(s).
|
||||||
detail::error_handler eh;
|
int value = parse_nonnegative_int(it, end, -1);
|
||||||
int value = parse_nonnegative_int(it, end, eh);
|
|
||||||
if (it != end && *it == '$') { // value is an argument index
|
if (it != end && *it == '$') { // value is an argument index
|
||||||
++it;
|
++it;
|
||||||
arg_index = value;
|
arg_index = value != -1 ? value : max_value<int>();
|
||||||
} else {
|
} else {
|
||||||
if (c == '0') specs.fill[0] = '0';
|
if (c == '0') specs.fill[0] = '0';
|
||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
// Nonzero value means that we parsed width and don't need to
|
// Nonzero value means that we parsed width and don't need to
|
||||||
// parse it or flags again, so return now.
|
// parse it or flags again, so return now.
|
||||||
|
if (value == -1) FMT_THROW(format_error("number is too big"));
|
||||||
specs.width = value;
|
specs.width = value;
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@ -353,8 +353,8 @@ int parse_header(const Char*& it, const Char* end,
|
|||||||
// Parse width.
|
// Parse width.
|
||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (*it >= '0' && *it <= '9') {
|
if (*it >= '0' && *it <= '9') {
|
||||||
detail::error_handler eh;
|
specs.width = parse_nonnegative_int(it, end, -1);
|
||||||
specs.width = parse_nonnegative_int(it, end, eh);
|
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.width = static_cast<int>(visit_format_arg(
|
specs.width = static_cast<int>(visit_format_arg(
|
||||||
@ -412,8 +412,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
++it;
|
++it;
|
||||||
c = it != end ? *it : 0;
|
c = it != end ? *it : 0;
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
detail::error_handler eh;
|
specs.precision = parse_nonnegative_int(it, end, 0);
|
||||||
specs.precision = parse_nonnegative_int(it, end, eh);
|
|
||||||
} else if (c == '*') {
|
} else if (c == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.precision = static_cast<int>(
|
specs.precision = static_cast<int>(
|
||||||
|
@ -78,15 +78,11 @@ TEST(util_test, increment) {
|
|||||||
TEST(util_test, parse_nonnegative_int) {
|
TEST(util_test, parse_nonnegative_int) {
|
||||||
auto s = fmt::string_view("10000000000");
|
auto s = fmt::string_view("10000000000");
|
||||||
auto begin = s.begin(), end = s.end();
|
auto begin = s.begin(), end = s.end();
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_EQ(fmt::detail::parse_nonnegative_int(begin, end, -1), -1);
|
||||||
parse_nonnegative_int(begin, end, fmt::detail::error_handler()),
|
|
||||||
fmt::format_error, "number is too big");
|
|
||||||
s = "2147483649";
|
s = "2147483649";
|
||||||
begin = s.begin();
|
begin = s.begin();
|
||||||
end = s.end();
|
end = s.end();
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_EQ(fmt::detail::parse_nonnegative_int(begin, end, -1), -1);
|
||||||
parse_nonnegative_int(begin, end, fmt::detail::error_handler()),
|
|
||||||
fmt::format_error, "number is too big");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(util_test, utf8_to_utf16) {
|
TEST(util_test, utf8_to_utf16) {
|
||||||
@ -416,10 +412,10 @@ TEST(format_test, arg_errors) {
|
|||||||
|
|
||||||
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
||||||
"number is too big");
|
"invalid format string");
|
||||||
safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
|
safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N> struct test_format {
|
template <int N> struct test_format {
|
||||||
@ -747,16 +743,16 @@ TEST(format_test, runtime_width) {
|
|||||||
safe_sprintf(format_str, "{0:{%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:{%u", UINT_MAX);
|
||||||
increment(format_str + 4);
|
increment(format_str + 4);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"invalid format string");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
format_str[size + 1] = '}';
|
format_str[size + 1] = '}';
|
||||||
format_str[size + 2] = 0;
|
format_str[size + 2] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{"), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime("{0:{"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
@ -924,16 +920,16 @@ TEST(format_test, runtime_precision) {
|
|||||||
safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
|
||||||
increment(format_str + 5);
|
increment(format_str + 5);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"invalid format string");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
format_str[size + 1] = '}';
|
format_str[size + 1] = '}';
|
||||||
format_str[size + 2] = 0;
|
format_str[size + 2] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{"), 0), format_error,
|
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
@ -2029,7 +2025,7 @@ TEST(format_test, format_string_errors) {
|
|||||||
"compile-time checks for named arguments require C++20 support",
|
"compile-time checks for named arguments require C++20 support",
|
||||||
int);
|
int);
|
||||||
# endif
|
# endif
|
||||||
EXPECT_ERROR_NOARGS("{10000000000}", "number is too big");
|
EXPECT_ERROR_NOARGS("{10000000000}", "argument not found");
|
||||||
EXPECT_ERROR_NOARGS("{0x}", "invalid format string");
|
EXPECT_ERROR_NOARGS("{0x}", "invalid format string");
|
||||||
EXPECT_ERROR_NOARGS("{-}", "invalid format string");
|
EXPECT_ERROR_NOARGS("{-}", "invalid format string");
|
||||||
EXPECT_ERROR("{:{0x}}", "invalid format string", int);
|
EXPECT_ERROR("{:{0x}}", "invalid format string", int);
|
||||||
|
@ -86,9 +86,9 @@ TEST(printf_test, automatic_arg_indexing) {
|
|||||||
|
|
||||||
TEST(printf_test, number_is_too_big_in_arg_index) {
|
TEST(printf_test, number_is_too_big_in_arg_index) {
|
||||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$", big_num)), format_error,
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$", big_num)), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num)), format_error,
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num)), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(printf_test, switch_arg_indexing) {
|
TEST(printf_test, switch_arg_indexing) {
|
||||||
@ -102,7 +102,7 @@ TEST(printf_test, switch_arg_indexing) {
|
|||||||
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", big_num), 1, 2), format_error,
|
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", big_num), 1, 2), format_error,
|
||||||
"number is too big");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ TEST(printf_test, invalid_arg_index) {
|
|||||||
|
|
||||||
EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error, "argument not found");
|
EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error, "argument not found");
|
||||||
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num), 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num), 42), format_error,
|
||||||
"number is too big");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(printf_test, default_align_right) {
|
TEST(printf_test, default_align_right) {
|
||||||
|
Reference in New Issue
Block a user