diff options
Diffstat (limited to 'libbutl')
-rw-r--r-- | libbutl/manifest-parser.cxx | 42 | ||||
-rw-r--r-- | libbutl/manifest-parser.ixx | 17 | ||||
-rw-r--r-- | libbutl/manifest-parser.mxx | 47 | ||||
-rw-r--r-- | libbutl/manifest-serializer.cxx | 21 | ||||
-rw-r--r-- | libbutl/manifest-serializer.mxx | 13 |
5 files changed, 129 insertions, 11 deletions
diff --git a/libbutl/manifest-parser.cxx b/libbutl/manifest-parser.cxx index 697273a..49b9ee0 100644 --- a/libbutl/manifest-parser.cxx +++ b/libbutl/manifest-parser.cxx @@ -10,6 +10,7 @@ #ifndef __cpp_lib_modules #include <string> +#include <vector> #include <cstdint> #include <utility> #include <stdexcept> @@ -28,6 +29,7 @@ module butl.manifest_parser; import std.core; import std.io; #endif +import butl.optional; import butl.char_scanner; import butl.manifest_types; #endif @@ -481,4 +483,44 @@ namespace butl line (0), column (0), description (d) { } + + // parse_manifest + // + static bool + try_parse_manifest (manifest_parser& p, + vector<manifest_name_value>& r, + bool allow_eos) + { + // Read the format version or eos pair. Note that the version is verified + // by the parser. + // + manifest_name_value nv (p.next ()); + + // Bail out if eos is reached and is allowed. + // + if (nv.empty () && allow_eos) + return false; + + if (!nv.name.empty () || nv.empty ()) + throw manifest_parsing (p.name (), + nv.value_line, nv.value_column, + "start of manifest expected"); + + for (nv = p.next (); !nv.empty (); nv = p.next ()) + r.push_back (move (nv)); + + return true; + } + + bool + try_parse_manifest (manifest_parser& p, vector<manifest_name_value>& r) + { + return try_parse_manifest (p, r, true /* allow_eos */); + } + + void + parse_manifest (manifest_parser& p, std::vector<manifest_name_value>& r) + { + try_parse_manifest (p, r, false /* allow_eos */); + } } diff --git a/libbutl/manifest-parser.ixx b/libbutl/manifest-parser.ixx index 4ffe3c5..1dbdcd5 100644 --- a/libbutl/manifest-parser.ixx +++ b/libbutl/manifest-parser.ixx @@ -11,4 +11,21 @@ namespace butl do { parse_next (r); } while (filter_ && !filter_ (r)); return r; } + + inline optional<std::vector<manifest_name_value>> + try_parse_manifest (manifest_parser& p) + { + std::vector<manifest_name_value> r; + return try_parse_manifest (p, r) + ? optional<std::vector<manifest_name_value>> (move (r)) + : nullopt; + } + + inline std::vector<manifest_name_value> + parse_manifest (manifest_parser& p) + { + std::vector<manifest_name_value> r; + parse_manifest (p, r); + return r; + } } diff --git a/libbutl/manifest-parser.mxx b/libbutl/manifest-parser.mxx index f39c9d2..a23d64f 100644 --- a/libbutl/manifest-parser.mxx +++ b/libbutl/manifest-parser.mxx @@ -10,6 +10,7 @@ #ifndef __cpp_lib_modules #include <string> +#include <vector> #include <iosfwd> #include <cstdint> // uint64_t #include <utility> // pair, move() @@ -25,9 +26,11 @@ export module butl.manifest_parser; import std.core; import std.io; #endif +import butl.optional; import butl.char_scanner; import butl.manifest_types; #else +#include <libbutl/optional.mxx> #include <libbutl/char-scanner.mxx> #include <libbutl/manifest-types.mxx> #endif @@ -72,16 +75,15 @@ LIBBUTL_MODEXPORT namespace butl const std::string& name () const {return name_;} - // The first returned pair is special "start-of-manifest" with - // empty name and value being the format version: {"", "<ver>"}. - // After that we have a sequence of ordinary pairs which are - // the manifest. At the end of the manifest we have the special - // "end-of-manifest" pair with empty name and value: {"", ""}. - // After that we can either get another start-of-manifest pair - // (in which case the whole sequence repeats from the beginning) - // or we get another end-of-manifest pair which signals the end - // of stream (aka EOF). To put it another way, the parse sequence - // always has the following form: + // The first returned pair is special "start-of-manifest" with empty name + // and value being the format version: {"", "<ver>"}. After that we have a + // sequence of ordinary pairs which are the manifest. At the end of the + // manifest we have the special "end-of-manifest" pair with empty name and + // value: {"", ""}. After that we can either get another start-of-manifest + // pair (in which case the whole sequence repeats from the beginning) or + // we get another end-of-manifest-like pair which signals the end of + // stream (aka EOF) and which we will call the end-of-stream pair. To put + // it another way, the parse sequence always has the following form: // // ({"", "<ver>"} {"<name>", "<value>"}* {"", ""})* {"", ""} // @@ -120,6 +122,31 @@ LIBBUTL_MODEXPORT namespace butl enum {start, body, end} s_ = start; std::string version_; // Current format version. }; + + // Parse and return a single manifest. Throw manifest_parsing in case of an + // error. + // + // Note that the returned manifest doesn't contain the format version nor + // the end-of-manifest/stream pairs. + // + LIBBUTL_SYMEXPORT std::vector<manifest_name_value> + parse_manifest (manifest_parser&); + + // As above but append the manifest values to an existing list. + // + LIBBUTL_SYMEXPORT void + parse_manifest (manifest_parser&, std::vector<manifest_name_value>&); + + // As above but return nullopt if eos is reached before reading any values. + // + LIBBUTL_SYMEXPORT optional<std::vector<manifest_name_value>> + try_parse_manifest (manifest_parser&); + + // As above but append the manifest values to an existing list returning + // false if eos is reached before reading any values. + // + LIBBUTL_SYMEXPORT bool + try_parse_manifest (manifest_parser&, std::vector<manifest_name_value>&); } #include <libbutl/manifest-parser.ixx> diff --git a/libbutl/manifest-serializer.cxx b/libbutl/manifest-serializer.cxx index 059c374..4284ec6 100644 --- a/libbutl/manifest-serializer.cxx +++ b/libbutl/manifest-serializer.cxx @@ -10,6 +10,7 @@ #ifndef __cpp_lib_modules #include <string> +#include <vector> #include <cstddef> #include <stdexcept> @@ -27,7 +28,7 @@ module butl.manifest_serializer; import std.core; import std.io; #endif -import butl.char_scanner; +import butl.manifest_types; #endif #endif @@ -319,4 +320,22 @@ namespace butl : runtime_error (format (n, d)), name (n), description (d) { } + + // serialize_manifest + // + void + serialize_manifest (manifest_serializer& s, + const vector<manifest_name_value>& nvs, + bool eos) + { + s.next ("", "1"); // Start of manifest. + + for (const manifest_name_value& nv: nvs) + s.next (nv.name, nv.value); + + s.next ("", ""); // End of manifest. + + if (eos) + s.next ("", ""); // End of stream. + } } diff --git a/libbutl/manifest-serializer.mxx b/libbutl/manifest-serializer.mxx index 1b3ace8..2a8d32e 100644 --- a/libbutl/manifest-serializer.mxx +++ b/libbutl/manifest-serializer.mxx @@ -10,6 +10,7 @@ #ifndef __cpp_lib_modules #include <string> +#include <vector> #include <iosfwd> #include <cstddef> // size_t #include <stdexcept> // runtime_error @@ -24,6 +25,9 @@ export module butl.manifest_serializer; import std.core; import std.io; #endif +import butl.manifest_types; +#else +#include <libbutl/manifest-types.mxx> #endif #include <libbutl/export.hxx> @@ -136,6 +140,15 @@ LIBBUTL_MODEXPORT namespace butl bool long_lines_; const std::function<filter_function> filter_; }; + + // Serialize a manifest to a stream adding the leading format version pair + // and the trailing end-of-manifest pair. Unless eos is false, then also + // write the end-of-stream pair. + // + LIBBUTL_SYMEXPORT void + serialize_manifest (manifest_serializer&, + const std::vector<manifest_name_value>&, + bool eos = true); } #include <libbutl/manifest-serializer.ixx> |