== `stdio.hpp` [#stdio] The initializer for the stdio of a subprocess The subprocess stdio initializer has three members: - in for stdin - out for stdout - err for stderr If the initializer is present all three will be set for the subprocess. By default they will inherit the stdio handles from the parent process. This means that this will forward stdio to the subprocess: [source,cpp] ---- asio::io_context ctx; v2::process proc(ctx, "/bin/bash", {}, v2::process_stdio{}); ---- No constructors are provided in order to support designated initializers in later version of C++. [source,cpp] ---- asio::io_context ctx; /// C++17 v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.err=nullptr}); /// C++11 & C++14 v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr}); ---- Valid initializers for any stdio are: - `std::nullptr_t` assigning a null-device - `FILE*` any open file, including `stdin`, `stdout` and `stderr` - `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix) - any io-object with a `.native_handle()` function that is compatible with the above. E.g. a `asio::ip::tcp::socket`, or a pipe object. - a filesystem::path, which will open a readable or writable depending on the direction of the stream - an `asio::basic_writeable_pipe` for stdin or `asio::basic_readable_pipe` for stderr/stdout. When passing a `FILE*`, a `native_handle` or an io-object with a `native_handle`, the initializer will assign the handle as is to the child process. That is the file descriptor/handle gets cloned into the subprocess and used without modification. When passing a filesystem::path, the initializer will attempt to open the file and then pass the handle to the subprocess. When passing a `readable_pipe` to stdout/stderr or a `writable_pipe` to stdin by reference, the initializer to create the other side of the pipe (`writable_pipe` for stdout/stderr, `readable_pipe` for `stdin`), connect the pair and pass the native_handle to the child process. That is, these two are equivalent: .Implicit construction of the readable pipe. [source,cpp] ---- asio::io_context ctx; asio::writable_pipe wp{ctx}; // create a readable pipe internally and connect it to wp process proc{ctx, "/bin/bash", {}, process_stdio{.in=wp}}; // create it explicitly { // the pipe the child process reads from asio::readable_pipe rp{ctx}; asio::connect_pipe(rp, wp); // `rp.native_handle()` will be assigned to the child processes stdin process proc{ctx, "/bin/bash", {}, process_stdio{.in=rp}}; rp.close(); // close it so the pipe closes when the `proc exits. } ---- The explicit version allows you to assign the same `writable_pipe` to `stdout` and `stderr`: [source,cpp] ---- // the pipe the parent process reads from and both // stderr & stdout of the child process write to asio::readable_pipe rp{ctx}; asio::writable_pipe wp{ctx}; asio::connect_pipe(rp, wp); process proc{ctx, "/bin/bash", {}, process_stdio{.out=wp, .err=wp}}; wp.close(); // close it so the pipe closes when the `proc exits. ---- NOTE: If the child writes to a pipe, the parent reads from it et vice versa. [source,cpp] ---- /// The initializer for the stdio of a subprocess struct process_stdio { __implementation_defined__ in; __implementation_defined__ out; __implementation_defined__ err; }; ----