From 405dfa3e28ab71d4f6b5210faba0e3600070a0f3 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 23 Nov 2021 19:24:00 +0300 Subject: Add support for new-fashioned multi-line manifest value introducer --- libbutl/manifest-parser.cxx | 35 ++++++++++++++++++++++++++++++++++- libbutl/manifest-parser.hxx | 4 ++-- libbutl/manifest-serializer.cxx | 3 +++ libbutl/manifest-serializer.hxx | 10 ++++++++-- 4 files changed, 47 insertions(+), 5 deletions(-) (limited to 'libbutl') diff --git a/libbutl/manifest-parser.cxx b/libbutl/manifest-parser.cxx index 1cb0ec7..ae0d43d 100644 --- a/libbutl/manifest-parser.cxx +++ b/libbutl/manifest-parser.cxx @@ -222,7 +222,8 @@ namespace butl string& v (r.value); string::size_type n (0); // Size of last non-space character (simple mode). - // Detect the multi-line mode introducer. + // Detect the old-fashioned multi-line mode introducer (like in + // 'foo:\'). // bool ml (false); if (c == '\\') @@ -245,6 +246,38 @@ namespace butl unget (c); } + // Detect the new-fashioned multi-line mode introducer (like in + // 'foo:\'). + // + if (!ml && c == '\n') + { + get (); + xchar p1 (peek ()); + + if (p1 == '\\') + { + get (); + xchar p2 (peek ()); + + if (p2 == '\n') + { + get (); // Newline is not part of the value so skip it. + c = peek (); + ml = true; + } + else if (eos (p2)) + { + c = p2; // Set to EOF. + ml = true; + } + else + unget (p1); // Unget '\\'. Note: '\n' will be ungot below. + } + + if (!ml) + unget (c); // Unget '\n'. + } + // Multi-line value starts from the line that follows the name. // if (ml) diff --git a/libbutl/manifest-parser.hxx b/libbutl/manifest-parser.hxx index d53eb42..601fb2d 100644 --- a/libbutl/manifest-parser.hxx +++ b/libbutl/manifest-parser.hxx @@ -37,7 +37,7 @@ namespace butl }; class LIBBUTL_SYMEXPORT manifest_parser: - protected char_scanner + protected char_scanner { public: // The filter, if specified, is called by next() prior to returning the @@ -83,7 +83,7 @@ namespace butl split_comment (const std::string&); private: - using base = char_scanner; + using base = char_scanner; void parse_next (manifest_name_value&); diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx index 5875052..b0d0324 100644 --- a/libbutl/manifest-serializer.cxx +++ b/libbutl/manifest-serializer.cxx @@ -297,6 +297,9 @@ namespace butl v.back () == ' ' || v.back () == '\t') { + if (multiline_v2_) + os_ << endl; + os_ << "\\" << endl; // Multi-line mode introducer. // Chunk the value into fragments separated by newlines. diff --git a/libbutl/manifest-serializer.hxx b/libbutl/manifest-serializer.hxx index 43924e7..2159901 100644 --- a/libbutl/manifest-serializer.hxx +++ b/libbutl/manifest-serializer.hxx @@ -45,14 +45,19 @@ namespace butl // Unless long_lines is true, break lines in values (including multi-line) // so that their length does not exceed 78 codepoints (including '\n'). // + // Note that the multiline_v2 flag is temporary and should not be used + // except by the implementation for testing. + // manifest_serializer (std::ostream& os, const std::string& name, bool long_lines = false, - std::function filter = {}) + std::function filter = {}, + bool multiline_v2 = false) : os_ (os), name_ (name), long_lines_ (long_lines), - filter_ (std::move (filter)) + filter_ (std::move (filter)), + multiline_v2_ (multiline_v2) { } @@ -123,6 +128,7 @@ namespace butl const std::string name_; bool long_lines_; const std::function filter_; + bool multiline_v2_; }; // Serialize a manifest to a stream adding the leading format version pair -- cgit v1.1