diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-04-10 13:19:19 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-04-10 13:19:19 +0200 |
commit | 550b5257aba507bcce98f6832b8905769a14955d (patch) | |
tree | 82804b1d214e94ceb8736f215dd20082614cbc1c /butl/process | |
parent | 0703f7a1acc9bf9512fdcad43a18a17981c8ca9e (diff) |
Add process_run()/process_start() higher-level API on top of class process
Diffstat (limited to 'butl/process')
-rw-r--r-- | butl/process | 156 |
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 |