From 6254448640530240dc9199bed60cd5568cbaf601 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 1 Aug 2017 16:42:22 +0300 Subject: Add manifest_parser::split_comment() and manifest_serializer::merge_comment() --- libbutl/manifest-parser.cxx | 42 ++++++++++++++++++++++++++++++++++++ libbutl/manifest-parser.hxx | 8 +++++++ libbutl/manifest-serializer.cxx | 25 +++++++++++++++++++++ libbutl/manifest-serializer.hxx | 7 ++++++ tests/manifest-parser/driver.cxx | 17 +++++++++++++++ tests/manifest-serializer/driver.cxx | 8 +++++++ 6 files changed, 107 insertions(+) diff --git a/libbutl/manifest-parser.cxx b/libbutl/manifest-parser.cxx index ae92d79..304815a 100644 --- a/libbutl/manifest-parser.cxx +++ b/libbutl/manifest-parser.cxx @@ -125,6 +125,48 @@ namespace butl return r; } + pair manifest_parser:: + split_comment (const string& v) + { + using iterator = string::const_iterator; + + auto space = [] (char c) -> bool {return c == ' ' || c == '\t';}; + + iterator i (v.begin ()); + iterator e (v.end ()); + + string r; + size_t n (0); + for (char c; i != e && (c = *i) != ';'; ++i) + { + // Unescape ';' character. + // + if (c == '\\' && i + 1 != e && *(i + 1) == ';') + c = *++i; + + r += c; + + if (!space (c)) + n = r.size (); + } + + // Strip the value trailing spaces. + // + if (r.size () != n) + r.resize (n); + + // Find beginning of a comment (i). + // + if (i != e) + { + // Skip spaces. + // + for (++i; i != e && space (*i); ++i); + } + + return make_pair (move (r), string (i, e)); + } + void manifest_parser:: parse_name (name_value& r) { diff --git a/libbutl/manifest-parser.hxx b/libbutl/manifest-parser.hxx index fd0cc4e..f84badd 100644 --- a/libbutl/manifest-parser.hxx +++ b/libbutl/manifest-parser.hxx @@ -8,6 +8,7 @@ #include #include #include // uint64_t +#include // pair #include // runtime_error #include @@ -71,6 +72,13 @@ namespace butl manifest_name_value next (); + // Split the manifest value, optionally followed by ';' character and a + // comment into the value/comment pair. Note that ';' characters in the + // value must be escaped by the backslash. + // + static std::pair + split_comment (const std::string&); + private: void parse_name (manifest_name_value&); diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx index adb7f13..d8f640b 100644 --- a/libbutl/manifest-serializer.cxx +++ b/libbutl/manifest-serializer.cxx @@ -133,6 +133,31 @@ namespace butl os_ << endl; } + string manifest_serializer:: + merge_comment (const string& value, const string& comment) + { + string r; + for (char c: value) + { + // Escape ';' character. + // + if (c == ';') + r += '\\'; + + r += c; + } + + // Add the comment. + // + if (!comment.empty ()) + { + r += "; "; + r += comment; + } + + return r; + } + void manifest_serializer:: check_name (const string& n) { diff --git a/libbutl/manifest-serializer.hxx b/libbutl/manifest-serializer.hxx index 89c162c..d95ddf1 100644 --- a/libbutl/manifest-serializer.hxx +++ b/libbutl/manifest-serializer.hxx @@ -51,6 +51,13 @@ namespace butl void comment (const std::string&); + // Merge the manifest value and a comment into the single string, having + // the '; ' form. Escape ';' characters in the value with + // the backslash. + // + static std::string + merge_comment (const std::string& value, const std::string& comment); + private: void check_name (const std::string&); diff --git a/tests/manifest-parser/driver.cxx b/tests/manifest-parser/driver.cxx index e480508..037df96 100644 --- a/tests/manifest-parser/driver.cxx +++ b/tests/manifest-parser/driver.cxx @@ -130,6 +130,23 @@ main () {{"","1"},{"a","x\\"},{"b",""},{"",""},{"",""}})); assert (test (":1\na:\\\nx\\\\\\\n\\\nb:", {{"","1"},{"a","x\\\\"},{"b",""},{"",""},{"",""}})); + + // Manifest value splitting (into the value/comment pair). + // + { + auto p (manifest_parser::split_comment ("value\\; text ; comment text")); + assert (p.first == "value; text" && p.second == "comment text"); + } + + { + auto p (manifest_parser::split_comment ("value")); + assert (p.first == "value" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ("; comment")); + assert (p.first == "" && p.second == "comment"); + } } static ostream& diff --git a/tests/manifest-serializer/driver.cxx b/tests/manifest-serializer/driver.cxx index 69c1c71..dad96bd 100644 --- a/tests/manifest-serializer/driver.cxx +++ b/tests/manifest-serializer/driver.cxx @@ -213,6 +213,14 @@ main () ": 1\na: c:\\\\\n")); assert (test ({{"","1"},{"a","c:\\\nd:\\"},{"",""},{"",""}}, ": 1\na: \\\nc:\\\\\nd:\\\\\n\\\n")); + + // Manifest value/comment merging. + // + assert (manifest_serializer::merge_comment ("value; text", "comment") == + "value\\; text; comment"); + + assert (manifest_serializer::merge_comment ("value text", "") == + "value text"); } static string -- cgit v1.1