diff --git a/format.cc b/format.cc index 90848b7e..0d01e70e 100644 --- a/format.cc +++ b/format.cc @@ -799,20 +799,23 @@ const Arg &fmt::internal::FormatterBase::next_arg(const char *&error) { } const Arg &fmt::internal::FormatterBase::handle_arg_index(unsigned arg_index) { - if (arg_index != UINT_MAX) { - if (next_arg_index_ <= 0) { - next_arg_index_ = -1; - --arg_index; - } else if (!error_) { - error_ = "cannot switch from automatic to manual argument indexing"; - } + const char *error = 0; + const Arg *arg = 0; + if (arg_index == UINT_MAX) { + arg = &next_arg(error); + } else { + if (next_arg_index_ > 0) + error = "cannot switch from automatic to manual argument indexing"; + next_arg_index_ = -1; + --arg_index; if (arg_index < args_.size()) - return args_[arg_index]; - if (!error_) - error_ = "argument index is out of range in format"; - return DUMMY_ARG; + arg = &args_[arg_index]; + else if (!error) + error = "argument index is out of range in format"; } - return next_arg(error_); + if (error) + throw FormatError(error); + return *arg; } template @@ -871,7 +874,7 @@ unsigned fmt::internal::PrintfFormatter::parse_header( spec.width_ = parse_nonnegative_int(s); } else if (*s == '*') { ++s; - spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX)); + spec.width_ = WidthHandler(spec).visit(get_arg(s)); } return arg_index; } @@ -897,17 +900,6 @@ void fmt::internal::PrintfFormatter::format( FormatSpec spec; spec.align_ = ALIGN_RIGHT; - // Reporting errors is delayed till the format specification is - // completely parsed. This is done to avoid potentially confusing - // error messages for incomplete format strings. For example, in - // sprintf("%2$", 42); - // the format specification is incomplete. In a naive approach we - // would parse 2 as an argument index and report an error that the - // index is out of range which would be rather confusing if the - // use meant "%2d$" rather than "%2$d". If we delay an error, the - // user will get an error that the format string is invalid which - // is OK for both cases. - // Parse argument index, flags and width. unsigned arg_index = parse_header(s, spec); @@ -918,11 +910,11 @@ void fmt::internal::PrintfFormatter::format( spec.precision_ = parse_nonnegative_int(s); } else if (*s == '*') { ++s; - spec.precision_ = PrecisionHandler().visit(handle_arg_index(UINT_MAX)); + spec.precision_ = PrecisionHandler().visit(get_arg(s)); } } - Arg arg = handle_arg_index(arg_index); + Arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) spec.flags_ &= ~HASH_FLAG; if (spec.fill_ == '0') { @@ -967,8 +959,6 @@ void fmt::internal::PrintfFormatter::format( // Parse type. if (!*s) throw FormatError("invalid format string"); - if (error_) - throw FormatError(error_); spec.type_ = static_cast(*s++); if (arg.type <= Arg::LAST_INTEGER_TYPE) { // Normalize type. @@ -1149,8 +1139,6 @@ const Char *fmt::BasicFormatter::format( const Arg &precision_arg = parse_arg_index(s); if (*s++ != '}') throw FormatError("unmatched '{' in format"); - if (error_) - throw FormatError(error_); ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: diff --git a/format.h b/format.h index 54565ac0..2a9e140c 100644 --- a/format.h +++ b/format.h @@ -845,12 +845,11 @@ class FormatterBase { protected: ArgList args_; int next_arg_index_; - const char *error_; // TODO: remove - - FormatterBase() : error_(0) {} const Arg &next_arg(const char *&error); + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. const Arg &handle_arg_index(unsigned arg_index); template @@ -866,10 +865,16 @@ class PrintfFormatter : private FormatterBase { private: void parse_flags(FormatSpec &spec, const Char *&s); - // Parses argument index, flags and width and returns the parsed - // argument index. + // Parses argument index, flags and width and returns the argument index. unsigned parse_header(const Char *&s, FormatSpec &spec); + const Arg &get_arg(const Char *s, + unsigned arg_index = std::numeric_limits::max()) { + if (!*s) + throw FormatError("invalid format string"); + return handle_arg_index(arg_index); + } + public: void format(BasicWriter &writer, BasicStringRef format, const ArgList &args);