aboutsummaryrefslogtreecommitdiff
path: root/libbutl
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2021-11-23 19:24:00 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2021-11-24 13:59:15 +0300
commit405dfa3e28ab71d4f6b5210faba0e3600070a0f3 (patch)
treee2e1de8213968c8b299904b48a60d4914eb1487b /libbutl
parentb90126986fbeec6f42d469e99574096c3f6abc22 (diff)
Add support for new-fashioned multi-line manifest value introducer
Diffstat (limited to 'libbutl')
-rw-r--r--libbutl/manifest-parser.cxx35
-rw-r--r--libbutl/manifest-parser.hxx4
-rw-r--r--libbutl/manifest-serializer.cxx3
-rw-r--r--libbutl/manifest-serializer.hxx10
4 files changed, 47 insertions, 5 deletions
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:\<newline>').
//
bool ml (false);
if (c == '\\')
@@ -245,6 +246,38 @@ namespace butl
unget (c);
}
+ // Detect the new-fashioned multi-line mode introducer (like in
+ // 'foo:<newline>\<newline>').
+ //
+ 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<utf8_validator>
+ protected char_scanner<utf8_validator, 2>
{
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<utf8_validator>;
+ using base = char_scanner<utf8_validator, 2>;
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_function> filter = {})
+ std::function<filter_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_function> filter_;
+ bool multiline_v2_;
};
// Serialize a manifest to a stream adding the leading format version pair