Skip to content

Commit

Permalink
PmtYaml: Fix parsing of colons
Browse files Browse the repository at this point in the history
Don't interpret ":" as key/value separator when followed by a
non-whitespace character.

Signed-off-by: Frank Osterfeld <[email protected]>
  • Loading branch information
frankosterfeld authored and RalphSteinhagen committed Dec 5, 2024
1 parent 0080aa7 commit 1b4931f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
34 changes: 32 additions & 2 deletions core/include/gnuradio-4.0/YamlPmt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ struct ParseContext {
return lines[lineIdx].substr(columnIdx).starts_with(sv);
}

bool startsWithToken(std::string_view sv) const {
if (atEndOfLine()) {
return false;
}
if (columnIdx + sv.size() < lines[lineIdx].size() && !std::isspace(lines[lineIdx][columnIdx + sv.size()])) {
return false;
}
return lines[lineIdx].substr(columnIdx).starts_with(sv);
}

bool startsWith(char c) const {
if (atEndOfLine()) {
return false;
Expand All @@ -246,6 +256,14 @@ struct ParseContext {
return false;
}

bool consumeIfStartsWithToken(std::string_view sv) {
if (startsWithToken(sv)) {
consume(sv.size());
return true;
}
return false;
}

char front() const { return lines[lineIdx][columnIdx]; }

void skipToNextLine() {
Expand Down Expand Up @@ -786,14 +804,26 @@ inline std::expected<std::string, ParseError> parseKey(ParseContext& ctx, std::s
}
ctx.consume(2 * quoteOffset + length);
ctx.consumeSpaces();
if (!ctx.consumeIfStartsWith(':')) {
if (!ctx.consumeIfStartsWithToken(":")) {
return std::unexpected(ctx.makeError("Could not find key/value separator ':'"));
}
return *maybeKey;
}

// not quoted
auto colonPos = ctx.remainingLine().find(':');
auto colonPos = [](auto sv) {
for (auto pos = 0UZ; pos < sv.size(); ++pos) {
pos = sv.find(':', pos);
if (pos == std::string_view::npos) {
return pos;
}
if (pos == sv.size() - 1 || std::isspace(sv[pos + 1])) {
return pos;
}
}
return std::string_view::npos;
}(ctx.remainingLine());

auto commentPos = ctx.remainingLine().find('#');
if (colonPos == std::string_view::npos || (commentPos != std::string_view::npos && commentPos < colonPos)) {
return std::unexpected(ctx.makeError("Could not find key/value separator ':'"));
Expand Down
4 changes: 4 additions & 0 deletions core/test/qa_YamlPmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ empty: !!str ""
spaces_only: !!str " "
value_with_colon: "value: with colon"
value_with_colon2: "value:\n with colon"
value_with_colon3: std::ranges
multiline1: !!str |
First line
Second line
Expand Down Expand Up @@ -229,6 +230,7 @@ unprintable_chars: !!str "\0\x01\x02\x03\x04\x05\x00\x06\x07\x08\x09\x0A\x0B\x0C
expected["spaces_only"] = " "s;
expected["value_with_colon"] = "value: with colon"s;
expected["value_with_colon2"] = "value:\n with colon"s;
expected["value_with_colon3"] = "std::ranges"s;
expected["multiline1"] = "First line\nSecond line\nThird line with trailing newline\nNull bytes (\x00\x00)\nThis is a quoted backslash \"\\\"\n"s;
expected["multiline2"] = "This is a long paragraph that will be folded into a single line with trailing newlines This is a quoted backslash \"\\\" These are some invalid escapes \\q\\xZZ\\x\n\n"s;
expected["multiline3"] = "First line\nSecond line\nThird line without trailing newline"s;
Expand Down Expand Up @@ -724,6 +726,7 @@ Key with spaces: !!int8 42
"key with CR \r": !!int8 48
"key with backslash \\": !!int8 49
"key with quote \"": !!int8 50
key::with::colons: !!int8 51
)yaml";

pmtv::map_t expected;
Expand All @@ -737,6 +740,7 @@ Key with spaces: !!int8 42
expected["key with CR \r"] = static_cast<int8_t>(48);
expected["key with backslash \\"] = static_cast<int8_t>(49);
expected["key with quote \""] = static_cast<int8_t>(50);
expected["key::with::colons"] = static_cast<int8_t>(51);

testYAML(src, expected);
};
Expand Down

0 comments on commit 1b4931f

Please sign in to comment.