mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Replace multiple error reporting mechanisms with report_error
This commit is contained in:
@ -683,8 +683,17 @@ enum {
|
|||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/** Throws ``format_error`` with a given message. */
|
/**
|
||||||
FMT_NORETURN FMT_API void throw_format_error(const char* message);
|
Reports a format error at compile time or, via a ``format_error`` exception,
|
||||||
|
at runtime.
|
||||||
|
*/
|
||||||
|
// This function is intentionally not constexpr to give a compile-time error.
|
||||||
|
FMT_NORETURN FMT_API void report_error(const char* message);
|
||||||
|
|
||||||
|
FMT_DEPRECATED FMT_NORETURN inline void throw_format_error(
|
||||||
|
const char* message) {
|
||||||
|
report_error(message);
|
||||||
|
}
|
||||||
|
|
||||||
/** String's character (code unit) type. */
|
/** String's character (code unit) type. */
|
||||||
template <typename S,
|
template <typename S,
|
||||||
@ -738,8 +747,7 @@ template <typename Char> class basic_format_parse_context {
|
|||||||
*/
|
*/
|
||||||
FMT_CONSTEXPR auto next_arg_id() -> int {
|
FMT_CONSTEXPR auto next_arg_id() -> int {
|
||||||
if (next_arg_id_ < 0) {
|
if (next_arg_id_ < 0) {
|
||||||
throw_format_error(
|
report_error("cannot switch from manual to automatic argument indexing");
|
||||||
"cannot switch from manual to automatic argument indexing");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int id = next_arg_id_++;
|
int id = next_arg_id_++;
|
||||||
@ -753,8 +761,7 @@ template <typename Char> class basic_format_parse_context {
|
|||||||
*/
|
*/
|
||||||
FMT_CONSTEXPR void check_arg_id(int id) {
|
FMT_CONSTEXPR void check_arg_id(int id) {
|
||||||
if (next_arg_id_ > 0) {
|
if (next_arg_id_ > 0) {
|
||||||
throw_format_error(
|
report_error("cannot switch from automatic to manual argument indexing");
|
||||||
"cannot switch from automatic to manual argument indexing");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
next_arg_id_ = -1;
|
next_arg_id_ = -1;
|
||||||
@ -787,20 +794,20 @@ class compile_parse_context : public basic_format_parse_context<Char> {
|
|||||||
|
|
||||||
FMT_CONSTEXPR auto next_arg_id() -> int {
|
FMT_CONSTEXPR auto next_arg_id() -> int {
|
||||||
int id = base::next_arg_id();
|
int id = base::next_arg_id();
|
||||||
if (id >= num_args_) throw_format_error("argument not found");
|
if (id >= num_args_) report_error("argument not found");
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void check_arg_id(int id) {
|
FMT_CONSTEXPR void check_arg_id(int id) {
|
||||||
base::check_arg_id(id);
|
base::check_arg_id(id);
|
||||||
if (id >= num_args_) throw_format_error("argument not found");
|
if (id >= num_args_) report_error("argument not found");
|
||||||
}
|
}
|
||||||
using base::check_arg_id;
|
using base::check_arg_id;
|
||||||
|
|
||||||
FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
|
FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
|
||||||
detail::ignore_unused(arg_id);
|
detail::ignore_unused(arg_id);
|
||||||
if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
|
if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
|
||||||
throw_format_error("width/precision is not integer");
|
report_error("width/precision is not integer");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1081,7 +1088,7 @@ FMT_CONSTEXPR void basic_format_parse_context<Char>::do_check_arg_id(int id) {
|
|||||||
(!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
|
(!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) {
|
||||||
using context = detail::compile_parse_context<Char>;
|
using context = detail::compile_parse_context<Char>;
|
||||||
if (id >= static_cast<context*>(this)->num_args())
|
if (id >= static_cast<context*>(this)->num_args())
|
||||||
throw_format_error("argument not found");
|
report_error("argument not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1916,9 +1923,6 @@ class context {
|
|||||||
}
|
}
|
||||||
auto args() const -> const basic_format_args<context>& { return args_; }
|
auto args() const -> const basic_format_args<context>& { return args_; }
|
||||||
|
|
||||||
// This function is intentionally not constexpr to give a compile-time error.
|
|
||||||
void on_error(const char* message) { throw_format_error(message); }
|
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the output range.
|
// Returns an iterator to the beginning of the output range.
|
||||||
FMT_CONSTEXPR auto out() -> iterator { return out_; }
|
FMT_CONSTEXPR auto out() -> iterator { return out_; }
|
||||||
|
|
||||||
@ -2215,13 +2219,13 @@ FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
|||||||
else
|
else
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end || (*begin != '}' && *begin != ':'))
|
if (begin == end || (*begin != '}' && *begin != ':'))
|
||||||
throw_format_error("invalid format string");
|
report_error("invalid format string");
|
||||||
else
|
else
|
||||||
handler.on_index(index);
|
handler.on_index(index);
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
if (!is_name_start(c)) {
|
if (!is_name_start(c)) {
|
||||||
throw_format_error("invalid format string");
|
report_error("invalid format string");
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
auto it = begin;
|
auto it = begin;
|
||||||
@ -2274,13 +2278,13 @@ FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
|||||||
if (val != -1)
|
if (val != -1)
|
||||||
value = val;
|
value = val;
|
||||||
else
|
else
|
||||||
throw_format_error("number is too big");
|
report_error("number is too big");
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
|
auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
|
||||||
if (begin != end) begin = parse_arg_id(begin, end, handler);
|
if (begin != end) begin = parse_arg_id(begin, end, handler);
|
||||||
if (begin != end && *begin == '}') return ++begin;
|
if (begin != end && *begin == '}') return ++begin;
|
||||||
throw_format_error("invalid format string");
|
report_error("invalid format string");
|
||||||
}
|
}
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
@ -2292,7 +2296,7 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
|||||||
-> const Char* {
|
-> const Char* {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
throw_format_error("invalid precision");
|
report_error("invalid precision");
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
return parse_dynamic_spec(begin, end, value, ref, ctx);
|
return parse_dynamic_spec(begin, end, value, ref, ctx);
|
||||||
@ -2319,7 +2323,7 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
state current_state = state::start;
|
state current_state = state::start;
|
||||||
FMT_CONSTEXPR void operator()(state s, bool valid = true) {
|
FMT_CONSTEXPR void operator()(state s, bool valid = true) {
|
||||||
if (current_state >= s || !valid)
|
if (current_state >= s || !valid)
|
||||||
throw_format_error("invalid format specifier");
|
report_error("invalid format specifier");
|
||||||
current_state = s;
|
current_state = s;
|
||||||
}
|
}
|
||||||
} enter_state;
|
} enter_state;
|
||||||
@ -2334,7 +2338,7 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
|
FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
|
||||||
if (!in(arg_type, set)) {
|
if (!in(arg_type, set)) {
|
||||||
if (arg_type == type::none_type) return begin;
|
if (arg_type == type::none_type) return begin;
|
||||||
throw_format_error("invalid format specifier");
|
report_error("invalid format specifier");
|
||||||
}
|
}
|
||||||
specs.type = pres_type;
|
specs.type = pres_type;
|
||||||
return begin + 1;
|
return begin + 1;
|
||||||
@ -2378,7 +2382,7 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
enter_state(state::zero);
|
enter_state(state::zero);
|
||||||
if (!is_arithmetic_type(arg_type)) {
|
if (!is_arithmetic_type(arg_type)) {
|
||||||
if (arg_type == type::none_type) return begin;
|
if (arg_type == type::none_type) return begin;
|
||||||
throw_format_error("format specifier requires numeric argument");
|
report_error("format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
if (specs.align == align::none) {
|
if (specs.align == align::none) {
|
||||||
// Ignore 0 if align is specified for compatibility with std::format.
|
// Ignore 0 if align is specified for compatibility with std::format.
|
||||||
@ -2448,8 +2452,7 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
case 'a':
|
case 'a':
|
||||||
return parse_presentation_type(pres::hexfloat, float_set);
|
return parse_presentation_type(pres::hexfloat, float_set);
|
||||||
case 'c':
|
case 'c':
|
||||||
if (arg_type == type::bool_type)
|
if (arg_type == type::bool_type) report_error("invalid format specifier");
|
||||||
throw_format_error("invalid format specifier");
|
|
||||||
return parse_presentation_type(pres::chr, integral_set);
|
return parse_presentation_type(pres::chr, integral_set);
|
||||||
case 's':
|
case 's':
|
||||||
return parse_presentation_type(pres::string,
|
return parse_presentation_type(pres::string,
|
||||||
@ -2466,11 +2469,11 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
// Parse fill and alignment.
|
// Parse fill and alignment.
|
||||||
auto fill_end = begin + code_point_length(begin);
|
auto fill_end = begin + code_point_length(begin);
|
||||||
if (end - fill_end <= 0) {
|
if (end - fill_end <= 0) {
|
||||||
throw_format_error("invalid format specifier");
|
report_error("invalid format specifier");
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
if (*begin == '{') {
|
if (*begin == '{') {
|
||||||
throw_format_error("invalid fill character '{'");
|
report_error("invalid fill character '{'");
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
auto align = parse_align(to_ascii(*fill_end));
|
auto align = parse_align(to_ascii(*fill_end));
|
||||||
@ -2610,7 +2613,7 @@ FMT_CONSTEXPR auto check_char_specs(const format_specs<Char>& specs) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
|
if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
|
||||||
throw_format_error("invalid format specifier for char");
|
report_error("invalid format specifier for char");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2687,9 +2690,7 @@ template <typename Char, typename... Args> class format_string_checker {
|
|||||||
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
|
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
FMT_CONSTEXPR void on_error(const char* message) { report_error(message); }
|
||||||
throw_format_error(message);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A base class for compile-time strings.
|
// A base class for compile-time strings.
|
||||||
|
@ -123,7 +123,7 @@ FMT_FUNC auto write_loc(appender out, loc_value value,
|
|||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_FUNC void throw_format_error(const char* message) {
|
FMT_FUNC void report_error(const char* message) {
|
||||||
FMT_THROW(format_error(message));
|
FMT_THROW(format_error(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1033,8 +1033,6 @@ template <typename OutputIt, typename Char> class generic_context {
|
|||||||
return args_;
|
return args_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* message) { throw_format_error(message); }
|
|
||||||
|
|
||||||
FMT_CONSTEXPR auto out() -> iterator { return out_; }
|
FMT_CONSTEXPR auto out() -> iterator { return out_; }
|
||||||
|
|
||||||
void advance_to(iterator it) {
|
void advance_to(iterator it) {
|
||||||
@ -2333,7 +2331,7 @@ FMT_CONSTEXPR auto write(OutputIt out, const Char* s,
|
|||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
if (specs.type == presentation_type::pointer)
|
if (specs.type == presentation_type::pointer)
|
||||||
return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
|
return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
|
||||||
if (!s) throw_format_error("string pointer is null");
|
if (!s) report_error("string pointer is null");
|
||||||
return write(out, basic_string_view<Char>(s), specs, {});
|
return write(out, basic_string_view<Char>(s), specs, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2384,7 +2382,7 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
|
|||||||
auto c = *begin;
|
auto c = *begin;
|
||||||
if (c == '}') return begin;
|
if (c == '}') return begin;
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
throw_format_error("invalid fill character '{'");
|
report_error("invalid fill character '{'");
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
specs.fill = {begin, to_unsigned(p - begin)};
|
specs.fill = {begin, to_unsigned(p - begin)};
|
||||||
@ -3600,7 +3598,7 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value,
|
|||||||
: 6;
|
: 6;
|
||||||
if (fspecs.format == float_format::exp) {
|
if (fspecs.format == float_format::exp) {
|
||||||
if (precision == max_value<int>())
|
if (precision == max_value<int>())
|
||||||
throw_format_error("number is too big");
|
report_error("number is too big");
|
||||||
else
|
else
|
||||||
++precision;
|
++precision;
|
||||||
} else if (fspecs.format != float_format::fixed && precision == 0) {
|
} else if (fspecs.format != float_format::fixed && precision == 0) {
|
||||||
@ -3707,7 +3705,7 @@ FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt {
|
|||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
FMT_CONSTEXPR20 auto write(OutputIt out, const Char* value) -> OutputIt {
|
FMT_CONSTEXPR20 auto write(OutputIt out, const Char* value) -> OutputIt {
|
||||||
if (value) return write(out, basic_string_view<Char>(value));
|
if (value) return write(out, basic_string_view<Char>(value));
|
||||||
throw_format_error("string pointer is null");
|
report_error("string pointer is null");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3785,13 +3783,13 @@ template <typename Char> struct arg_formatter {
|
|||||||
struct width_checker {
|
struct width_checker {
|
||||||
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
||||||
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
|
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
|
||||||
if (is_negative(value)) throw_format_error("negative width");
|
if (is_negative(value)) report_error("negative width");
|
||||||
return static_cast<unsigned long long>(value);
|
return static_cast<unsigned long long>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
|
||||||
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
||||||
throw_format_error("width is not integer");
|
report_error("width is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3799,13 +3797,13 @@ struct width_checker {
|
|||||||
struct precision_checker {
|
struct precision_checker {
|
||||||
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
||||||
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
|
FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
|
||||||
if (is_negative(value)) throw_format_error("negative precision");
|
if (is_negative(value)) report_error("negative precision");
|
||||||
return static_cast<unsigned long long>(value);
|
return static_cast<unsigned long long>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
|
||||||
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
|
||||||
throw_format_error("precision is not integer");
|
report_error("precision is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3813,15 +3811,14 @@ struct precision_checker {
|
|||||||
template <typename Handler, typename FormatArg>
|
template <typename Handler, typename FormatArg>
|
||||||
FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int {
|
FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int {
|
||||||
unsigned long long value = arg.visit(Handler());
|
unsigned long long value = arg.visit(Handler());
|
||||||
if (value > to_unsigned(max_value<int>()))
|
if (value > to_unsigned(max_value<int>())) report_error("number is too big");
|
||||||
throw_format_error("number is too big");
|
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context, typename ID>
|
template <typename Context, typename ID>
|
||||||
FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) {
|
FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) {
|
||||||
auto arg = ctx.arg(id);
|
auto arg = ctx.arg(id);
|
||||||
if (!arg) ctx.on_error("argument not found");
|
if (!arg) report_error("argument not found");
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3893,6 +3890,7 @@ using format_func = void (*)(detail::buffer<char>&, int, const char*);
|
|||||||
FMT_API void format_error_code(buffer<char>& out, int error_code,
|
FMT_API void format_error_code(buffer<char>& out, int error_code,
|
||||||
string_view message) noexcept;
|
string_view message) noexcept;
|
||||||
|
|
||||||
|
using fmt::report_error;
|
||||||
FMT_API void report_error(format_func func, int error_code,
|
FMT_API void report_error(format_func func, int error_code,
|
||||||
const char* message) noexcept;
|
const char* message) noexcept;
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -4253,7 +4251,7 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
|||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
if (fmt.size() == 2 && equal2(fmt.data(), "{}")) {
|
if (fmt.size() == 2 && equal2(fmt.data(), "{}")) {
|
||||||
auto arg = args.get(0);
|
auto arg = args.get(0);
|
||||||
if (!arg) throw_format_error("argument not found");
|
if (!arg) report_error("argument not found");
|
||||||
arg.visit(default_arg_formatter<Char>{out, args, loc});
|
arg.visit(default_arg_formatter<Char>{out, args, loc});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4280,7 +4278,7 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
|||||||
}
|
}
|
||||||
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
|
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
|
||||||
int arg_id = context.arg_id(id);
|
int arg_id = context.arg_id(id);
|
||||||
if (arg_id < 0) throw_format_error("argument not found");
|
if (arg_id < 0) report_error("argument not found");
|
||||||
return arg_id;
|
return arg_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4303,13 +4301,13 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
|||||||
detail::handle_dynamic_spec<detail::precision_checker>(
|
detail::handle_dynamic_spec<detail::precision_checker>(
|
||||||
specs.precision, specs.precision_ref, context);
|
specs.precision, specs.precision_ref, context);
|
||||||
if (begin == end || *begin != '}')
|
if (begin == end || *begin != '}')
|
||||||
throw_format_error("missing '}' in format string");
|
report_error("missing '}' in format string");
|
||||||
context.advance_to(arg.visit(
|
context.advance_to(arg.visit(
|
||||||
arg_formatter<Char>{context.out(), specs, context.locale()}));
|
arg_formatter<Char>{context.out(), specs, context.locale()}));
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* message) { throw_format_error(message); }
|
void on_error(const char* message) { report_error(message); }
|
||||||
};
|
};
|
||||||
detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
|
detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,6 @@ template <typename Char> class basic_printf_context {
|
|||||||
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
||||||
return args_.get(id);
|
return args_.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* message) { throw_format_error(message); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -80,13 +78,13 @@ struct printf_precision_handler {
|
|||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
auto operator()(T value) -> int {
|
auto operator()(T value) -> int {
|
||||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
throw_format_error("number is too big");
|
report_error("number is too big");
|
||||||
return (std::max)(static_cast<int>(value), 0);
|
return (std::max)(static_cast<int>(value), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
auto operator()(T) -> int {
|
auto operator()(T) -> int {
|
||||||
throw_format_error("precision is not integer");
|
report_error("precision is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -208,13 +206,13 @@ template <typename Char> class printf_width_handler {
|
|||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
unsigned int_max = max_value<int>();
|
unsigned int_max = max_value<int>();
|
||||||
if (width > int_max) throw_format_error("number is too big");
|
if (width > int_max) report_error("number is too big");
|
||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
auto operator()(T) -> unsigned {
|
auto operator()(T) -> unsigned {
|
||||||
throw_format_error("width is not integer");
|
report_error("width is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -352,7 +350,7 @@ auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
|
|||||||
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) throw_format_error("number is too big");
|
if (value == -1) report_error("number is too big");
|
||||||
specs.width = value;
|
specs.width = value;
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@ -363,7 +361,7 @@ auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
|
|||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (*it >= '0' && *it <= '9') {
|
if (*it >= '0' && *it <= '9') {
|
||||||
specs.width = parse_nonnegative_int(it, end, -1);
|
specs.width = parse_nonnegative_int(it, end, -1);
|
||||||
if (specs.width == -1) throw_format_error("number is too big");
|
if (specs.width == -1) report_error("number is too big");
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.width = static_cast<int>(
|
specs.width = static_cast<int>(
|
||||||
@ -457,7 +455,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
|
|
||||||
// Parse argument index, flags and width.
|
// Parse argument index, flags and width.
|
||||||
int arg_index = parse_header(it, end, specs, get_arg);
|
int arg_index = parse_header(it, end, specs, get_arg);
|
||||||
if (arg_index == 0) throw_format_error("argument not found");
|
if (arg_index == 0) report_error("argument not found");
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (it != end && *it == '.') {
|
if (it != end && *it == '.') {
|
||||||
@ -539,7 +537,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (it == end) throw_format_error("invalid format string");
|
if (it == end) report_error("invalid format string");
|
||||||
char type = static_cast<char>(*it++);
|
char type = static_cast<char>(*it++);
|
||||||
if (arg.is_integral()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
@ -556,7 +554,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
bool upper = false;
|
bool upper = false;
|
||||||
specs.type = parse_printf_presentation_type(type, arg.type(), upper);
|
specs.type = parse_printf_presentation_type(type, arg.type(), upper);
|
||||||
if (specs.type == presentation_type::none)
|
if (specs.type == presentation_type::none)
|
||||||
throw_format_error("invalid format specifier");
|
report_error("invalid format specifier");
|
||||||
specs.upper = upper;
|
specs.upper = upper;
|
||||||
|
|
||||||
start = it;
|
start = it;
|
||||||
|
@ -310,8 +310,7 @@ struct formatter<Tuple, Char,
|
|||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = ctx.begin();
|
auto it = ctx.begin();
|
||||||
if (it != ctx.end() && *it != '}')
|
if (it != ctx.end() && *it != '}') report_error("invalid format specifier");
|
||||||
throw_format_error("invalid format specifier");
|
|
||||||
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
|
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
@ -417,7 +416,7 @@ struct range_formatter<
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (it != end && *it != '}') {
|
if (it != end && *it != '}') {
|
||||||
if (*it != ':') throw_format_error("invalid format specifier");
|
if (*it != ':') report_error("invalid format specifier");
|
||||||
++it;
|
++it;
|
||||||
} else {
|
} else {
|
||||||
detail::maybe_set_debug_format(underlying_, true);
|
detail::maybe_set_debug_format(underlying_, true);
|
||||||
@ -650,7 +649,7 @@ struct formatter<tuple_join_view<Char, T...>, Char> {
|
|||||||
if (N > 1) {
|
if (N > 1) {
|
||||||
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||||
if (end != end1)
|
if (end != end1)
|
||||||
throw_format_error("incompatible format specs for tuple elements");
|
report_error("incompatible format specs for tuple elements");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return end;
|
return end;
|
||||||
|
@ -447,7 +447,7 @@ TEST(memory_buffer_test, max_size_allocator_overflow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, exception_from_lib) {
|
TEST(format_test, exception_from_lib) {
|
||||||
EXPECT_THROW_MSG(fmt::throw_format_error("test"), format_error, "test");
|
EXPECT_THROW_MSG(fmt::report_error("test"), format_error, "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, escape) {
|
TEST(format_test, escape) {
|
||||||
|
@ -87,7 +87,7 @@ template <> struct scanner<num> {
|
|||||||
hex = true;
|
hex = true;
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
if (it != end && *it != '}') throw_format_error("invalid format");
|
if (it != end && *it != '}') report_error("invalid format");
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
test/scan.h
20
test/scan.h
@ -453,7 +453,7 @@ template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
|
|||||||
auto read(scan_iterator it, T& value) -> scan_iterator {
|
auto read(scan_iterator it, T& value) -> scan_iterator {
|
||||||
if (it == scan_sentinel()) return it;
|
if (it == scan_sentinel()) return it;
|
||||||
char c = *it;
|
char c = *it;
|
||||||
if (c < '0' || c > '9') throw_format_error("invalid input");
|
if (c < '0' || c > '9') report_error("invalid input");
|
||||||
|
|
||||||
int num_digits = 0;
|
int num_digits = 0;
|
||||||
T n = 0, prev = 0;
|
T n = 0, prev = 0;
|
||||||
@ -477,7 +477,7 @@ auto read(scan_iterator it, T& value) -> scan_iterator {
|
|||||||
prev * 10ull + unsigned(prev_digit - '0') <= max) {
|
prev * 10ull + unsigned(prev_digit - '0') <= max) {
|
||||||
value = n;
|
value = n;
|
||||||
} else {
|
} else {
|
||||||
throw_format_error("number is too big");
|
report_error("number is too big");
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
@ -486,7 +486,7 @@ template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
|
|||||||
auto read_hex(scan_iterator it, T& value) -> scan_iterator {
|
auto read_hex(scan_iterator it, T& value) -> scan_iterator {
|
||||||
if (it == scan_sentinel()) return it;
|
if (it == scan_sentinel()) return it;
|
||||||
int digit = to_hex_digit(*it);
|
int digit = to_hex_digit(*it);
|
||||||
if (digit < 0) throw_format_error("invalid input");
|
if (digit < 0) report_error("invalid input");
|
||||||
|
|
||||||
int num_digits = 0;
|
int num_digits = 0;
|
||||||
T n = 0;
|
T n = 0;
|
||||||
@ -501,7 +501,7 @@ auto read_hex(scan_iterator it, T& value) -> scan_iterator {
|
|||||||
if (num_digits <= (std::numeric_limits<T>::digits >> 2))
|
if (num_digits <= (std::numeric_limits<T>::digits >> 2))
|
||||||
value = n;
|
value = n;
|
||||||
else
|
else
|
||||||
throw_format_error("number is too big");
|
report_error("number is too big");
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +518,7 @@ auto read(scan_iterator it, T& value, const format_specs<>& specs = {})
|
|||||||
bool negative = it != scan_sentinel() && *it == '-';
|
bool negative = it != scan_sentinel() && *it == '-';
|
||||||
if (negative) {
|
if (negative) {
|
||||||
++it;
|
++it;
|
||||||
if (it == scan_sentinel()) throw_format_error("invalid input");
|
if (it == scan_sentinel()) report_error("invalid input");
|
||||||
}
|
}
|
||||||
using unsigned_type = typename std::make_unsigned<T>::type;
|
using unsigned_type = typename std::make_unsigned<T>::type;
|
||||||
unsigned_type abs_value = 0;
|
unsigned_type abs_value = 0;
|
||||||
@ -538,7 +538,7 @@ auto read(scan_iterator it, string_view& value, const format_specs<>& = {})
|
|||||||
-> scan_iterator {
|
-> scan_iterator {
|
||||||
auto range = to_contiguous(it);
|
auto range = to_contiguous(it);
|
||||||
// This could also be checked at compile time in scan.
|
// This could also be checked at compile time in scan.
|
||||||
if (!range) throw_format_error("string_view requires contiguous input");
|
if (!range) report_error("string_view requires contiguous input");
|
||||||
auto p = range.begin;
|
auto p = range.begin;
|
||||||
while (p != range.end && *p != ' ') ++p;
|
while (p != range.end && *p != ' ') ++p;
|
||||||
size_t size = to_unsigned(p - range.begin);
|
size_t size = to_unsigned(p - range.begin);
|
||||||
@ -624,7 +624,7 @@ struct scan_handler {
|
|||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* message) { throw_format_error(message); }
|
void on_error(const char* message) { report_error(message); }
|
||||||
};
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
@ -640,7 +640,7 @@ template <typename T> class scan_value {
|
|||||||
public:
|
public:
|
||||||
scan_value(T value) : value_(std::move(value)) {}
|
scan_value(T value) : value_(std::move(value)) {}
|
||||||
|
|
||||||
const T& value() const { return value_; }
|
auto value() const -> const T& { return value_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A rudimentary version of std::expected for testing the API shape.
|
// A rudimentary version of std::expected for testing the API shape.
|
||||||
@ -651,7 +651,7 @@ template <typename T> class expected {
|
|||||||
public:
|
public:
|
||||||
expected(T value) : value_(std::move(value)) {}
|
expected(T value) : value_(std::move(value)) {}
|
||||||
|
|
||||||
const T* operator->() const { return &value_; }
|
auto operator->() const -> const T* { return &value_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> using scan_result = expected<scan_value<T>>;
|
template <typename T> using scan_result = expected<scan_value<T>>;
|
||||||
@ -688,7 +688,7 @@ auto scan_to(InputRange&& input, string_view fmt, T&... args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
bool scan_to(FILE* f, string_view fmt, T&... args) {
|
auto scan_to(FILE* f, string_view fmt, T&... args) -> bool {
|
||||||
auto&& buf = detail::file_scan_buffer(f);
|
auto&& buf = detail::file_scan_buffer(f);
|
||||||
vscan(buf, fmt, make_scan_args(args...));
|
vscan(buf, fmt, make_scan_args(args...));
|
||||||
return buf.begin() != buf.end();
|
return buf.begin() != buf.end();
|
||||||
|
Reference in New Issue
Block a user