Skip to content

Commit 53c8830

Browse files
committed
Fix dynamic named arg format spec handling
When dealing with dynamic named format args, need to account for nested named args when skipping the content of the replacement. Fixes fmtlib#4360
1 parent 7f76955 commit 53c8830

File tree

2 files changed

+15
-1
lines changed

2 files changed

+15
-1
lines changed

include/fmt/base.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,19 @@ class format_string_checker {
17061706
-> const Char* {
17071707
context_.advance_to(begin);
17081708
if (id >= 0 && id < NUM_ARGS) return parse_funcs_[id](context_);
1709-
while (begin != end && *begin != '}') ++begin;
1709+
1710+
// If id is out of range, it means we do not know the type and cannot parse the format at
1711+
// compile time. Instead, skip over content until we finish the format spec, accounting
1712+
// for any nested replacements.
1713+
auto bracket_count = 0;
1714+
while (begin != end && (bracket_count > 0 || *begin != '}')) {
1715+
if (*begin == '{')
1716+
++bracket_count;
1717+
else if (*begin == '}')
1718+
--bracket_count;
1719+
1720+
++begin;
1721+
}
17101722
return begin;
17111723
}
17121724

test/format-test.cc

+2
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ TEST(format_test, named_arg) {
582582
EXPECT_EQ("1/a/A", fmt::format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'),
583583
fmt::arg("A_", "A"), fmt::arg("_1", 1)));
584584
EXPECT_EQ(fmt::format("{0:{width}}", -42, fmt::arg("width", 4)), " -42");
585+
EXPECT_EQ(fmt::format("{value:{width}}", fmt::arg("value", -42),
586+
fmt::arg("width", 4)), " -42");
585587
EXPECT_EQ("st",
586588
fmt::format("{0:.{precision}}", "str", fmt::arg("precision", 2)));
587589
EXPECT_EQ(fmt::format("{} {two}", 1, fmt::arg("two", 2)), "1 2");

0 commit comments

Comments
 (0)