From 258835fb4cd7338f9a0f9a758860cf1a368987dc Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Sat, 21 Jul 2018 22:15:29 +0300 Subject: Implement manifest parsing/serialization --- libbutl/manifest-serializer.bash.in | 8 +-- libbutl/manifest.cxx | 114 ++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 17 deletions(-) (limited to 'libbutl') diff --git a/libbutl/manifest-serializer.bash.in b/libbutl/manifest-serializer.bash.in index 24eac65..5b91eed 100644 --- a/libbutl/manifest-serializer.bash.in +++ b/libbutl/manifest-serializer.bash.in @@ -17,13 +17,7 @@ fi # function butl_serialize_manifest () { - # @@ TODO - #"$(butl_path)/manifest" serialize - - local n v - while IFS=: read -r -d '' n v; do - printf "$n: $v\n" - done + "$(butl_path)/manifest" serialize } # Start the manifest serialization co-process setting the following "return" diff --git a/libbutl/manifest.cxx b/libbutl/manifest.cxx index 9319b71..4c85b57 100644 --- a/libbutl/manifest.cxx +++ b/libbutl/manifest.cxx @@ -2,30 +2,80 @@ // copyright : Copyright (c) 2014-2018 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include // ios::failure, ios::*bit #include +#include +#include // size_t #include +#include // invalid_argument #include +#include #include #include using namespace std; using namespace butl; +// Set the binary translation mode for stdout. Throw ios::failure on error. +// Noop on POSIX. +// +// Note that it makes sense to set the binary mode for stdout not to litter +// the resulting manifest representation with the carriage return characters +// on Windows. +// +static void +stdout_binary () +{ + try + { + stdout_fdmode (fdstream_mode::binary); + } + catch (const invalid_argument&) + { + assert (false); // No reason to happen. + } +} + static int cmd_parse () { - //@@ TODO + using parser = manifest_parser; + using parsing = manifest_parsing; + using name_value = manifest_name_value; + + // Parse the manifest list and write its binary representation. + // + try + { + stdout_binary (); + + cin.exceptions (ios::badbit | ios::failbit); + cout.exceptions (ios::badbit | ios::failbit); - const char m[] = - ":1\0" - "name:foo\0" - "version:1.2.3\0" - "description:foo\nexecutable\0" - "depends:libfoo\0" - "depends:libbar"; // Last \0 will be added. + parser p (cin, "stdin"); - cout.write (m, sizeof (m)); + // Iterate over manifests in the list. + // + for (name_value nv (p.next ()); !nv.empty (); nv = p.next ()) + { + // Iterate over manifest name/values. + // + for (; !nv.empty (); nv = p.next ()) + cout << nv.name << ':' << nv.value << '\0' << flush; + } + } + catch (const parsing& e) + { + cerr << e << endl; + return 1; + } + catch (const ios::failure& e) + { + cerr << "error: unable to read from stdin or write to stdout: " << e + << endl; + return 1; + } return 0; } @@ -33,7 +83,51 @@ cmd_parse () static int cmd_serialize () { - //@@ TODO + using serializer = manifest_serializer; + using serialization = manifest_serialization; + + try + { + stdout_binary (); + + // Don't throw when failbit is set (getline() failed to extract any + // characters). + // + cin.exceptions (ios::badbit); + + cout.exceptions (ios::badbit | ios::failbit); + + serializer s (cout, "stdout"); + + for (string l; !eof (getline (cin, l, '\0')); ) + { + size_t p (l.find (':')); + + if (p == string::npos) + throw serialization (s.name (), "':' expected after name"); + + string n (l, 0, p); + string v (l, p + 1); + + // Validates the name. Expects the first pair to be the format version. + // Ends current and starts next manifest for the start-of-manifest pair. + // + s.next (n, v); + } + + s.next ("", ""); // End of manifest list. + } + catch (const serialization& e) + { + cerr << e << endl; + return 1; + } + catch (const ios::failure& e) + { + cerr << "error: unable to read from stdin or write to stdout: " << e + << endl; + return 1; + } return 0; } -- cgit v1.1