// file : libbutl/process-run.txx -*- C++ -*- // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include #include // forward(), index_sequence namespace butl { template process_env:: process_env (const process_path& p, const V& v) : process_env (p) { if (!v.empty ()) { std::string storage; process_args_as (vars_, v, storage); assert (storage.empty ()); // We don't expect the storage to be used. vars_.push_back (nullptr); vars = vars_.data (); } } inline int process_stdin (int v) {assert (v >= 0); return v;} inline int process_stdout (int v) {assert (v >= 0); return v;} inline int process_stderr (int v) {assert (v >= 0); return v;} inline int process_stdin (const auto_fd& v) {assert (v.get () >= 0); return v.get ();} inline int process_stdout (const auto_fd& v) {assert (v.get () >= 0); return v.get ();} inline int process_stderr (const auto_fd& v) {assert (v.get () >= 0); return v.get ();} LIBBUTL_SYMEXPORT process process_start (const dir_path* cwd, const process_path& pp, const char* cmd[], const char* const* envvars, int in, int out, int err); template inline const char* process_args_as_wrapper (V& v, const T& x, std::string& storage) { process_args_as (v, x, storage); return nullptr; } template process process_start (std::index_sequence, const C& cmdc, I&& in, O&& out, E&& err, const process_env& env, A&&... args) { // Map stdin/stdout/stderr arguments to their integer values, as expected // by the process constructor. // int in_i (process_stdin (std::forward (in))); int out_i (process_stdout (std::forward (out))); int err_i (process_stderr (std::forward (err))); // Construct the command line array. // const std::size_t args_size (sizeof... (args)); small_vector cmd; assert (env.path != nullptr); cmd.push_back (env.path->recall_string ()); std::string storage[args_size != 0 ? args_size : 1]; const char* dummy[] = { nullptr, process_args_as_wrapper (cmd, args, storage[index])... }; cmd.push_back (dummy[0]); // NULL (and get rid of unused warning). cmdc (cmd.data (), cmd.size ()); // @@ Do we need to make sure certain fd's are closed before calling // wait()? Is this only the case with pipes? Needs thinking. return process_start (env.cwd, *env.path, cmd.data (), env.vars, in_i, out_i, err_i); } template inline process process_start_callback (const C& cmdc, I&& in, O&& out, E&& err, const process_env& env, A&&... args) { return process_start (std::index_sequence_for (), cmdc, std::forward (in), std::forward (out), std::forward (err), env, std::forward (args)...); } template inline process process_start (I&& in, O&& out, E&& err, const process_env& env, A&&... args) { return process_start_callback ([] (const char* [], std::size_t) {}, std::forward (in), std::forward (out), std::forward (err), env, std::forward (args)...); } template inline process_exit process_run_callback (const C& cmdc, I&& in, O&& out, E&& err, const process_env& env, A&&... args) { process pr ( process_start_callback (cmdc, std::forward (in), std::forward (out), std::forward (err), env, std::forward (args)...)); pr.wait (); return *pr.exit; } template inline process_exit process_run (I&& in, O&& out, E&& err, const process_env& env, A&&... args) { return process_run_callback ([] (const char* [], std::size_t) {}, std::forward (in), std::forward (out), std::forward (err), env, std::forward (args)...); } }