From b90126986fbeec6f42d469e99574096c3f6abc22 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 23 Nov 2021 21:26:20 +0300 Subject: Don't separate multi-line manifest value introducer from colon with space in manifest serializer --- libbutl/manifest-rewriter.cxx | 8 ++------ libbutl/manifest-serializer.cxx | 22 +++++++++++++-------- libbutl/manifest-serializer.hxx | 10 ++++++---- tests/manifest-rewriter/driver.cxx | 15 +++++++++++--- tests/manifest-roundtrip/manifest | 4 ++-- tests/manifest-serializer/driver.cxx | 38 ++++++++++++++++++------------------ 6 files changed, 55 insertions(+), 42 deletions(-) diff --git a/libbutl/manifest-rewriter.cxx b/libbutl/manifest-rewriter.cxx index 3bddd37..1232e9c 100644 --- a/libbutl/manifest-rewriter.cxx +++ b/libbutl/manifest-rewriter.cxx @@ -73,8 +73,6 @@ namespace butl if (!nv.value.empty ()) { - os << ' '; - manifest_serializer s (os, path_.string (), long_lines_); // Note that the name can be surrounded with the ASCII whitespace @@ -86,7 +84,7 @@ namespace butl // s.write_value (nv.value, static_cast (nv.colon_pos - nv.start_pos) - - (nv.name.size () - utf8_length (nv.name)) + 2); + (nv.name.size () - utf8_length (nv.name)) + 1); } os << suffix; @@ -118,15 +116,13 @@ namespace butl if (!nv.value.empty ()) { - os << ' '; - // Note that the name can be surrounded with the ASCII whitespace // characters and the start_pos refers to the first character in the // line. // s.write_value (nv.value, static_cast (nv.colon_pos - nv.start_pos) - - (nv.name.size () - n) + 2); + (nv.name.size () - n) + 1); } os << suffix; diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx index 8f248cf..5875052 100644 --- a/libbutl/manifest-serializer.cxx +++ b/libbutl/manifest-serializer.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -66,10 +67,7 @@ namespace butl os_ << ':'; if (!v.empty ()) - { - os_ << ' '; - write_value (v, l + 2); - } + write_value (v, l + 1); os_ << endl; break; @@ -272,6 +270,8 @@ namespace butl void manifest_serializer:: write_value (const string& v, size_t cl) { + assert (!v.empty ()); + // Consider both \r and \n characters as line separators, and the // \r\n characters sequence as a single line separator. // @@ -290,9 +290,12 @@ namespace butl // readability, still allowing the user to easily copy the value which // seems to be the main reason for using the flag. // - if (cl > 39 || nl () != string::npos || - v.front () == ' ' || v.front () == '\t' || - v.back () == ' ' || v.back () == '\t') + if (cl + 1 > 39 || // '+ 1' for the space after the colon. + nl () != string::npos || + v.front () == ' ' || + v.front () == '\t' || + v.back () == ' ' || + v.back () == '\t') { os_ << "\\" << endl; // Multi-line mode introducer. @@ -317,7 +320,10 @@ namespace butl os_ << endl << "\\"; // Multi-line mode terminator. } else - write_value (v.c_str (), v.size (), cl); + { + os_ << ' '; + write_value (v.c_str (), v.size (), cl + 1); + } } // manifest_serialization diff --git a/libbutl/manifest-serializer.hxx b/libbutl/manifest-serializer.hxx index dfe37da..43924e7 100644 --- a/libbutl/manifest-serializer.hxx +++ b/libbutl/manifest-serializer.hxx @@ -96,10 +96,12 @@ namespace butl size_t write_name (const std::string&); - // Write a value assuming the current line already has the specified - // codepoint offset. If the resulting line length would be too large then - // the multi-line representation will be used. It is assumed that the - // name, followed by the colon, is already written. + // Write a non-empty value assuming the current line already has the + // specified codepoint offset. If the resulting line length would be too + // large then the multi-line representation will be used. For the + // single-line representation the space character is written before the + // value. It is assumed that the name, followed by the colon, is already + // written. // void write_value (const std::string&, std::size_t offset); diff --git a/tests/manifest-rewriter/driver.cxx b/tests/manifest-rewriter/driver.cxx index 3e8fecb..3b1dfe9 100644 --- a/tests/manifest-rewriter/driver.cxx +++ b/tests/manifest-rewriter/driver.cxx @@ -67,17 +67,26 @@ namespace butl {{"a", "xyz"}, edit_cmd {"x", "y", "c"}, {"e", "123"}}) == ":1\na: xyz\nc:d\nx: y\ne: 123"); - assert (edit (":1\na: b", {{"a", "xy\nz"}}) == ":1\na: \\\nxy\nz\n\\"); + assert (edit (":1\na: b", {{"a", "xy\nz"}}) == ":1\na:\\\nxy\nz\n\\"); + + assert (edit (":1\na:\\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); + + assert (edit (":1\na: \\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); + + assert (edit (":1\na:\n\\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); assert (edit (":1\n", {{"a", "b", ""}}) == ":1\na: b\n"); assert (edit (":1\n abc: b", {{"abc", "xyz"}}) == - ":1\n abc: \\\nxyz\n\\"); + ":1\n abc:\\\nxyz\n\\"); assert (edit (":1\n a\xD0\xB0g : b", {{"a\xD0\xB0g", "xyz"}}) == - ":1\n a\xD0\xB0g : \\\nxyz\n\\"); + ":1\n a\xD0\xB0g :\\\nxyz\n\\"); // Test editing of manifests that contains CR characters. // diff --git a/tests/manifest-roundtrip/manifest b/tests/manifest-roundtrip/manifest index 23c2730..4926e29 100644 --- a/tests/manifest-roundtrip/manifest +++ b/tests/manifest-roundtrip/manifest @@ -7,7 +7,7 @@ tags: c++, package, manager, bpkg description: A very very very very very very very very very very very very\ very very very very very very very very very very very very very very very\ very very long description. -changes: \ +changes:\ 1.0.1 - Fixed a very very very very very very very very very very very very very\ very annoying bug. @@ -26,7 +26,7 @@ requires: ?* linux | windows requires: c++11 : path: c:\windows\\ -path: \ +path:\ c:\windows\\ \ diff --git a/tests/manifest-serializer/driver.cxx b/tests/manifest-serializer/driver.cxx index 4c09038..be3ae25 100644 --- a/tests/manifest-serializer/driver.cxx +++ b/tests/manifest-serializer/driver.cxx @@ -189,21 +189,21 @@ main () // string n ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); assert (test ({{"","1"},{n,"x"},{"",""},{"",""}}, - ": 1\n" + n + ": \\\nx\n\\\n")); + ": 1\n" + n + ":\\\nx\n\\\n")); assert (test ({{"","1"},{"a","\n"},{"",""},{"",""}}, - ": 1\na: \\\n\n\n\\\n")); + ": 1\na:\\\n\n\n\\\n")); assert (test ({{"","1"},{"a","\n\n"},{"",""},{"",""}}, - ": 1\na: \\\n\n\n\n\\\n")); + ": 1\na:\\\n\n\n\n\\\n")); assert (test ({{"","1"},{"a","\nx\n"},{"",""},{"",""}}, - ": 1\na: \\\n\nx\n\n\\\n")); + ": 1\na:\\\n\nx\n\n\\\n")); assert (test ({{"","1"},{"a","x\ny\nz"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\nz\n\\\n")); + ": 1\na:\\\nx\ny\nz\n\\\n")); assert (test ({{"","1"},{"a"," x"},{"",""},{"",""}}, - ": 1\na: \\\n x\n\\\n")); + ": 1\na:\\\n x\n\\\n")); assert (test ({{"","1"},{"a","x "},{"",""},{"",""}}, - ": 1\na: \\\nx \n\\\n")); + ": 1\na:\\\nx \n\\\n")); assert (test ({{"","1"},{"a"," x "},{"",""},{"",""}}, - ": 1\na: \\\n x \n\\\n")); + ": 1\na:\\\n x \n\\\n")); // The long lines mode. // @@ -212,42 +212,42 @@ main () true /* long_lines */)); assert (test ({{"","1"},{"a", " abc\n" + l1 + "\ndef"},{"",""},{"",""}}, - ": 1\na: \\\n abc\n" + l1 + "\ndef\n\\\n", + ": 1\na:\\\n abc\n" + l1 + "\ndef\n\\\n", true /* long_lines */)); assert (test ({{"","1"},{n,l1},{"",""},{"",""}}, - ": 1\n" + n + ": \\\n" + l1 + "\n\\\n", + ": 1\n" + n + ":\\\n" + l1 + "\n\\\n", true /* long_lines */)); // Carriage return character. // assert (test ({{"","1"},{"a","x\ry"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\n\\\n")); + ": 1\na:\\\nx\ny\n\\\n")); assert (test ({{"","1"},{"a","x\r"},{"",""},{"",""}}, - ": 1\na: \\\nx\n\n\\\n")); + ": 1\na:\\\nx\n\n\\\n")); assert (test ({{"","1"},{"a","x\r\ny"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\n\\\n")); + ": 1\na:\\\nx\ny\n\\\n")); assert (test ({{"","1"},{"a","x\r\n"},{"",""},{"",""}}, - ": 1\na: \\\nx\n\n\\\n")); + ": 1\na:\\\nx\n\n\\\n")); // Extra three x's are for the leading name part ("a: ") that we // don't have. // assert (test ({{"","1"},{"a","\nxxx" + l1},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e1 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e1 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l2},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e2 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e2 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l3},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e3 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e3 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l4},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e4 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e4 + "\n\\\n")); // Backslash escaping (simple and multi-line). // assert (test ({{"","1"},{"a","c:\\"},{"",""},{"",""}}, ": 1\na: c:\\\\\n")); assert (test ({{"","1"},{"a","c:\\\nd:\\"},{"",""},{"",""}}, - ": 1\na: \\\nc:\\\\\nd:\\\\\n\\\n")); + ": 1\na:\\\nc:\\\\\nd:\\\\\n\\\n")); // Manifest value/comment merging. // -- cgit v1.1