diff --git a/main b/main index 7cd76b9..7eb0e19 100755 Binary files a/main and b/main differ diff --git a/main.cc b/main.cc index e80c13d..a94c260 100755 --- a/main.cc +++ b/main.cc @@ -5,5 +5,12 @@ using namespace subprocess; int main() { auto p = Popen({"./script.sh"}, output{"out.txt"}); + + auto buf = check_output({"echo", "\"It works!\""}); + std::cout << buf.buf.data() << " :: " << buf.length << std::endl; + + auto buf2 = check_output("cat subprocess.hpp"); + std::cout << buf2.buf.data() << " :: " << buf2.length << std::endl; + return 0; } diff --git a/subprocess.hpp b/subprocess.hpp index 51e2138..297834e 100755 --- a/subprocess.hpp +++ b/subprocess.hpp @@ -50,6 +50,7 @@ public: namespace util { + static std::vector split(const std::string& str, const std::string& delims=" \t") { @@ -291,6 +292,31 @@ class Popen; namespace detail { +// Type trait for searching a type within +// a variadic parameter pack + +template struct param_pack{}; + +template struct has_type; + +template +struct has_type> { + static constexpr bool value = false; +}; + +template +struct has_type> { + static constexpr bool value = true; +}; + +template +struct has_type> { + static constexpr bool value = + std::is_same::type>::value ? true : has_type>::value; +}; + +//---- + struct ArgumentDeducer { ArgumentDeducer(Popen* p): popen_(p) {} @@ -478,7 +504,7 @@ public: int retcode() const noexcept { return retcode_; } - bool wait() throw(OSError); + int wait() throw(OSError); int poll() throw(OSError); @@ -567,17 +593,19 @@ void Popen::start_process() throw (CalledProcessError, OSError) execute_process(); } -bool Popen::wait() throw (OSError) +int Popen::wait() throw (OSError) { int ret, status; std::tie(ret, status) = util::wait_for_child_exit(pid()); if (ret == -1) { if (errno != ECHILD) throw OSError("waitpid failed", errno); - return true; + return 0; } - if (!WIFEXITED(status)) return false; + if (WIFEXITED(status)) return WEXITSTATUS(status); + if (WIFSIGNALED(status)) return WTERMSIG(status); + else return 255; - return true; + return 0; } int Popen::poll() throw (OSError) @@ -606,10 +634,10 @@ int Popen::poll() throw (OSError) // status. if (errno == ECHILD) retcode_ = 0; else throw OSError("waitpid failed", errno); + } else { + retcode_ = ret; } - retcode_ = ret; - return retcode_; } @@ -879,8 +907,11 @@ namespace detail { if (rbytes == -1) { throw OSError("read to obuf failed", errno); } + + obuf.length = rbytes; // Close the output stream stream_->output_.reset(); + } else if (stream_->error()) { // Same screwness applies here as well ebuf.add_cap(err_buf_cap_); @@ -893,6 +924,8 @@ namespace detail { if (rbytes == -1) { throw OSError("read to ebuf failed", errno); } + + ebuf.length = rbytes; // Close the error stream stream_->error_.reset(); } @@ -961,6 +994,40 @@ namespace detail { // Convenience Functions // +// +namespace detail +{ + template + OutBuffer check_output_impl(F& farg, Args&&... args) + { + static_assert(!detail::has_type>::value, "output not allowed in args"); + auto p = Popen(farg, std::forward(args)..., output{PIPE}); + auto res = p.communicate(nullptr, 0); + auto retcode = p.poll(); + if (retcode) { + throw CalledProcessError("Command failed"); + } + return (res.first); + } +} + +template +int call(Args&&... args) +{ + return Popen(std::forward(args)...).wait(); +} + +template +OutBuffer check_output(std::initializer_list plist, Args&&... args) +{ + return detail::check_output_impl(plist, std::forward(args)...); +} + +template +OutBuffer check_output(const std::string& arg, Args&&... args) +{ + return detail::check_output_impl(arg, std::forward(args)...); +} };