Help markup parser: Fix some issues with auto-closed tags

This commit is contained in:
Celtic Minstrel 2024-08-06 01:40:08 -04:00 committed by Celtic Minstrel
parent d910171b3d
commit 2e3c401f45
2 changed files with 29 additions and 2 deletions

View file

@ -1546,7 +1546,8 @@ static std::pair<std::string, std::string> parse_attribute(std::string::const_it
}
} else {
std::ostringstream s;
for(; beg != end && *beg != '/' && *beg != '>' && *beg != '<' && !isspace(*beg); ++beg) {
bool found_slash = false;
for(; beg != end && *beg != '>' && *beg != '<' && !isspace(*beg); ++beg) {
if(*beg == '&') {
auto entity = parse_entity(beg, end);
if(beg == end) {
@ -1560,7 +1561,13 @@ static std::pair<std::string, std::string> parse_attribute(std::string::const_it
}
} else if(*beg == '\\') {
s << parse_escape(beg, end);
} else if(*beg == '/') {
found_slash = true;
} else {
if(found_slash) {
s << '/';
found_slash = false;
}
s << *beg;
}
}
@ -1568,6 +1575,7 @@ static std::pair<std::string, std::string> parse_attribute(std::string::const_it
// The caller expects beg to point to the last character of the attribute upon return.
// But in this path, we're now pointing to the character AFTER that.
--beg;
if(found_slash) --beg;
}
return {attr, value};
}
@ -1650,7 +1658,7 @@ static std::pair<std::string, config> parse_tag(std::string::const_iterator& beg
config elem;
for(; beg != end && *beg != '>'; ++beg) {
if(isspace(*beg)) continue;
if(*beg == '/') {
if(*beg == '/' && (beg + 1) != end && *(beg + 1) == '>') {
auto_closed = true;
} else if(isalnum(*beg) || *beg == '_') {
const auto& [key, value] = parse_attribute(beg, end, true);

View file

@ -313,6 +313,12 @@ BOOST_AUTO_TEST_CASE( test_help_markup_new )
BOOST_CHECK(output.has_child("tt"));
BOOST_CHECK(!output.mandatory_child("tt").has_attribute("text"));
// Auto-closed tag can have a space before the slash
output = help::parse_text("<tt />");
BOOST_CHECK_EQUAL(output.all_children_count(), 1);
BOOST_CHECK(output.has_child("tt"));
BOOST_CHECK(!output.mandatory_child("tt").has_attribute("text"));
// With an attribute
output = help::parse_text("<tt attr='value'>some text</tt>");
BOOST_CHECK_EQUAL(output.all_children_count(), 1);
@ -467,6 +473,19 @@ BOOST_AUTO_TEST_CASE( test_help_markup_new )
BOOST_CHECK_EQUAL(output.mandatory_child("def")["text"], "tags");
BOOST_CHECK(output.mandatory_child("text", 2).has_attribute("text"));
BOOST_CHECK_EQUAL(output.mandatory_child("text", 2)["text"], " within");
// Two tags with nothing between them shouldn't have an intervening text span.
output = help::parse_text("<img src=help/orb-green.png align=here/><img src=help/orb-green.png align=there/>");
BOOST_CHECK_EQUAL(output.all_children_count(), 2);
BOOST_CHECK_EQUAL(output.child_count("img"), 2);
BOOST_CHECK(output.mandatory_child("img").has_attribute("src"));
BOOST_CHECK_EQUAL(output.mandatory_child("img")["src"], "help/orb-green.png");
BOOST_CHECK(output.mandatory_child("img").has_attribute("align"));
BOOST_CHECK_EQUAL(output.mandatory_child("img")["align"], "here");
BOOST_CHECK(output.mandatory_child("img", 1).has_attribute("src"));
BOOST_CHECK_EQUAL(output.mandatory_child("img", 1)["src"], "help/orb-green.png");
BOOST_CHECK(output.mandatory_child("img", 1).has_attribute("align"));
BOOST_CHECK_EQUAL(output.mandatory_child("img", 1)["align"], "there");
}
BOOST_AUTO_TEST_SUITE_END()