diff --git a/format.cc b/format.cc index 8cb43450..31a74689 100644 --- a/format.cc +++ b/format.cc @@ -431,8 +431,18 @@ class fmt::internal::ArgFormatter : void visit_any_double(T value) { writer_.FormatDouble(value, spec_); } void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') - fmt::internal::ReportUnknownType(spec_.type_, "char"); + if (spec_.type_ && spec_.type_ != 'c') { + switch (spec_.type_) { + // TODO: don't duplicate integer format specifiers here + case 'd': case 'x': case 'X': case 'b': case 'B': case 'o': + writer_.FormatInt(value, spec_); + break; + default: + internal::ReportUnknownType(spec_.type_, "char"); + } + } + if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) + throw FormatError("invalid format specifier for char"); typedef typename fmt::BasicWriter::CharPtr CharPtr; CharPtr out = CharPtr(); if (spec_.width_ > 1) { @@ -893,25 +903,17 @@ void fmt::internal::PrintfFormatter::Format( case Arg::ULONG_LONG: writer.FormatInt(arg.ulong_long_value, spec); break; - case Arg::DOUBLE: - writer.FormatDouble(arg.double_value, spec); - break; - case Arg::LONG_DOUBLE: - writer.FormatDouble(arg.long_double_value, spec); - break; case Arg::CHAR: { if (spec.type_ && spec.type_ != 'c') - internal::ReportUnknownType(spec.type_, "char"); + writer.FormatInt(arg.int_value, spec); typedef typename BasicWriter::CharPtr CharPtr; CharPtr out = CharPtr(); if (spec.width_ > 1) { - Char fill = static_cast(spec.fill()); + Char fill = ' '; out = writer.GrowBuffer(spec.width_); - if (spec.align_ == ALIGN_RIGHT) { + if (spec.align_ != ALIGN_LEFT) { std::fill_n(out, spec.width_ - 1, fill); out += spec.width_ - 1; - } else if (spec.align_ == ALIGN_CENTER) { - out = writer.FillPadding(out, spec.width_, 1, fill); } else { std::fill_n(out + 1, spec.width_ - 1, fill); } @@ -921,6 +923,12 @@ void fmt::internal::PrintfFormatter::Format( *out = static_cast(arg.int_value); break; } + case Arg::DOUBLE: + writer.FormatDouble(arg.double_value, spec); + break; + case Arg::LONG_DOUBLE: + writer.FormatDouble(arg.long_double_value, spec); + break; case Arg::STRING: writer.write_str(arg.string, spec); break; @@ -1001,6 +1009,7 @@ const Char *fmt::BasicFormatter::format( break; case '-': CheckSign(s, arg); + spec.flags_ |= MINUS_FLAG; break; case ' ': CheckSign(s, arg); diff --git a/format.h b/format.h index 342b8daa..9c55d780 100644 --- a/format.h +++ b/format.h @@ -569,10 +569,10 @@ struct NonZero<0> { struct Arg { enum Type { // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, LAST_INTEGER_TYPE = ULONG_LONG, + INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CHAR, STRING, WSTRING, POINTER, CUSTOM + STRING, WSTRING, POINTER, CUSTOM }; Type type; @@ -900,7 +900,7 @@ enum Alignment { }; // Flags. -enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HASH_FLAG = 4 }; +enum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8 }; // An empty format specifier. struct EmptySpec {}; diff --git a/test/format-test.cc b/test/format-test.cc index 753bee24..7bed6967 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -696,7 +696,7 @@ TEST(FormatterTest, NumericAlign) { EXPECT_THROW_MSG(format("{0:=5", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0:=5}", 'c'), - FormatError, "format specifier '=' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:=5}", "abc"), FormatError, "format specifier '=' requires numeric argument"); EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast(0xface)), @@ -760,7 +760,7 @@ TEST(FormatterTest, PlusSign) { EXPECT_THROW_MSG(format("{0:+", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0:+}", 'c'), - FormatError, "format specifier '+' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:+}", "abc"), FormatError, "format specifier '+' requires numeric argument"); EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast(0x42)), @@ -786,7 +786,7 @@ TEST(FormatterTest, MinusSign) { EXPECT_THROW_MSG(format("{0:-", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0:-}", 'c'), - FormatError, "format specifier '-' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:-}", "abc"), FormatError, "format specifier '-' requires numeric argument"); EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast(0x42)), @@ -812,7 +812,7 @@ TEST(FormatterTest, SpaceSign) { EXPECT_THROW_MSG(format("{0: ", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0: }", 'c'), - FormatError, "format specifier ' ' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0: }", "abc"), FormatError, "format specifier ' ' requires numeric argument"); EXPECT_THROW_MSG(format("{0: }", reinterpret_cast(0x42)), @@ -859,7 +859,7 @@ TEST(FormatterTest, HashFlag) { EXPECT_THROW_MSG(format("{0:#", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0:#}", 'c'), - FormatError, "format specifier '#' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:#}", "abc"), FormatError, "format specifier '#' requires numeric argument"); EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast(0x42)), @@ -881,7 +881,7 @@ TEST(FormatterTest, ZeroFlag) { EXPECT_THROW_MSG(format("{0:0", 'c'), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(format("{0:05}", 'c'), - FormatError, "format specifier '0' requires numeric argument"); + FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:05}", "abc"), FormatError, "format specifier '0' requires numeric argument"); EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast(0x42)), @@ -1268,7 +1268,7 @@ TEST(FormatterTest, FormatLongDouble) { } TEST(FormatterTest, FormatChar) { - CheckUnknownTypes('a', "c", "char"); + CheckUnknownTypes('a', "cbBdoxX", "char"); EXPECT_EQ("a", format("{0}", 'a')); EXPECT_EQ("z", format("{0:c}", 'z')); EXPECT_EQ(L"a", format(L"{0}", 'a'));