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 139 struct null_t {constexpr null_t() = default;}; 140 struct close_t; 141 142 template<class> 143 struct std_in_ 144 { 145 constexpr std_in_() = default; 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 { 202 constexpr std_out_() = default; 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 { 263 constexpr close_t() = default; 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