aboutsummaryrefslogtreecommitdiff
path: root/butl/process
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-04-10 13:19:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-04-10 13:19:19 +0200
commit550b5257aba507bcce98f6832b8905769a14955d (patch)
tree82804b1d214e94ceb8736f215dd20082614cbc1c /butl/process
parent0703f7a1acc9bf9512fdcad43a18a17981c8ca9e (diff)
Add process_run()/process_start() higher-level API on top of class process
Diffstat (limited to 'butl/process')
-rw-r--r--butl/process156
1 files changed, 141 insertions, 15 deletions
diff --git a/butl/process b/butl/process
index 31cb681..6f22718 100644
--- a/butl/process
+++ b/butl/process
@@ -17,31 +17,28 @@
#include <butl/path>
#include <butl/export>
#include <butl/optional>
-#include <butl/fdstream> // auto_fd
+#include <butl/fdstream> // auto_fd, fdpipe
namespace butl
{
struct process_error: std::system_error
{
- bool
- child () const {return child_;}
-
- public:
+ const bool child;
-#ifndef _WIN32
- process_error (int e, bool child)
- : system_error (e, std::generic_category ()), child_ (child) {}
-#else
process_error (int e, bool child = false)
- : system_error (e, std::generic_category ()), child_ (child) {}
+ : system_error (e, std::generic_category ()), child (child) {}
+#ifdef _WIN32
process_error (const std::string& d, int fallback_errno_code = 0)
: system_error (fallback_errno_code, std::system_category (), d),
- child_ (false) {}
+ child (false) {}
#endif
+ };
- private:
- bool child_;
+ struct process_child_error: process_error
+ {
+ explicit
+ process_child_error (int e): process_error (e, true) {}
};
// A process executable has three paths: initial, recall, and effective.
@@ -142,6 +139,8 @@ namespace butl
code_type
code () const;
+ explicit operator bool () const {return normal () && code () == 0;}
+
// Abnormal termination information.
//
#ifndef _WIN32
@@ -205,7 +204,7 @@ namespace butl
//
// Throw process_error if anything goes wrong. Note that some of the
// exceptions (e.g., if exec() failed) can be thrown in the child
- // version of us.
+ // version of us (as process_child_error).
//
// Note that the versions without the the process_path argument may
// temporarily change args[0] (see path_search() for details).
@@ -254,9 +253,12 @@ namespace butl
wait (bool ignore_errors = false);
// Return true if the process has already terminated in which case
- // the argument is set to the result of wait().
+ // optionally set the argument to the result of wait().
//
bool
+ try_wait ();
+
+ bool
try_wait (bool&);
// Note that the destructor will wait for the process but will ignore
@@ -363,8 +365,132 @@ namespace butl
auto_fd in_ofd; // Read from it to receive from stdout.
auto_fd in_efd; // Read from it to receive from stderr.
};
+
+ // Higher-level process running interface that aims to make executing a
+ // process for the common cases as simple as calling a functions. Normally
+ // it is further simplified by project-specific wrapper functions that
+ // handle the process_error exception as well as abnormal and/or non-zero
+ // exit status.
+ //
+ // The I/O/E arguments determine the child's stdin/stdout/stderr. They can
+ // be of type int, auto_fd (and, in the future, perhaps also fd_pipe,
+ // string, buffer, etc). For example, the following call will make stdin
+ // read from /dev/null, stdout redirect to stderr, and inherit the parent's
+ // stderr.
+ //
+ // process_run (..., fdnull (), 2, 2, ...)
+ //
+ // The P argument is the program path. It can be anything that can be passed
+ // to process::path_search() (const char*, std::string, path) or the
+ // process_path itself.
+ //
+ // The A arguments can be anything convertible to const char* via the
+ // overloaded process_arg_as() (see below). Out of the box you can use const
+ // char*, std::string, path/dir_path, and numeric types.
+ //
+ //
+ //
+ template <typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ process_exit
+ process_run (I&& in,
+ O&& out,
+ E&& err,
+ const dir_path& cwd,
+ const P&,
+ A&&... args);
+
+ // The version with the command callback that can be used for printing the
+ // command line or similar. It should be callable with the following
+ // signature:
+ //
+ // void (const char*[], std::size_t)
+ //
+ template <typename C,
+ typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ process_exit
+ process_run (const C&,
+ I&& in,
+ O&& out,
+ E&& err,
+ const dir_path& cwd,
+ const P&,
+ A&&... args);
+
+ // Versions that start the process without waiting.
+ //
+ template <typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ process
+ process_start (I&& in,
+ O&& out,
+ E&& err,
+ const dir_path& cwd,
+ const P&,
+ A&&... args);
+
+ template <typename C,
+ typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ process
+ process_start (const C&,
+ I&& in,
+ O&& out,
+ E&& err,
+ const dir_path& cwd,
+ const P&,
+ A&&... args);
+
+ // Conversion of types to their C string representations. Can be overloaded
+ // (including via ADL) for custom types. The default implementation calls
+ // to_string() which covers all the numeric values via std::to_string () and
+ // also any type that defines to_string() (via ADL).
+ //
+ template <typename T>
+ inline const char*
+ process_arg_as (const T& x, std::string& storage)
+ {
+ using namespace std;
+ return (storage = to_string (x)).c_str ();
+ }
+
+ inline const char*
+ process_arg_as (const std::string& s, std::string&) {return s.c_str ();}
+
+ template <typename K>
+ inline const char*
+ process_arg_as (const basic_path<char, K>& p, std::string&)
+ {
+ return p.string ().c_str ();
+ }
+
+ inline const char*
+ process_arg_as (const char* s, std::string&) {return s;}
+
+ template <std::size_t N>
+ inline const char*
+ process_arg_as (char (&s)[N], std::string&) {return s;}
+
+ template <std::size_t N>
+ inline const char*
+ process_arg_as (const char (&s)[N], std::string&) {return s;}
}
#include <butl/process.ixx>
+#include <butl/process-run.txx>
+
#endif // BUTL_PROCESS