diff --git a/format.cc b/format.cc index 2a11fe86..a6affaae 100644 --- a/format.cc +++ b/format.cc @@ -55,7 +55,7 @@ using fmt::StringRef; namespace { // Flags. -enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HEX_PREFIX_FLAG = 4 }; +enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HASH_FLAG = 4 }; void ReportUnknownType(char code, const char *type) { if (std::isprint(static_cast(code))) { @@ -236,7 +236,7 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) { } case 'x': case 'X': { UnsignedType n = abs_value; - bool print_prefix = (spec.flags & HEX_PREFIX_FLAG) != 0; + bool print_prefix = (spec.flags & HASH_FLAG) != 0; if (print_prefix) size += 2; do { ++size; @@ -250,12 +250,14 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) { } while ((n >>= 4) != 0); if (print_prefix) { *p-- = spec.type; - *p-- = '0'; + *p = '0'; } break; } case 'o': { UnsignedType n = abs_value; + bool print_prefix = (spec.flags & HASH_FLAG) != 0; + if (print_prefix) ++size; do { ++size; } while ((n >>= 3) != 0); @@ -264,6 +266,8 @@ void Formatter::FormatInt(T value, const FormatSpec &spec) { do { *p-- = '0' + (n & 7); } while ((n >>= 3) != 0); + if (print_prefix) + *p = '0'; break; } default: @@ -310,11 +314,13 @@ void Formatter::FormatDouble(T value, const FormatSpec &spec, int precision) { } // Build format string. - enum { MAX_FORMAT_SIZE = 10}; // longest format: %+0*.*Lg + enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg char format[MAX_FORMAT_SIZE]; char *format_ptr = format; *format_ptr++ = '%'; unsigned width_for_sprintf = width; + if ((spec.flags & HASH_FLAG) != 0) + *format_ptr++ = '#'; if (spec.align == ALIGN_CENTER) { width_for_sprintf = 0; } else { @@ -503,6 +509,13 @@ void Formatter::DoFormat() { break; } + if (*s == '#') { + if (arg.type > LAST_NUMERIC_TYPE) + ReportError(s, "format specifier '#' requires numeric argument"); + spec.flags |= HASH_FLAG; + ++s; + } + // Parse width and zero flag. if ('0' <= *s && *s <= '9') { if (*s == '0') { @@ -634,7 +647,7 @@ void Formatter::DoFormat() { case POINTER: if (spec.type && spec.type != 'p') ReportUnknownType(spec.type, "pointer"); - spec.flags = HEX_PREFIX_FLAG; + spec.flags = HASH_FLAG; spec.type = 'x'; FormatInt(reinterpret_cast(arg.pointer_value), spec); break; diff --git a/format_test.cc b/format_test.cc index ee26238a..6660169f 100644 --- a/format_test.cc +++ b/format_test.cc @@ -425,6 +425,39 @@ TEST(FormatterTest, SpaceSign) { FormatError, "format specifier ' ' requires numeric argument"); } +TEST(FormatterTest, HashFlag) { + // TODO + EXPECT_EQ("42", str(Format("{0:#}") << 42)); + EXPECT_EQ("-42", str(Format("{0:#}") << -42)); + EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42)); + EXPECT_EQ("-0x42", str(Format("{0:#x}") << -0x42)); + EXPECT_EQ("042", str(Format("{0:#o}") << 042)); + EXPECT_EQ("-042", str(Format("{0:#o}") << -042)); + EXPECT_EQ("42", str(Format("{0:#}") << 42u)); + EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42u)); + EXPECT_EQ("042", str(Format("{0:#o}") << 042u)); + EXPECT_EQ("-42", str(Format("{0:#}") << -42l)); + EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42l)); + EXPECT_EQ("-0x42", str(Format("{0:#x}") << -0x42l)); + EXPECT_EQ("042", str(Format("{0:#o}") << 042l)); + EXPECT_EQ("-042", str(Format("{0:#o}") << -042l)); + EXPECT_EQ("42", str(Format("{0:#}") << 42ul)); + EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42ul)); + EXPECT_EQ("042", str(Format("{0:#o}") << 042ul)); + EXPECT_EQ("-42.0000", str(Format("{0:#}") << -42.0)); + EXPECT_EQ("-42.0000", str(Format("{0:#}") << -42.0l)); + EXPECT_THROW_MSG(Format("{0:#") << 'c', + FormatError, "unmatched '{' in format"); + EXPECT_THROW_MSG(Format("{0:#}") << 'c', + FormatError, "format specifier '#' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:#}") << "abc", + FormatError, "format specifier '#' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:#}") << reinterpret_cast(0x42), + FormatError, "format specifier '#' requires numeric argument"); + EXPECT_THROW_MSG(Format("{0:#}") << TestString(), + FormatError, "format specifier '#' requires numeric argument"); +} + TEST(FormatterTest, ZeroFlag) { EXPECT_EQ("42", str(Format("{0:0}") << 42)); EXPECT_EQ("-0042", str(Format("{0:05}") << -42));