fixed keys with \n round-tripping incorrectly

This commit is contained in:
Mark Gillard 2023-10-10 17:21:03 +03:00
parent be30d11245
commit cc1962eac7
6 changed files with 62 additions and 29 deletions

View File

@ -33,6 +33,7 @@ template:
- fixed `for_each()` compilation error on GCC <= 7 (#197) (@sagi-ottopia, @damirbarr)
- fixed `FLT_RADIX` check getting broken by Intel MKL headers (#202) (@iago-lito)
- fixed keys containing `\t` incorrectly formatting as bare keys (@jasmine-zhu, @arp242)
- fixed keys containing `\t` and `\n` not round-tripping correctly (@arp242)
#### Additions

View File

@ -149,7 +149,10 @@ TOML_IMPL_NAMESPACE_START
void print_unformatted(std::string_view);
TOML_EXPORTED_MEMBER_FUNCTION
void print_string(std::string_view str, bool allow_multi_line = true, bool allow_bare = false);
void print_string(std::string_view str,
bool allow_multi_line = true,
bool allow_bare = false,
bool allow_literal_whitespace = true);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<std::string>&);

View File

@ -113,7 +113,10 @@ TOML_IMPL_NAMESPACE_START
}
TOML_EXTERNAL_LINKAGE
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
void formatter::print_string(std::string_view str,
bool allow_multi_line,
bool allow_bare,
bool allow_literal_whitespace)
{
if (str.empty())
{
@ -206,8 +209,10 @@ TOML_IMPL_NAMESPACE_START
bad_unicode();
}
// strings with line breaks and tabs can't be bare
if (!!(traits & (formatted_string_traits::line_breaks | formatted_string_traits::tabs)))
// strings with line breaks, tabs, and single-quotes can't be bare
if (!!(traits
& (formatted_string_traits::line_breaks | formatted_string_traits::tabs
| formatted_string_traits::single_quotes)))
traits |= formatted_string_traits::non_bare;
// if the string meets the requirements of being 'bare' we can emit a bare string
@ -218,17 +223,20 @@ TOML_IMPL_NAMESPACE_START
print_unformatted(str);
return;
}
const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
// determine if this should be a multi-line string (triple-quotes)
const auto multi_line = allow_multi_line //
const auto multi_line = allow_literal_whitespace //
&& allow_multi_line //
&& multi_line_strings_allowed() //
&& !!(traits & formatted_string_traits::line_breaks);
// determine if this should be a literal string (single-quotes with no escaping)
const auto literal = literal_strings_allowed() //
&& !(traits & formatted_string_traits::control_chars) //
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
&& (!(traits & formatted_string_traits::tabs) || real_tabs_in_strings_allowed()) //
const auto literal = literal_strings_allowed() //
&& !(traits & formatted_string_traits::control_chars) //
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
&& (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
&& (!(traits & formatted_string_traits::line_breaks) || multi_line) //
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
// literal strings (single quotes, no escape codes)
@ -244,8 +252,6 @@ TOML_IMPL_NAMESPACE_START
// anything from here down is a non-literal string, so requires iteration and escaping.
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
const auto real_tabs_allowed = real_tabs_in_strings_allowed();
// ascii fast path
if (!(traits & formatted_string_traits::non_ascii))
{

View File

@ -130,7 +130,7 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const key& k)
{
print_string(k.str(), false, true);
print_string(k.str(), false, true, false);
}
TOML_EXTERNAL_LINKAGE

View File

@ -415,19 +415,33 @@ b = []
SECTION("tomlplusplus/issues/176") // https://github.com/marzer/tomlplusplus/issues/176
{
parsing_should_succeed(FILE_LINE_ARGS,
R"(
parsing_should_succeed(FILE_LINE_ARGS, " a = \"x\\ty\""sv);
parsing_should_succeed(FILE_LINE_ARGS, "\"a\" = \"x\\ty\""sv);
parsing_should_succeed(FILE_LINE_ARGS, "\"a\tb\" = \"x\\ty\""sv);
parsing_should_fail(FILE_LINE_ARGS, "\"a\nb\" = \"x\\ty\""sv); // literal newline in single-line key
static constexpr auto input = R"(
"a" = "x\ty"
"a\tb" = "x\ty"
)",
[](auto&& tbl)
"a\nb" = "x\ty"
)"sv;
static constexpr auto output = "a = 'x\ty'\n"
"\"a\\tb\" = 'x\ty'\n" // tab and newlines in keys should be emitted
"\"a\\nb\" = 'x\ty'" // as escapes, not literals
""sv;
parsing_should_succeed(FILE_LINE_ARGS,
input,
[&](auto&& tbl)
{
CHECK(tbl["a"]);
CHECK(tbl["a\tb"]);
CHECK(tbl["a\nb"]);
std::stringstream ss;
ss << tbl;
CHECK(ss.str() == "a = 'x\ty'\n'a\tb' = 'x\ty'"sv);
CHECK(ss.str() == output);
});
}
}

View File

@ -9782,7 +9782,10 @@ TOML_IMPL_NAMESPACE_START
void print_unformatted(std::string_view);
TOML_EXPORTED_MEMBER_FUNCTION
void print_string(std::string_view str, bool allow_multi_line = true, bool allow_bare = false);
void print_string(std::string_view str,
bool allow_multi_line = true,
bool allow_bare = false,
bool allow_literal_whitespace = true);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<std::string>&);
@ -16468,7 +16471,10 @@ TOML_IMPL_NAMESPACE_START
}
TOML_EXTERNAL_LINKAGE
void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare)
void formatter::print_string(std::string_view str,
bool allow_multi_line,
bool allow_bare,
bool allow_literal_whitespace)
{
if (str.empty())
{
@ -16561,8 +16567,10 @@ TOML_IMPL_NAMESPACE_START
bad_unicode();
}
// strings with line breaks and tabs can't be bare
if (!!(traits & (formatted_string_traits::line_breaks | formatted_string_traits::tabs)))
// strings with line breaks, tabs, and single-quotes can't be bare
if (!!(traits
& (formatted_string_traits::line_breaks | formatted_string_traits::tabs
| formatted_string_traits::single_quotes)))
traits |= formatted_string_traits::non_bare;
// if the string meets the requirements of being 'bare' we can emit a bare string
@ -16573,17 +16581,20 @@ TOML_IMPL_NAMESPACE_START
print_unformatted(str);
return;
}
const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
// determine if this should be a multi-line string (triple-quotes)
const auto multi_line = allow_multi_line //
const auto multi_line = allow_literal_whitespace //
&& allow_multi_line //
&& multi_line_strings_allowed() //
&& !!(traits & formatted_string_traits::line_breaks);
// determine if this should be a literal string (single-quotes with no escaping)
const auto literal = literal_strings_allowed() //
&& !(traits & formatted_string_traits::control_chars) //
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
&& (!(traits & formatted_string_traits::tabs) || real_tabs_in_strings_allowed()) //
const auto literal = literal_strings_allowed() //
&& !(traits & formatted_string_traits::control_chars) //
&& (!(traits & formatted_string_traits::single_quotes) || multi_line) //
&& (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
&& (!(traits & formatted_string_traits::line_breaks) || multi_line) //
&& (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
// literal strings (single quotes, no escape codes)
@ -16599,8 +16610,6 @@ TOML_IMPL_NAMESPACE_START
// anything from here down is a non-literal string, so requires iteration and escaping.
print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
const auto real_tabs_allowed = real_tabs_in_strings_allowed();
// ascii fast path
if (!(traits & formatted_string_traits::non_ascii))
{
@ -17005,7 +17014,7 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void toml_formatter::print(const key& k)
{
print_string(k.str(), false, true);
print_string(k.str(), false, true, false);
}
TOML_EXTERNAL_LINKAGE