1 // Copyright (c) 2016 Klemens D. Morgenstern
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #ifndef BOOST_PROCESS_IO_HPP_
7 #define BOOST_PROCESS_IO_HPP_
13 #include <boost/process/detail/config.hpp>
14 #include <boost/process/pipe.hpp>
18 #if defined(BOOST_POSIX_API)
19 #include <boost/process/detail/posix/asio_fwd.hpp>
20 #include <boost/process/detail/posix/close_in.hpp>
21 #include <boost/process/detail/posix/close_out.hpp>
22 #include <boost/process/detail/posix/null_in.hpp>
23 #include <boost/process/detail/posix/null_out.hpp>
24 #include <boost/process/detail/posix/file_in.hpp>
25 #include <boost/process/detail/posix/file_out.hpp>
26 #include <boost/process/detail/posix/pipe_in.hpp>
27 #include <boost/process/detail/posix/pipe_out.hpp>
28 #elif defined(BOOST_WINDOWS_API)
29 #include <boost/process/detail/windows/asio_fwd.hpp>
30 #include <boost/process/detail/windows/close_in.hpp>
31 #include <boost/process/detail/windows/close_out.hpp>
32 #include <boost/process/detail/windows/null_in.hpp>
33 #include <boost/process/detail/windows/null_out.hpp>
34 #include <boost/process/detail/windows/file_in.hpp>
35 #include <boost/process/detail/windows/file_out.hpp>
36 #include <boost/process/detail/windows/pipe_in.hpp>
37 #include <boost/process/detail/windows/pipe_out.hpp>
40 /** \file boost/process/io.hpp
42 * Header which provides the io properties. It provides the following properties:
48 <emphasis>unspecified</emphasis> <globalname alt="boost::process::close">close</globalname>;
49 <emphasis>unspecified</emphasis> <globalname alt="boost::process::null">null</globalname>;
50 <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_in">std_in</globalname>;
51 <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_out">std_out</globalname>;
52 <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_err">std_err</globalname>;
60 The library allows full redirection of streams to files as shown below.
63 boost::filesystem::path log = "my_log_file.txt";
64 boost::filesystem::path input = "input.txt";
65 boost::filesystem::path output = "output.txt";
66 system("my_prog", std_out>output, std_in<input, std_err>log);
69 \par Synchronous Pipe I/O
71 Another way is to communicate through pipes.
75 child c("my_prog", std_out > str);
81 Note that the pipe may also be used between several processes, like this:
85 child c1("nm", "a.out", std_out>p);
86 child c2("c++filt", std_in<p);
91 Utilizing `boost.asio` asynchronous I/O is provided.
94 boost::asio::io_context ios;
95 std::future<std::string> output;
96 system("ls", std_out > output, ios);
101 \note `boost/process/async.hpp` must also be included for this to work.
105 Stream can be closed, so nothing can be read or written.
108 system("foo", std_in.close());
113 Streams can be redirected to null, which means, that written date will be
114 discarded and read data will only contain `EOF`.
117 system("b2", std_out > null);
123 namespace boost { namespace process { namespace detail {
126 template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
127 template<typename T> using is_const_buffer =
128 std::integral_constant<bool,
129 std::is_same< boost::asio::const_buffer, T>::value |
130 std::is_base_of<boost::asio::const_buffer, T>::value
132 template<typename T> using is_mutable_buffer =
133 std::integral_constant<bool,
134 std::is_same< boost::asio::mutable_buffer, T>::value |
135 std::is_base_of<boost::asio::mutable_buffer, T>::value
139 struct null_t {constexpr null_t() {}};
145 constexpr std_in_() {}
147 api::close_in close() const {return api::close_in(); }
148 api::close_in operator=(const close_t &) const {return api::close_in();}
149 api::close_in operator<(const close_t &) const {return api::close_in();}
151 api::null_in null() const {return api::null_in();}
152 api::null_in operator=(const null_t &) const {return api::null_in();}
153 api::null_in operator<(const null_t &) const {return api::null_in();}
155 api::file_in operator=(const boost::filesystem::path &p) const {return p;}
156 api::file_in operator=(const std::string & p) const {return p;}
157 api::file_in operator=(const std::wstring &p) const {return p;}
158 api::file_in operator=(const char * p) const {return p;}
159 api::file_in operator=(const wchar_t * p) const {return p;}
161 api::file_in operator<(const boost::filesystem::path &p) const {return p;}
162 api::file_in operator<(const std::string &p) const {return p;}
163 api::file_in operator<(const std::wstring &p) const {return p;}
164 api::file_in operator<(const char*p) const {return p;}
165 api::file_in operator<(const wchar_t * p) const {return p;}
167 api::file_in operator=(FILE * f) const {return f;}
168 api::file_in operator<(FILE * f) const {return f;}
170 template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p) const {return p;}
171 template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p) const {return p;}
172 template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p) const {return p.pipe();}
173 template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p) const {return p.pipe();}
174 template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
175 template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p) const {return p.pipe();}
177 api::async_pipe_in operator=(async_pipe & p) const {return p;}
178 api::async_pipe_in operator<(async_pipe & p) const {return p;}
180 template<typename T, typename = typename std::enable_if<
181 is_const_buffer<T>::value || is_mutable_buffer<T>::value
183 api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
184 template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
185 api::async_in_buffer<T> operator=(T & buf) const {return buf;}
187 template<typename T, typename = typename std::enable_if<
188 is_const_buffer<T>::value || is_mutable_buffer<T>::value
190 api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
191 template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
192 api::async_in_buffer<T> operator<(T & buf) const {return buf;}
199 template<int p1, int p2 = -1>
202 constexpr std_out_() {}
204 api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); }
205 api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();}
206 api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();}
208 api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();}
209 api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
210 api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
212 api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
213 api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
214 api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
215 api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
216 api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
218 api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
219 api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
220 api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
221 api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
222 api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
224 api::file_out<p1,p2> operator=(FILE * f) const {return f;}
225 api::file_out<p1,p2> operator>(FILE * f) const {return f;}
227 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p) const {return p;}
228 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p) const {return p;}
229 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
230 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
231 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
232 template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p) const {return p.pipe();}
234 api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
235 api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
237 api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
238 api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
239 api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
241 api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
242 api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
243 api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
245 api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
246 api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
247 api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
248 api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
250 template<int pin, typename = typename std::enable_if<
251 (((p1 == 1) && (pin == 2)) ||
252 ((p1 == 2) && (pin == 1)))
253 && (p2 == -1)>::type>
254 constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
256 return std_out_<1, 2> ();
263 constexpr close_t() {}
264 template<int T, int U>
265 api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
271 ///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams.
272 constexpr boost::process::detail::close_t close;
273 ///This constant is a utility to redirect streams to the null-device.
274 constexpr boost::process::detail::null_t null;
277 This property allows to set the input stream for the child process.
279 \section stdin_details Details
281 \subsection stdin_file File Input
283 The file I/O simple redirects the stream to a file, for which the possible types are
285 - `boost::filesystem::path`
286 - `std::basic_string<char_type>`
290 with `char_type` being either `char` or `wchar_t`.
292 FILE* is explicitly added, so the process can easily redirect the output stream
293 of the child to another output stream of the process. That is:
296 system("ls", std_in < stdin);
299 \warning If the launching and the child process use the input, this leads to undefined behaviour.
301 A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
302 implementation not providing access to the handle.
304 The valid expressions for this property are
311 \subsection stdin_pipe Pipe Input
313 As explained in the corresponding section, the boost.process library provides a
314 @ref boost::process::async_pipe "async_pipe" class which can be
315 used to communicate with child processes.
317 \note Technically the @ref boost::process::async_pipe "async_pipe"
318 works synchronous here, since no asio implementation is used by the library here.
319 The async-operation will then however not end if the process is finished, since
320 the pipe remains open. You can use the async_close function with on_exit to fix that.
322 Valid expressions with pipes are these:
329 Where the valid types for `pipe` are the following:
336 Note that the pipe may also be used between several processes, like this:
340 child c1("nm", "a.out", std_out>p);
341 child c2("c++filt", std_in<p);
344 \subsection stdin_async_pipe Asynchronous Pipe Input
346 Asynchronous Pipe I/O classifies communication which has automatically handling
347 of the asynchronous operations by the process library. This means, that a pipe will be
348 constructed, the async_read/-write will be automatically started, and that the
349 end of the child process will also close the pipe.
351 Valid types for pipe I/O are the following:
353 - `boost::asio::const_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
354 - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
355 - `boost::asio::streambuf`
357 Valid expressions with pipes are these:
366 (std_out & std_err) > buffer;
367 (std_out & std_err) = buffer;
370 \note It is also possible to get a future for std_in, by chaining another `std::future<void>` onto it,
371 so you can wait for the input to be completed. It looks like this:
373 std::future<void> fut;
374 boost::asio::io_context ios;
376 child c("prog", std_in < buffer(data) > fut, ios);
381 \note `boost::asio::buffer` is also available in the `boost::process` namespace.
383 \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.
386 \subsection stdin_close Close
388 The input stream can be closed, so it cannot be read from. This will lead to an error when attempted.
390 This can be achieved by the following syntax.
398 \subsection stdin_null Null
400 The input stream can be redirected to read from the null-device, which means that only `EOF` is read.
402 The syntax to achieve that has the following variants:
412 constexpr boost::process::detail::std_in_<void> std_in;
415 This property allows to set the output stream for the child process.
417 \note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly
419 \note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`.
421 \section stdout_details Details
423 \subsection stdout_file File Input
425 The file I/O simple redirects the stream to a file, for which the possible types are
427 - `boost::filesystem::path`
428 - `std::basic_string<char_type>`
432 with `char_type` being either `char` or `wchar_t`.
434 FILE* is explicitly added, so the process can easily redirect the output stream
435 of the child to another output stream of the process. That is:
438 system("ls", std_out < stdin);
441 \warning If the launching and the child process use the input, this leads to undefined behaviour.
443 A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
444 implementation not providing access to the handle.
446 The valid expressions for this property are
453 \subsection stdout_pipe Pipe Output
455 As explained in the corresponding section, the boost.process library provides a
456 @ref boost::process::async_pipe "async_pipe" class which can be
457 used to communicate with child processes.
459 \note Technically the @ref boost::process::async_pipe "async_pipe"
460 works like a synchronous pipe here, since no asio implementation is used by the library here.
461 The asynchronous operation will then however not end if the process is finished, since
462 the pipe remains open. You can use the async_close function with on_exit to fix that.
464 Valid expressions with pipes are these:
471 Where the valid types for `pipe` are the following:
478 Note that the pipe may also be used between several processes, like this:
482 child c1("nm", "a.out", std_out>p);
483 child c2("c++filt", std_in<p);
486 \subsection stdout_async_pipe Asynchronous Pipe Output
488 Asynchronous Pipe I/O classifies communication which has automatically handling
489 of the async operations by the process library. This means, that a pipe will be
490 constructed, the async_read/-write will be automatically started, and that the
491 end of the child process will also close the pipe.
493 Valid types for pipe I/O are the following:
495 - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
496 - `boost::asio::streambuf`
497 - `std::future<std::vector<char>>`
498 - `std::future<std::string>`
500 Valid expressions with pipes are these:
507 (std_out & std_err) > buffer;
508 (std_out & std_err) = buffer;
511 \note `boost::asio::buffer` is also available in the `boost::process` namespace.
513 \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.
516 \subsection stdout_close Close
518 The out stream can be closed, so it cannot be write from.
519 This will lead to an error when attempted.
521 This can be achieved by the following syntax.
529 \subsection stdout_null Null
531 The output stream can be redirected to write to the null-device,
532 which means that all output is discarded.
534 The syntax to achieve that has the following variants:
544 constexpr boost::process::detail::std_out_<1> std_out;
545 /**This property allows setting the `stderr` stream. The semantic and syntax is the same as for
546 * \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly .
548 constexpr boost::process::detail::std_out_<2> std_err;
551 #endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */