aboutsummaryrefslogtreecommitdiff
path: root/libbutl/manifest-serializer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/manifest-serializer.cxx')
-rw-r--r--libbutl/manifest-serializer.cxx153
1 files changed, 100 insertions, 53 deletions
diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx
index 6a26a15..26699e0 100644
--- a/libbutl/manifest-serializer.cxx
+++ b/libbutl/manifest-serializer.cxx
@@ -1,41 +1,13 @@
// file : libbutl/manifest-serializer.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef __cpp_modules_ts
-#include <libbutl/manifest-serializer.mxx>
-#endif
-
-#include <cassert>
-
-#ifndef __cpp_lib_modules_ts
-#include <string>
-#include <vector>
-#include <cstddef>
-#include <stdexcept>
+#include <libbutl/manifest-serializer.hxx>
#include <ostream>
-#endif
-
-// Other includes.
-
-#ifdef __cpp_modules_ts
-module butl.manifest_serializer;
-
-// Only imports additional to interface.
-#ifdef __clang__
-#ifdef __cpp_lib_modules_ts
-import std.core;
-import std.io;
-#endif
-import butl.manifest_types;
-#endif
+#include <cassert>
-import butl.utf8;
-import butl.utility;
-#else
-#include <libbutl/utf8.mxx>
-#include <libbutl/utility.mxx>
-#endif
+#include <libbutl/utf8.hxx>
+#include <libbutl/utility.hxx>
using namespace std;
@@ -95,10 +67,7 @@ namespace butl
os_ << ':';
if (!v.empty ())
- {
- os_ << ' ';
- write_value (v, l + 2);
- }
+ write_value (v, l + 1);
os_ << endl;
break;
@@ -132,22 +101,89 @@ namespace butl
merge_comment (const string& value, const string& comment)
{
string r;
- for (char c: value)
+
+ // Merge the value and comment differently depending on whether any of
+ // them is multi-line or not.
+ //
+ if (value.find ('\n') == string::npos && // Single-line.
+ comment.find ('\n') == string::npos)
{
- // Escape ';' character.
- //
- if (c == ';')
- r += '\\';
+ for (char c: value)
+ {
+ // Escape ';' and '\' characters.
+ //
+ if (c == ';' || c == '\\')
+ r += '\\';
- r += c;
- }
+ r += c;
+ }
- // Add the comment.
- //
- if (!comment.empty ())
+ // Add the comment.
+ //
+ if (!comment.empty ())
+ {
+ r += "; ";
+ r += comment;
+ }
+ }
+ else // Multi-line.
{
- r += "; ";
- r += comment;
+ // Parse the value lines and add them to the resulting value, escaping
+ // them if required.
+ //
+ // Note that we only need to escape lines which have the '\*;' form.
+ //
+ for (auto i (value.begin ()), e (value.end ()); i != e; )
+ {
+ // Find the end of the line and while at it the first non-backslash
+ // character.
+ //
+ auto le (i);
+ auto nb (e);
+ for (; le != e && *le != '\n'; ++le)
+ {
+ if (nb == e && *le != '\\')
+ nb = le;
+ }
+
+ // If the first non-backslash character is ';' and it is the last
+ // character on the line, then we need to escape the line characters.
+ // Note that we only escape ';' if it is the only character on the
+ // line. Otherwise, we only escape backslashes doubling the number of
+ // them from the left:
+ //
+ // ; -> \;
+ // \; -> \\;
+ // \\; -> \\\\;
+ // \\\; -> \\\\\\;
+ //
+ if (nb != e && *nb == ';' && nb + 1 == le)
+ r.append (nb == i ? 1 : nb - i, '\\');
+
+ // Add the line to the resulting value together with the trailing
+ // newline, if present.
+ //
+ r.append (i, le);
+
+ if (le != e)
+ r += '\n';
+
+ // If the value end is not reached then position to the beginning of
+ // the next line and to the end of the value otherwise.
+ //
+ i = (le != e ? le + 1 : e);
+ }
+
+ // Append the comment, if present.
+ //
+ if (!comment.empty ())
+ {
+ if (!r.empty ())
+ r += '\n';
+
+ r += ";\n";
+ r += comment;
+ }
}
return r;
@@ -301,6 +337,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.
//
@@ -319,11 +357,17 @@ 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 introductor.
+ if (multiline_v2_)
+ os_ << endl;
+
+ os_ << "\\" << endl; // Multi-line mode introducer.
// Chunk the value into fragments separated by newlines.
//
@@ -346,7 +390,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