diff --git a/include/fmt/printf.h b/include/fmt/printf.h index f80a57ad..f7eb28c8 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -141,6 +141,13 @@ template class char_converter { void operator()(T) {} // No conversion needed for non-integral types. }; +// An argument visitor that return a pointer to a C string if argument is a +// string or null otherwise. +template struct get_cstring { + template const Char* operator()(T) { return nullptr; } + const Char* operator()(const Char* s) { return s; } +}; + // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. template class printf_width_handler { @@ -495,6 +502,13 @@ OutputIt basic_printf_context::format() { } format_arg arg = get_arg(arg_index); + if (specs.precision >= 0 && arg.type() == internal::type::cstring_type) { + auto str = visit_format_arg(internal::get_cstring(), arg); + auto end = str + specs.precision; + auto nul = std::find(str, end, Char()); + arg = internal::make_arg(basic_string_view( + str, nul != end ? nul - str : specs.precision)); + } if (specs.alt && visit_format_arg(internal::is_zero_int(), arg)) specs.alt = false; if (specs.fill[0] == '0') { diff --git a/test/printf-test.cc b/test/printf-test.cc index adb7e65a..7873c28d 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -259,6 +259,11 @@ TEST(PrintfTest, FloatPrecision) { EXPECT_PRINTF(buffer, "%.3a", 1234.5678); } +TEST(PrintfTest, StringPrecision) { + char test[] = {'H', 'e', 'l', 'l', 'o'}; + EXPECT_EQ(fmt::sprintf("%.4s", test), "Hell"); +} + TEST(PrintfTest, IgnorePrecisionForNonNumericArg) { EXPECT_PRINTF("abc", "%.5s", "abc"); }