From a32378a9aedd61c51166432ecd26a6a5dd405ebb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 1 Jun 2017 23:22:43 +0300 Subject: Treat CR specially by manifest serializer --- libbutl/char-scanner.cxx | 2 +- libbutl/manifest-serializer.cxx | 14 ++++++++++---- tests/manifest-serializer/driver.cxx | 11 +++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/libbutl/char-scanner.cxx b/libbutl/char-scanner.cxx index a2baaf3..a97ed48 100644 --- a/libbutl/char-scanner.cxx +++ b/libbutl/char-scanner.cxx @@ -34,7 +34,7 @@ namespace butl if (v == xchar::traits_type::eof ()) eos_ = true; - else if (crlf_ && v == 0x0D) + else if (crlf_ && v == '\r') { get_ (); int_type v1 (peek_ ()); diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx index 35f2d72..adb7f13 100644 --- a/libbutl/manifest-serializer.cxx +++ b/libbutl/manifest-serializer.cxx @@ -66,6 +66,11 @@ namespace butl { os_ << ' '; + // Consider both \r and \n characters as line separators, and the + // \r\n characters sequence as a single line separator. + // + auto nl = [&v] (size_t p = 0) {return v.find_first_of ("\r\n", p);}; + // Use the multi-line mode in any of the following cases: // // - name is too long (say longer than 37 (78/2 - 2) characters; @@ -74,8 +79,7 @@ namespace butl // - value contains newlines // - value contains leading/trailing whitespaces // - if (n.size () > 37 || - v.find ('\n') != string::npos || + if (n.size () > 37 || nl () != string::npos || v.front () == ' ' || v.front () == '\t' || v.back () == ' ' || v.back () == '\t') { @@ -83,7 +87,7 @@ namespace butl // Chunk the value into fragments separated by newlines. // - for (size_t i (0), p (v.find ('\n')); ; p = v.find ('\n', i)) + for (size_t i (0), p (nl ()); ; p = nl (i)) { if (p == string::npos) { @@ -95,7 +99,8 @@ namespace butl write_value (0, v.c_str () + i, p - i); os_ << endl; - i = p + 1; + + i = p + (v[p] == '\r' && v[p + 1] == '\n' ? 2 : 1); } os_ << endl << "\\"; // Multi-line mode terminator. @@ -140,6 +145,7 @@ namespace butl { case ' ': case '\t': + case '\r': case '\n': throw serialization (name_, "name contains whitespace"); case ':': throw serialization (name_, "name contains ':'"); default: break; diff --git a/tests/manifest-serializer/driver.cxx b/tests/manifest-serializer/driver.cxx index 3a8aef8..69c1c71 100644 --- a/tests/manifest-serializer/driver.cxx +++ b/tests/manifest-serializer/driver.cxx @@ -184,6 +184,17 @@ main () assert (test ({{"","1"},{"a"," x "},{"",""},{"",""}}, ": 1\na: \\\n x \n\\\n")); + // Carriage return character. + // + assert (test ({{"","1"},{"a","x\ry"},{"",""},{"",""}}, + ": 1\na: \\\nx\ny\n\\\n")); + assert (test ({{"","1"},{"a","x\r"},{"",""},{"",""}}, + ": 1\na: \\\nx\n\n\\\n")); + assert (test ({{"","1"},{"a","x\r\ny"},{"",""},{"",""}}, + ": 1\na: \\\nx\ny\n\\\n")); + assert (test ({{"","1"},{"a","x\r\n"},{"",""},{"",""}}, + ": 1\na: \\\nx\n\n\\\n")); + // Extra three x's are for the leading name part ("a: ") that we // don't have. // -- cgit v1.1