1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
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)
5 
6 #ifndef BOOST_PROCESS_IO_HPP_
7 #define BOOST_PROCESS_IO_HPP_
8 
9 #include <iosfwd>
10 #include <cstdio>
11 #include <functional>
12 #include <utility>
13 #include <boost/process/detail/config.hpp>
14 #include <boost/process/pipe.hpp>
15 
16 #include <future>
17 
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>
38 #endif
39 
40 /** \file boost/process/io.hpp
41  *
42  *    Header which provides the io properties. It provides the following properties:
43  *
44 \xmlonly
45 <programlisting>
46 namespace boost {
47   namespace process {
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>;
53   }
54 }
55 </programlisting>
56 \endxmlonly
57 
58 \par File I/O
59 
60 The library allows full redirection of streams to files as shown below.
61 
62 \code{.cpp}
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);
67 \endcode
68 
69 \par Synchronous Pipe I/O
70 
71 Another way is to communicate through pipes.
72 
73 \code{.cpp}
74 pstream str;
75 child c("my_prog", std_out > str);
76 
77 int i;
78 str >> i;
79 \endcode
80 
81 Note that the pipe may also be used between several processes, like this:
82 
83 \code{.cpp}
84 pipe p;
85 child c1("nm", "a.out", std_out>p);
86 child c2("c++filt", std_in<p);
87 \endcode
88 
89 \par Asynchronous I/O
90 
91 Utilizing `boost.asio` asynchronous I/O is provided.
92 
93 \code
94 boost::asio::io_context ios;
95 std::future<std::string> output;
96 system("ls", std_out > output, ios);
97 
98 auto res = fut.get();
99 \endcode
100 
101 \note `boost/process/async.hpp` must also be included for this to work.
102 
103 \par Closing
104 
105 Stream can be closed, so nothing can be read or written.
106 
107 \code{.cpp}
108 system("foo", std_in.close());
109 \endcode
110 
111 \par Null
112 
113 Streams can be redirected to null, which means, that written date will be
114 discarded and read data will only contain `EOF`.
115 
116 \code{.cpp}
117 system("b2", std_out > null);
118 \endcode
119 
120  *
121  */
122 
123 namespace boost { namespace process { namespace detail {
124 
125 
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
131         >;
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
136         >;
137 
138 
null_tboost::process::detail::null_t139 struct null_t  {constexpr null_t() {}};
140 struct close_t;
141 
142 template<class>
143 struct std_in_
144 {
std_in_boost::process::detail::std_in_145     constexpr std_in_() {}
146 
closeboost::process::detail::std_in_147     api::close_in close() const {return api::close_in(); }
operator =boost::process::detail::std_in_148     api::close_in operator=(const close_t &) const {return api::close_in();}
operator <boost::process::detail::std_in_149     api::close_in operator<(const close_t &) const {return api::close_in();}
150 
nullboost::process::detail::std_in_151     api::null_in null() const {return api::null_in();}
operator =boost::process::detail::std_in_152     api::null_in operator=(const null_t &) const {return api::null_in();}
operator <boost::process::detail::std_in_153     api::null_in operator<(const null_t &) const {return api::null_in();}
154 
operator =boost::process::detail::std_in_155     api::file_in operator=(const boost::filesystem::path &p) const {return p;}
operator =boost::process::detail::std_in_156     api::file_in operator=(const std::string & p)            const {return p;}
operator =boost::process::detail::std_in_157     api::file_in operator=(const std::wstring &p)            const {return p;}
operator =boost::process::detail::std_in_158     api::file_in operator=(const char * p)                   const {return p;}
operator =boost::process::detail::std_in_159     api::file_in operator=(const wchar_t * p)                const {return p;}
160 
operator <boost::process::detail::std_in_161     api::file_in operator<(const boost::filesystem::path &p) const {return p;}
operator <boost::process::detail::std_in_162     api::file_in operator<(const std::string &p)             const {return p;}
operator <boost::process::detail::std_in_163     api::file_in operator<(const std::wstring &p)            const {return p;}
operator <boost::process::detail::std_in_164     api::file_in operator<(const char*p)                     const {return p;}
operator <boost::process::detail::std_in_165     api::file_in operator<(const wchar_t * p)                const {return p;}
166 
operator =boost::process::detail::std_in_167     api::file_in operator=(FILE * f)                         const {return f;}
operator <boost::process::detail::std_in_168     api::file_in operator<(FILE * f)                         const {return f;}
169 
operator =boost::process::detail::std_in_170     template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p)      const {return p;}
operator <boost::process::detail::std_in_171     template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p)      const {return p;}
operator =boost::process::detail::std_in_172     template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p)  const {return p.pipe();}
operator <boost::process::detail::std_in_173     template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p)  const {return p.pipe();}
operator =boost::process::detail::std_in_174     template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p)  const {return p.pipe();}
operator <boost::process::detail::std_in_175     template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p)  const {return p.pipe();}
176 
operator =boost::process::detail::std_in_177     api::async_pipe_in operator=(async_pipe & p) const {return p;}
operator <boost::process::detail::std_in_178     api::async_pipe_in operator<(async_pipe & p) const {return p;}
179 
180     template<typename T, typename = typename std::enable_if<
181             is_const_buffer<T>::value || is_mutable_buffer<T>::value
182             >::type>
operator =boost::process::detail::std_in_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 >
operator =boost::process::detail::std_in_185     api::async_in_buffer<T>       operator=(T       & buf) const {return buf;}
186 
187     template<typename T, typename = typename std::enable_if<
188             is_const_buffer<T>::value || is_mutable_buffer<T>::value
189             >::type>
operator <boost::process::detail::std_in_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 >
operator <boost::process::detail::std_in_192     api::async_in_buffer<T>       operator<(T       & buf) const {return buf;}
193 
194 };
195 
196 //-1 == empty.
197 //1 == stdout
198 //2 == stderr
199 template<int p1, int p2 = -1>
200 struct std_out_
201 {
std_out_boost::process::detail::std_out_202     constexpr std_out_() {}
203 
closeboost::process::detail::std_out_204     api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); }
operator =boost::process::detail::std_out_205     api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();}
operator >boost::process::detail::std_out_206     api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();}
207 
nullboost::process::detail::std_out_208     api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();}
operator =boost::process::detail::std_out_209     api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
operator >boost::process::detail::std_out_210     api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
211 
operator =boost::process::detail::std_out_212     api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
operator =boost::process::detail::std_out_213     api::file_out<p1,p2> operator=(const std::string &p)             const {return api::file_out<p1,p2>(p);}
operator =boost::process::detail::std_out_214     api::file_out<p1,p2> operator=(const std::wstring &p)            const {return api::file_out<p1,p2>(p);}
operator =boost::process::detail::std_out_215     api::file_out<p1,p2> operator=(const char * p)                   const {return api::file_out<p1,p2>(p);}
operator =boost::process::detail::std_out_216     api::file_out<p1,p2> operator=(const wchar_t * p)                const {return api::file_out<p1,p2>(p);}
217 
operator >boost::process::detail::std_out_218     api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
operator >boost::process::detail::std_out_219     api::file_out<p1,p2> operator>(const std::string &p)             const {return api::file_out<p1,p2>(p);}
operator >boost::process::detail::std_out_220     api::file_out<p1,p2> operator>(const std::wstring &p)            const {return api::file_out<p1,p2>(p);}
operator >boost::process::detail::std_out_221     api::file_out<p1,p2> operator>(const char * p)                   const {return api::file_out<p1,p2>(p);}
operator >boost::process::detail::std_out_222     api::file_out<p1,p2> operator>(const wchar_t * p)                const {return api::file_out<p1,p2>(p);}
223 
operator =boost::process::detail::std_out_224     api::file_out<p1,p2> operator=(FILE * f)  const {return f;}
operator >boost::process::detail::std_out_225     api::file_out<p1,p2> operator>(FILE * f)  const {return f;}
226 
operator =boost::process::detail::std_out_227     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p)      const {return p;}
operator >boost::process::detail::std_out_228     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p)      const {return p;}
operator =boost::process::detail::std_out_229     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p)  const {return p.pipe();}
operator >boost::process::detail::std_out_230     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p)  const {return p.pipe();}
operator =boost::process::detail::std_out_231     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p)  const {return p.pipe();}
operator >boost::process::detail::std_out_232     template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p)  const {return p.pipe();}
233 
operator =boost::process::detail::std_out_234     api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
operator >boost::process::detail::std_out_235     api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
236 
operator =boost::process::detail::std_out_237     api::async_out_buffer<p1, p2, const asio::mutable_buffer>     operator=(const asio::mutable_buffer & buf)     const {return buf;}
operator =boost::process::detail::std_out_238     api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
operator =boost::process::detail::std_out_239     api::async_out_buffer<p1, p2, asio::streambuf>               operator=(asio::streambuf & os)                   const {return os ;}
240 
operator >boost::process::detail::std_out_241     api::async_out_buffer<p1, p2, const asio::mutable_buffer>     operator>(const asio::mutable_buffer & buf)     const {return buf;}
operator >boost::process::detail::std_out_242     api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
operator >boost::process::detail::std_out_243     api::async_out_buffer<p1, p2, asio::streambuf>               operator>(asio::streambuf & os)                   const {return os ;}
244 
operator =boost::process::detail::std_out_245     api::async_out_future<p1,p2, std::string>       operator=(std::future<std::string> & fut)       const { return fut;}
operator >boost::process::detail::std_out_246     api::async_out_future<p1,p2, std::string>       operator>(std::future<std::string> & fut)       const { return fut;}
operator =boost::process::detail::std_out_247     api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
operator >boost::process::detail::std_out_248     api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
249 
250     template<int pin, typename = typename std::enable_if<
251             (((p1 == 1) && (pin == 2)) ||
252              ((p1 == 2) && (pin == 1)))
253              && (p2 == -1)>::type>
operator &boost::process::detail::std_out_254     constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
255     {
256         return std_out_<1, 2> ();
257     }
258 
259 };
260 
261 struct close_t
262 {
close_tboost::process::detail::close_t263     constexpr close_t() {}
264     template<int T, int U>
operator ()boost::process::detail::close_t265     api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
266 };
267 
268 
269 
270 }
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;
275 
276 /**
277 This property allows to set the input stream for the child process.
278 
279 \section stdin_details Details
280 
281 \subsection stdin_file File Input
282 
283 The file I/O simple redirects the stream to a file, for which the possible types are
284 
285  - `boost::filesystem::path`
286  - `std::basic_string<char_type>`
287  - `const char_type*`
288  - `FILE*`
289 
290 with `char_type` being either `char` or `wchar_t`.
291 
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:
294 
295 \code{.cpp}
296 system("ls", std_in < stdin);
297 \endcode
298 
299 \warning If the launching and the child process use the input, this leads to undefined behaviour.
300 
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.
303 
304 The valid expressions for this property are
305 
306 \code{.cpp}
307 std_in < file;
308 std_in = file;
309 \endcode
310 
311 \subsection stdin_pipe Pipe Input
312 
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.
316 
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.
321 
322 Valid expressions with pipes are these:
323 
324 \code{.cpp}
325 std_in < pipe;
326 std_in = pipe;
327 \endcode
328 
329 Where the valid types for `pipe` are the following:
330 
331  - `basic_pipe`
332  - `async_pipe`
333  - `basic_opstream`
334  - `basic_pstream`
335 
336 Note that the pipe may also be used between several processes, like this:
337 
338 \code{.cpp}
339 pipe p;
340 child c1("nm", "a.out", std_out>p);
341 child c2("c++filt", std_in<p);
342 \endcode
343 
344 \subsection stdin_async_pipe Asynchronous Pipe Input
345 
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.
350 
351 Valid types for pipe I/O are the following:
352 
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`
356 
357 Valid expressions with pipes are these:
358 
359 \code{.cpp}
360 std_in < buffer;
361 std_in = buffer;
362 std_out > buffer;
363 std_out = buffer;
364 std_err > buffer;
365 std_err = buffer;
366 (std_out & std_err) > buffer;
367 (std_out & std_err) = buffer;
368 \endcode
369 
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:
372 \code{.cpp}
373 std::future<void> fut;
374 boost::asio::io_context ios;
375 std::string data;
376 child c("prog", std_in < buffer(data) >  fut, ios);
377 fut.get();
378 \endcode
379 
380 
381 \note `boost::asio::buffer` is also available in the `boost::process` namespace.
382 
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.
384 
385 
386 \subsection stdin_close Close
387 
388 The input stream can be closed, so it cannot be read from. This will lead to an error when attempted.
389 
390 This can be achieved by the following syntax.
391 
392 \code{.cpp}
393 std_in < close;
394 std_in = close;
395 std_in.close();
396 \endcode
397 
398 \subsection stdin_null Null
399 
400 The input stream can be redirected to read from the null-device, which means that only `EOF` is read.
401 
402 The syntax to achieve that has the following variants:
403 
404 \code{.cpp}
405 std_in < null;
406 std_in = null;
407 std_in.null();
408 \endcode
409 
410 */
411 
412 constexpr boost::process::detail::std_in_<void>   std_in;
413 
414 /**
415 This property allows to set the output stream for the child process.
416 
417 \note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly
418 
419 \note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`.
420 
421 \section stdout_details Details
422 
423 \subsection stdout_file File Input
424 
425 The file I/O simple redirects the stream to a file, for which the possible types are
426 
427  - `boost::filesystem::path`
428  - `std::basic_string<char_type>`
429  - `const char_type*`
430  - `FILE*`
431 
432 with `char_type` being either `char` or `wchar_t`.
433 
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:
436 
437 \code{.cpp}
438 system("ls", std_out < stdin);
439 \endcode
440 
441 \warning If the launching and the child process use the input, this leads to undefined behaviour.
442 
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.
445 
446 The valid expressions for this property are
447 
448 \code{.cpp}
449 std_out < file;
450 std_out = file;
451 \endcode
452 
453 \subsection stdout_pipe Pipe Output
454 
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.
458 
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.
463 
464 Valid expressions with pipes are these:
465 
466 \code{.cpp}
467 std_out > pipe;
468 std_out = pipe;
469 \endcode
470 
471 Where the valid types for `pipe` are the following:
472 
473  - `basic_pipe`
474  - `async_pipe`
475  - `basic_ipstream`
476  - `basic_pstream`
477 
478 Note that the pipe may also be used between several processes, like this:
479 
480 \code{.cpp}
481 pipe p;
482 child c1("nm", "a.out", std_out>p);
483 child c2("c++filt", std_in<p);
484 \endcode
485 
486 \subsection stdout_async_pipe Asynchronous Pipe Output
487 
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.
492 
493 Valid types for pipe I/O are the following:
494 
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>`
499 
500 Valid expressions with pipes are these:
501 
502 \code{.cpp}
503 std_out > buffer;
504 std_out = buffer;
505 std_err > buffer;
506 std_err = buffer;
507 (std_out & std_err) > buffer;
508 (std_out & std_err) = buffer;
509 \endcode
510 
511 \note `boost::asio::buffer` is also available in the `boost::process` namespace.
512 
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.
514 
515 
516 \subsection stdout_close Close
517 
518 The out stream can be closed, so it cannot be write from.
519 This will lead to an error when attempted.
520 
521 This can be achieved by the following syntax.
522 
523 \code{.cpp}
524 std_out > close;
525 std_out = close;
526 std_out.close();
527 \endcode
528 
529 \subsection stdout_null Null
530 
531 The output stream can be redirected to write to the null-device,
532 which means that all output is discarded.
533 
534 The syntax to achieve that has the following variants:
535 
536 \code{.cpp}
537 std_out > null;
538 std_out = null;
539 std_out.null();
540 \endcode
541 
542 */
543 
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 .
547  */
548 constexpr boost::process::detail::std_out_<2> std_err;
549 
550 }}
551 #endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */
552