// Copyright (c) 2016 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PROCESS_IO_HPP_ #define BOOST_PROCESS_IO_HPP_ #include #include #include #include #include #include #include #if defined(BOOST_POSIX_API) #include #include #include #include #include #include #include #include #include #elif defined(BOOST_WINDOWS_API) #include #include #include #include #include #include #include #include #include #endif /** \file boost/process/io.hpp * * Header which provides the io properties. It provides the following properties: * \xmlonly namespace boost { namespace process { unspecified close; unspecified null; unspecified std_in; unspecified std_out; unspecified std_err; } } \endxmlonly \par File I/O The library allows full redirection of streams to files as shown below. \code{.cpp} boost::filesystem::path log = "my_log_file.txt"; boost::filesystem::path input = "input.txt"; boost::filesystem::path output = "output.txt"; system("my_prog", std_out>output, std_inlog); \endcode \par Synchronous Pipe I/O Another way is to communicate through pipes. \code{.cpp} pstream str; child c("my_prog", std_out > str); int i; str >> i; \endcode Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in output; system("ls", std_out > output, ios); auto res = fut.get(); \endcode \note `boost/process/async.hpp` must also be included for this to work. \par Closing Stream can be closed, so nothing can be read or written. \code{.cpp} system("foo", std_in.close()); \endcode \par Null Streams can be redirected to null, which means, that written date will be discarded and read data will only contain `EOF`. \code{.cpp} system("b2", std_out > null); \endcode * */ namespace boost { namespace process { namespace detail { template using is_streambuf = typename std::is_same::type; template using is_const_buffer = std::integral_constant::value | std::is_base_of::value >; template using is_mutable_buffer = std::integral_constant::value | std::is_base_of::value >; struct null_t {constexpr null_t() {}}; struct close_t; template struct std_in_ { constexpr std_in_() {} api::close_in close() const {return api::close_in(); } api::close_in operator=(const close_t &) const {return api::close_in();} api::close_in operator<(const close_t &) const {return api::close_in();} api::null_in null() const {return api::null_in();} api::null_in operator=(const null_t &) const {return api::null_in();} api::null_in operator<(const null_t &) const {return api::null_in();} api::file_in operator=(const boost::filesystem::path &p) const {return p;} api::file_in operator=(const std::string & p) const {return p;} api::file_in operator=(const std::wstring &p) const {return p;} api::file_in operator=(const char * p) const {return p;} api::file_in operator=(const wchar_t * p) const {return p;} api::file_in operator<(const boost::filesystem::path &p) const {return p;} api::file_in operator<(const std::string &p) const {return p;} api::file_in operator<(const std::wstring &p) const {return p;} api::file_in operator<(const char*p) const {return p;} api::file_in operator<(const wchar_t * p) const {return p;} api::file_in operator=(FILE * f) const {return f;} api::file_in operator<(FILE * f) const {return f;} template api::pipe_in operator=(basic_pipe & p) const {return p;} template api::pipe_in operator<(basic_pipe & p) const {return p;} template api::pipe_in operator=(basic_opstream & p) const {return p.pipe();} template api::pipe_in operator<(basic_opstream & p) const {return p.pipe();} template api::pipe_in operator=(basic_pstream & p) const {return p.pipe();} template api::pipe_in operator<(basic_pstream & p) const {return p.pipe();} api::async_pipe_in operator=(async_pipe & p) const {return p;} api::async_pipe_in operator<(async_pipe & p) const {return p;} template::value || is_mutable_buffer::value >::type> api::async_in_buffer operator=(const T & buf) const {return buf;} template::value>::type > api::async_in_buffer operator=(T & buf) const {return buf;} template::value || is_mutable_buffer::value >::type> api::async_in_buffer operator<(const T & buf) const {return buf;} template::value>::type > api::async_in_buffer operator<(T & buf) const {return buf;} }; //-1 == empty. //1 == stdout //2 == stderr template struct std_out_ { constexpr std_out_() {} api::close_out close() const {return api::close_out(); } api::close_out operator=(const close_t &) const {return api::close_out();} api::close_out operator>(const close_t &) const {return api::close_out();} api::null_out null() const {return api::null_out();} api::null_out operator=(const null_t &) const {return api::null_out();} api::null_out operator>(const null_t &) const {return api::null_out();} api::file_out operator=(const boost::filesystem::path &p) const {return api::file_out(p);} api::file_out operator=(const std::string &p) const {return api::file_out(p);} api::file_out operator=(const std::wstring &p) const {return api::file_out(p);} api::file_out operator=(const char * p) const {return api::file_out(p);} api::file_out operator=(const wchar_t * p) const {return api::file_out(p);} api::file_out operator>(const boost::filesystem::path &p) const {return api::file_out(p);} api::file_out operator>(const std::string &p) const {return api::file_out(p);} api::file_out operator>(const std::wstring &p) const {return api::file_out(p);} api::file_out operator>(const char * p) const {return api::file_out(p);} api::file_out operator>(const wchar_t * p) const {return api::file_out(p);} api::file_out operator=(FILE * f) const {return f;} api::file_out operator>(FILE * f) const {return f;} template api::pipe_out operator=(basic_pipe & p) const {return p;} template api::pipe_out operator>(basic_pipe & p) const {return p;} template api::pipe_out operator=(basic_ipstream & p) const {return p.pipe();} template api::pipe_out operator>(basic_ipstream & p) const {return p.pipe();} template api::pipe_out operator=(basic_pstream & p) const {return p.pipe();} template api::pipe_out operator>(basic_pstream & p) const {return p.pipe();} api::async_pipe_out operator=(async_pipe & p) const {return p;} api::async_pipe_out operator>(async_pipe & p) const {return p;} api::async_out_buffer operator=(const asio::mutable_buffer & buf) const {return buf;} api::async_out_buffer operator=(const asio::mutable_buffers_1 & buf) const {return buf;} api::async_out_buffer operator=(asio::streambuf & os) const {return os ;} api::async_out_buffer operator>(const asio::mutable_buffer & buf) const {return buf;} api::async_out_buffer operator>(const asio::mutable_buffers_1 & buf) const {return buf;} api::async_out_buffer operator>(asio::streambuf & os) const {return os ;} api::async_out_future operator=(std::future & fut) const { return fut;} api::async_out_future operator>(std::future & fut) const { return fut;} api::async_out_future> operator=(std::future> & fut) const { return fut;} api::async_out_future> operator>(std::future> & fut) const { return fut;} template::type> constexpr std_out_<1, 2> operator& (const std_out_&) const { return std_out_<1, 2> (); } }; struct close_t { constexpr close_t() {} template api::close_out operator()(std_out_) {return api::close_out();} }; } ///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams. constexpr boost::process::detail::close_t close; ///This constant is a utility to redirect streams to the null-device. constexpr boost::process::detail::null_t null; /** This property allows to set the input stream for the child process. \section stdin_details Details \subsection stdin_file File Input The file I/O simple redirects the stream to a file, for which the possible types are - `boost::filesystem::path` - `std::basic_string` - `const char_type*` - `FILE*` with `char_type` being either `char` or `wchar_t`. FILE* is explicitly added, so the process can easily redirect the output stream of the child to another output stream of the process. That is: \code{.cpp} system("ls", std_in < stdin); \endcode \warning If the launching and the child process use the input, this leads to undefined behaviour. A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++ implementation not providing access to the handle. The valid expressions for this property are \code{.cpp} std_in < file; std_in = file; \endcode \subsection stdin_pipe Pipe Input As explained in the corresponding section, the boost.process library provides a @ref boost::process::async_pipe "async_pipe" class which can be used to communicate with child processes. \note Technically the @ref boost::process::async_pipe "async_pipe" works synchronous here, since no asio implementation is used by the library here. The async-operation will then however not end if the process is finished, since the pipe remains open. You can use the async_close function with on_exit to fix that. Valid expressions with pipes are these: \code{.cpp} std_in < pipe; std_in = pipe; \endcode Where the valid types for `pipe` are the following: - `basic_pipe` - `async_pipe` - `basic_opstream` - `basic_pstream` Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in Constructed with boost::asio::buffer \endxmlonly - `boost::asio::mutable_buffer` \xmlonly Constructed with boost::asio::buffer \endxmlonly - `boost::asio::streambuf` Valid expressions with pipes are these: \code{.cpp} std_in < buffer; std_in = buffer; std_out > buffer; std_out = buffer; std_err > buffer; std_err = buffer; (std_out & std_err) > buffer; (std_out & std_err) = buffer; \endcode \note It is also possible to get a future for std_in, by chaining another `std::future` onto it, so you can wait for the input to be completed. It looks like this: \code{.cpp} std::future fut; boost::asio::io_context ios; std::string data; child c("prog", std_in < buffer(data) > fut, ios); fut.get(); \endcode \note `boost::asio::buffer` is also available in the `boost::process` namespace. \warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function. \subsection stdin_close Close The input stream can be closed, so it cannot be read from. This will lead to an error when attempted. This can be achieved by the following syntax. \code{.cpp} std_in < close; std_in = close; std_in.close(); \endcode \subsection stdin_null Null The input stream can be redirected to read from the null-device, which means that only `EOF` is read. The syntax to achieve that has the following variants: \code{.cpp} std_in < null; std_in = null; std_in.null(); \endcode */ constexpr boost::process::detail::std_in_ std_in; /** This property allows to set the output stream for the child process. \note The Semantic is the same as for \xmlonly std_err \endxmlonly \note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`. \section stdout_details Details \subsection stdout_file File Input The file I/O simple redirects the stream to a file, for which the possible types are - `boost::filesystem::path` - `std::basic_string` - `const char_type*` - `FILE*` with `char_type` being either `char` or `wchar_t`. FILE* is explicitly added, so the process can easily redirect the output stream of the child to another output stream of the process. That is: \code{.cpp} system("ls", std_out < stdin); \endcode \warning If the launching and the child process use the input, this leads to undefined behaviour. A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++ implementation not providing access to the handle. The valid expressions for this property are \code{.cpp} std_out < file; std_out = file; \endcode \subsection stdout_pipe Pipe Output As explained in the corresponding section, the boost.process library provides a @ref boost::process::async_pipe "async_pipe" class which can be used to communicate with child processes. \note Technically the @ref boost::process::async_pipe "async_pipe" works like a synchronous pipe here, since no asio implementation is used by the library here. The asynchronous operation will then however not end if the process is finished, since the pipe remains open. You can use the async_close function with on_exit to fix that. Valid expressions with pipes are these: \code{.cpp} std_out > pipe; std_out = pipe; \endcode Where the valid types for `pipe` are the following: - `basic_pipe` - `async_pipe` - `basic_ipstream` - `basic_pstream` Note that the pipe may also be used between several processes, like this: \code{.cpp} pipe p; child c1("nm", "a.out", std_out>p); child c2("c++filt", std_in Constructed with boost::asio::buffer \endxmlonly - `boost::asio::streambuf` - `std::future>` - `std::future` Valid expressions with pipes are these: \code{.cpp} std_out > buffer; std_out = buffer; std_err > buffer; std_err = buffer; (std_out & std_err) > buffer; (std_out & std_err) = buffer; \endcode \note `boost::asio::buffer` is also available in the `boost::process` namespace. \warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function. \subsection stdout_close Close The out stream can be closed, so it cannot be write from. This will lead to an error when attempted. This can be achieved by the following syntax. \code{.cpp} std_out > close; std_out = close; std_out.close(); \endcode \subsection stdout_null Null The output stream can be redirected to write to the null-device, which means that all output is discarded. The syntax to achieve that has the following variants: \code{.cpp} std_out > null; std_out = null; std_out.null(); \endcode */ constexpr boost::process::detail::std_out_<1> std_out; /**This property allows setting the `stderr` stream. The semantic and syntax is the same as for * \xmlonly std_out \endxmlonly . */ constexpr boost::process::detail::std_out_<2> std_err; }} #endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */