diff options
Diffstat (limited to 'libbutl/manifest-serializer.cxx')
-rw-r--r-- | libbutl/manifest-serializer.cxx | 153 |
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 |