rename to subprocess_stream/error

master
Daniel Kolesa 2017-05-11 23:57:04 +02:00
parent 5fc674e4d3
commit 005485f6a6
3 changed files with 67 additions and 67 deletions

View File

@ -84,7 +84,7 @@ Sink &&split_args(Sink &&out, string_range str) {
} }
/** @brief Thrown on errors in ostd::subprocess. */ /** @brief Thrown on errors in ostd::subprocess. */
struct process_error: std::runtime_error { struct subprocess_error: std::runtime_error {
using std::runtime_error::runtime_error; using std::runtime_error::runtime_error;
}; };
@ -97,7 +97,7 @@ struct process_error: std::runtime_error {
* *
* Only use the `STDOUT` value for stderr stream. * Only use the `STDOUT` value for stderr stream.
*/ */
enum class process_stream { enum class subprocess_stream {
DEFAULT = 0, ///< Do not perform any redirection. DEFAULT = 0, ///< Do not perform any redirection.
PIPE, ///< Capture the stream as an ostd::file_stream. PIPE, ///< Capture the stream as an ostd::file_stream.
STDOUT ///< Writes to stderr will be written to stdout. STDOUT ///< Writes to stderr will be written to stdout.
@ -114,7 +114,7 @@ enum class process_stream {
struct OSTD_EXPORT subprocess { struct OSTD_EXPORT subprocess {
/** @brief The standard input redirection mode. /** @brief The standard input redirection mode.
* *
* The value is one of ostd::process_stream. Set this before opening * The value is one of ostd::subprocess_stream. Set this before opening
* the subprocess. If it's set to `PIPE`, you will be able to write * the subprocess. If it's set to `PIPE`, you will be able to write
* into the standard input of the child process using the `in` member, * into the standard input of the child process using the `in` member,
* which is a standard ostd::file_stream. Never set it to `STDOUT` * which is a standard ostd::file_stream. Never set it to `STDOUT`
@ -124,11 +124,11 @@ struct OSTD_EXPORT subprocess {
* @see ostd::subprocess::in, ostd::subprocess::use_out, * @see ostd::subprocess::in, ostd::subprocess::use_out,
* ostd::subprocess::use_err * ostd::subprocess::use_err
*/ */
process_stream use_in = process_stream::DEFAULT; subprocess_stream use_in = subprocess_stream::DEFAULT;
/** @brief The standard output redirection mode. /** @brief The standard output redirection mode.
* *
* The value is one of ostd::process_stream. Set this before opening * The value is one of ostd::subprocess_stream. Set this before opening
* the subprocess. If it's set to `PIPE`, you will be able to read * the subprocess. If it's set to `PIPE`, you will be able to read
* from the standard output of the child process using the `out` member, * from the standard output of the child process using the `out` member,
* which is a standard ostd::file_stream. Setting this to `STDOUT` has * which is a standard ostd::file_stream. Setting this to `STDOUT` has
@ -137,11 +137,11 @@ struct OSTD_EXPORT subprocess {
* @see ostd::subprocess::out, ostd::subprocess::use_in, * @see ostd::subprocess::out, ostd::subprocess::use_in,
* ostd::subprocess::use_err * ostd::subprocess::use_err
*/ */
process_stream use_out = process_stream::DEFAULT; subprocess_stream use_out = subprocess_stream::DEFAULT;
/** @brief The standard error redirection mode. /** @brief The standard error redirection mode.
* *
* The value is one of ostd::process_stream. Set this before opening * The value is one of ostd::subprocess_stream. Set this before opening
* the subprocess. If it's set to `PIPE`, you will be able to read * the subprocess. If it's set to `PIPE`, you will be able to read
* from the standard error of the child process using the `err` member, * from the standard error of the child process using the `err` member,
* which is a standard ostd::file_stream. Setting this to `STDOUT` * which is a standard ostd::file_stream. Setting this to `STDOUT`
@ -153,7 +153,7 @@ struct OSTD_EXPORT subprocess {
* @see ostd::subprocess::err, ostd::subprocess::use_in, * @see ostd::subprocess::err, ostd::subprocess::use_in,
* ostd::subprocess::use_out * ostd::subprocess::use_out
*/ */
process_stream use_err = process_stream::DEFAULT; subprocess_stream use_err = subprocess_stream::DEFAULT;
/** @brief The standard input stream when redirected. /** @brief The standard input stream when redirected.
* *
@ -184,9 +184,9 @@ struct OSTD_EXPORT subprocess {
/** @brief Initializes the structure with the given stream redirections. */ /** @brief Initializes the structure with the given stream redirections. */
subprocess( subprocess(
process_stream in_use = process_stream::DEFAULT, subprocess_stream in_use = subprocess_stream::DEFAULT,
process_stream out_use = process_stream::DEFAULT, subprocess_stream out_use = subprocess_stream::DEFAULT,
process_stream err_use = process_stream::DEFAULT subprocess_stream err_use = subprocess_stream::DEFAULT
) noexcept: ) noexcept:
use_in(in_use), use_out(out_use), use_err(err_use) use_in(in_use), use_out(out_use), use_err(err_use)
{} {}
@ -200,9 +200,9 @@ struct OSTD_EXPORT subprocess {
template<typename InputRange> template<typename InputRange>
subprocess( subprocess(
string_range cmd, InputRange &&args, bool use_path = true, string_range cmd, InputRange &&args, bool use_path = true,
process_stream in_use = process_stream::DEFAULT, subprocess_stream in_use = subprocess_stream::DEFAULT,
process_stream out_use = process_stream::DEFAULT, subprocess_stream out_use = subprocess_stream::DEFAULT,
process_stream err_use = process_stream::DEFAULT, subprocess_stream err_use = subprocess_stream::DEFAULT,
std::enable_if_t< std::enable_if_t<
is_input_range<InputRange>, bool is_input_range<InputRange>, bool
> = true > = true
@ -221,9 +221,9 @@ struct OSTD_EXPORT subprocess {
template<typename InputRange> template<typename InputRange>
subprocess( subprocess(
InputRange &&args, bool use_path = true, InputRange &&args, bool use_path = true,
process_stream in_use = process_stream::DEFAULT, subprocess_stream in_use = subprocess_stream::DEFAULT,
process_stream out_use = process_stream::DEFAULT, subprocess_stream out_use = subprocess_stream::DEFAULT,
process_stream err_use = process_stream::DEFAULT, subprocess_stream err_use = subprocess_stream::DEFAULT,
std::enable_if_t< std::enable_if_t<
is_input_range<InputRange>, bool is_input_range<InputRange>, bool
> = true > = true
@ -273,21 +273,21 @@ struct OSTD_EXPORT subprocess {
} }
try { try {
close(); close();
} catch (process_error const &) {} } catch (subprocess_error const &) {}
reset(); reset();
} }
/** @brief Waits for a currently running child process to be done. /** @brief Waits for a currently running child process to be done.
* *
* If there isn't any child process assigned to this, it will throw * If there isn't any child process assigned to this, it will throw
* ostd::process_error. It will also throw the same exception if some * ostd::subprocess_error. It will also throw the same exception if
* other error has occured. It will not throw if the command has * some other error has occured. It will not throw if the command has
* executed but exited with a non-zero code. This code will be * executed but exited with a non-zero code. This code will be
* returned instead. * returned instead.
* *
* @returns The child process return code on success. * @returns The child process return code on success.
* *
* @throws ostd::process_error on failure of any kind. * @throws ostd::subprocess_error on failure of any kind.
* *
* @see open_path(), open_command() * @see open_path(), open_command()
*/ */
@ -302,13 +302,13 @@ struct OSTD_EXPORT subprocess {
* *
* If `path` is empty, the first element of `args` is used. * If `path` is empty, the first element of `args` is used.
* *
* If this fails, ostd::process_error will be thrown. * If this fails, ostd::subprocess_error will be thrown.
* *
* On success, a new subprocess will be created and this will return * On success, a new subprocess will be created and this will return
* without waiting for it to finish. Use close() to wait and get the * without waiting for it to finish. Use close() to wait and get the
* return code. * return code.
* *
* @throws ostd::process_error on failure of any kind. * @throws ostd::subprocess_error on failure of any kind.
* *
* @see open_command(), close() * @see open_command(), close()
*/ */
@ -334,13 +334,13 @@ struct OSTD_EXPORT subprocess {
* *
* If `cmd` is empty, the first element of `args` is used. * If `cmd` is empty, the first element of `args` is used.
* *
* If this fails, ostd::process_error will be thrown. * If this fails, ostd::subprocess_error will be thrown.
* *
* On success, a new subprocess will be created and this will return * On success, a new subprocess will be created and this will return
* without waiting for it to finish. Use close() to wait and get the * without waiting for it to finish. Use close() to wait and get the
* return code. * return code.
* *
* @throws ostd::process_error on failure of any kind. * @throws ostd::subprocess_error on failure of any kind.
* *
* @see open_path(), close() * @see open_path(), close()
*/ */
@ -367,12 +367,12 @@ private:
argv.emplace_back(args.front()); argv.emplace_back(args.front());
} }
if (argv.empty()) { if (argv.empty()) {
throw process_error{"no arguments given"}; throw subprocess_error{"no arguments given"};
} }
if (cmd.empty()) { if (cmd.empty()) {
cmd = argv[0]; cmd = argv[0];
if (cmd.empty()) { if (cmd.empty()) {
throw process_error{"no command given"}; throw subprocess_error{"no command given"};
} }
} }
open_impl(std::string{cmd}, argv, use_path); open_impl(std::string{cmd}, argv, use_path);

View File

@ -88,12 +88,12 @@ struct pipe {
} }
} }
void open(process_stream use) { void open(subprocess_stream use) {
if (use != process_stream::PIPE) { if (use != subprocess_stream::PIPE) {
return; return;
} }
if (::pipe(fd) < 0) { if (::pipe(fd) < 0) {
throw process_error{"could not open pipe"}; throw subprocess_error{"could not open pipe"};
} }
} }
@ -104,7 +104,7 @@ struct pipe {
void fdopen(file_stream &s, bool write) { void fdopen(file_stream &s, bool write) {
FILE *p = ::fdopen(fd[std::size_t(write)], write ? "w" : "r"); FILE *p = ::fdopen(fd[std::size_t(write)], write ? "w" : "r");
if (!p) { if (!p) {
throw process_error{"could not open redirected stream"}; throw subprocess_error{"could not open redirected stream"};
} }
/* do not close twice, the stream will close it */ /* do not close twice, the stream will close it */
fd[std::size_t(write)] = -1; fd[std::size_t(write)] = -1;
@ -135,8 +135,8 @@ OSTD_EXPORT void subprocess::open_impl(
std::string const &cmd, std::vector<std::string> const &args, std::string const &cmd, std::vector<std::string> const &args,
bool use_path bool use_path
) { ) {
if (use_in == process_stream::STDOUT) { if (use_in == subprocess_stream::STDOUT) {
throw process_error{"could not redirect stdin to stdout"}; throw subprocess_error{"could not redirect stdin to stdout"};
} }
auto argp = std::make_unique<char *[]>(args.size() + 1); auto argp = std::make_unique<char *[]>(args.size() + 1);
@ -148,14 +148,14 @@ OSTD_EXPORT void subprocess::open_impl(
/* fd_errno used to detect if exec failed */ /* fd_errno used to detect if exec failed */
pipe fd_errno, fd_stdin, fd_stdout, fd_stderr; pipe fd_errno, fd_stdin, fd_stdout, fd_stderr;
fd_errno.open(process_stream::PIPE); fd_errno.open(subprocess_stream::PIPE);
fd_stdin.open(use_in); fd_stdin.open(use_in);
fd_stdout.open(use_out); fd_stdout.open(use_out);
fd_stderr.open(use_err); fd_stderr.open(use_err);
auto cpid = fork(); auto cpid = fork();
if (cpid == -1) { if (cpid == -1) {
throw process_error{"fork failed"}; throw subprocess_error{"fork failed"};
} else if (!cpid) { } else if (!cpid) {
/* child process */ /* child process */
fd_errno.close(false); fd_errno.close(false);
@ -165,24 +165,24 @@ OSTD_EXPORT void subprocess::open_impl(
std::exit(1); std::exit(1);
} }
/* prepare standard streams */ /* prepare standard streams */
if (use_in == process_stream::PIPE) { if (use_in == subprocess_stream::PIPE) {
fd_stdin.close(true); fd_stdin.close(true);
if (!fd_stdin.dup2(STDIN_FILENO, fd_errno, false)) { if (!fd_stdin.dup2(STDIN_FILENO, fd_errno, false)) {
std::exit(1); std::exit(1);
} }
} }
if (use_out == process_stream::PIPE) { if (use_out == subprocess_stream::PIPE) {
fd_stdout.close(false); fd_stdout.close(false);
if (!fd_stdout.dup2(STDOUT_FILENO, fd_errno, true)) { if (!fd_stdout.dup2(STDOUT_FILENO, fd_errno, true)) {
std::exit(1); std::exit(1);
} }
} }
if (use_err == process_stream::PIPE) { if (use_err == subprocess_stream::PIPE) {
fd_stderr.close(false); fd_stderr.close(false);
if (!fd_stderr.dup2(STDERR_FILENO, fd_errno, true)) { if (!fd_stderr.dup2(STDERR_FILENO, fd_errno, true)) {
std::exit(1); std::exit(1);
} }
} else if (use_err == process_stream::STDOUT) { } else if (use_err == subprocess_stream::STDOUT) {
if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) { if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
fd_errno.write_errno(); fd_errno.write_errno();
std::exit(1); std::exit(1);
@ -199,15 +199,15 @@ OSTD_EXPORT void subprocess::open_impl(
} else { } else {
/* parent process */ /* parent process */
fd_errno.close(true); fd_errno.close(true);
if (use_in == process_stream::PIPE) { if (use_in == subprocess_stream::PIPE) {
fd_stdin.close(false); fd_stdin.close(false);
fd_stdin.fdopen(in, true); fd_stdin.fdopen(in, true);
} }
if (use_out == process_stream::PIPE) { if (use_out == subprocess_stream::PIPE) {
fd_stdout.close(true); fd_stdout.close(true);
fd_stdout.fdopen(out, false); fd_stdout.fdopen(out, false);
} }
if (use_err == process_stream::PIPE) { if (use_err == subprocess_stream::PIPE) {
fd_stderr.close(true); fd_stderr.close(true);
fd_stderr.fdopen(err, false); fd_stderr.fdopen(err, false);
} }
@ -230,25 +230,25 @@ OSTD_EXPORT void subprocess::reset() {
OSTD_EXPORT int subprocess::close() { OSTD_EXPORT int subprocess::close() {
if (!p_current) { if (!p_current) {
throw process_error{"no child process"}; throw subprocess_error{"no child process"};
} }
data *pd = static_cast<data *>(p_current); data *pd = static_cast<data *>(p_current);
int retc = 0; int retc = 0;
if (pid_t wp; (wp = waitpid(pd->pid, &retc, 0)) < 0) { if (pid_t wp; (wp = waitpid(pd->pid, &retc, 0)) < 0) {
reset(); reset();
throw process_error{"child process wait failed"}; throw subprocess_error{"child process wait failed"};
} }
if (retc) { if (retc) {
int eno; int eno;
auto r = read(pd->errno_fd, &eno, sizeof(int)); auto r = read(pd->errno_fd, &eno, sizeof(int));
reset(); reset();
if (r < 0) { if (r < 0) {
throw process_error{"could not read from pipe"}; throw subprocess_error{"could not read from pipe"};
} else if (r == sizeof(int)) { } else if (r == sizeof(int)) {
auto ec = std::system_category().default_error_condition(eno); auto ec = std::system_category().default_error_condition(eno);
auto app = appender<std::string>(); auto app = appender<std::string>();
format(app, "could not execute subprocess (%s)", ec.message()); format(app, "could not execute subprocess (%s)", ec.message());
throw process_error{std::move(app.get())}; throw subprocess_error{std::move(app.get())};
} }
} }
reset(); reset();

View File

@ -101,15 +101,15 @@ struct pipe {
} }
} }
void open(process_stream use, SECURITY_ATTRIBUTES &sa, bool read) { void open(subprocess_stream use, SECURITY_ATTRIBUTES &sa, bool read) {
if (use != process_stream::PIPE) { if (use != subprocess_stream::PIPE) {
return; return;
} }
if (!CreatePipe(&p_r, &p_w, &sa, 0)) { if (!CreatePipe(&p_r, &p_w, &sa, 0)) {
throw process_error{"could not open pipe"}; throw subprocess_error{"could not open pipe"};
} }
if (!SetHandleInformation(read ? p_r : p_w, HANDLE_FLAG_INHERIT, 0)) { if (!SetHandleInformation(read ? p_r : p_w, HANDLE_FLAG_INHERIT, 0)) {
throw process_error{"could not set pipe parameters"}; throw subprocess_error{"could not set pipe parameters"};
} }
} }
@ -119,7 +119,7 @@ struct pipe {
read ? _O_RDONLY : 0 read ? _O_RDONLY : 0
); );
if (fd < 0) { if (fd < 0) {
throw process_error{"could not open redirected stream"}; throw subprocess_error{"could not open redirected stream"};
} }
if (read) { if (read) {
p_r = nullptr; p_r = nullptr;
@ -129,7 +129,7 @@ struct pipe {
auto p = _fdopen(fd, read ? "r" : "w"); auto p = _fdopen(fd, read ? "r" : "w");
if (!p) { if (!p) {
_close(fd); _close(fd);
throw process_error{"could not open redirected stream"}; throw subprocess_error{"could not open redirected stream"};
} }
s.open(p, [](FILE *f) { s.open(p, [](FILE *f) {
std::fclose(f); std::fclose(f);
@ -283,8 +283,8 @@ static std::string concat_args(std::vector<std::string> const &args) {
OSTD_EXPORT void subprocess::open_impl( OSTD_EXPORT void subprocess::open_impl(
std::string const &cmd, std::vector<std::string> const &args, bool use_path std::string const &cmd, std::vector<std::string> const &args, bool use_path
) { ) {
if (use_in == process_stream::STDOUT) { if (use_in == subprocess_stream::STDOUT) {
throw process_error{"could not redirect stdin to stdout"}; throw subprocess_error{"could not redirect stdin to stdout"};
} }
/* pipes */ /* pipes */
@ -310,33 +310,33 @@ OSTD_EXPORT void subprocess::open_impl(
si.cb = sizeof(STARTUPINFOW); si.cb = sizeof(STARTUPINFOW);
if (use_in == process_stream::PIPE) { if (use_in == subprocess_stream::PIPE) {
si.hStdInput = pipe_in.p_r; si.hStdInput = pipe_in.p_r;
pipe_in.fdopen(in, false); pipe_in.fdopen(in, false);
} else { } else {
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
if (si.hStdInput == INVALID_HANDLE_VALUE) { if (si.hStdInput == INVALID_HANDLE_VALUE) {
throw process_error{"could not get standard input handle"}; throw subprocess_error{"could not get standard input handle"};
} }
} }
if (use_out == process_stream::PIPE) { if (use_out == subprocess_stream::PIPE) {
si.hStdOutput = pipe_out.p_w; si.hStdOutput = pipe_out.p_w;
pipe_out.fdopen(out, true); pipe_out.fdopen(out, true);
} else { } else {
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (si.hStdOutput == INVALID_HANDLE_VALUE) { if (si.hStdOutput == INVALID_HANDLE_VALUE) {
throw process_error{"could not get standard output handle"}; throw subprocess_error{"could not get standard output handle"};
} }
} }
if (use_err == process_stream::PIPE) { if (use_err == subprocess_stream::PIPE) {
si.hStdError = pipe_err.p_w; si.hStdError = pipe_err.p_w;
pipe_err.fdopen(err, true); pipe_err.fdopen(err, true);
} else if (use_err == process_stream::STDOUT) { } else if (use_err == subprocess_stream::STDOUT) {
si.hStdError = si.hStdOutput; si.hStdError = si.hStdOutput;
} else { } else {
si.hStdError = GetStdHandle(STD_ERROR_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (si.hStdError == INVALID_HANDLE_VALUE) { if (si.hStdError == INVALID_HANDLE_VALUE) {
throw process_error{"could not get standard error handle"}; throw subprocess_error{"could not get standard error handle"};
} }
} }
si.dwFlags |= STARTF_USESTDHANDLES; si.dwFlags |= STARTF_USESTDHANDLES;
@ -348,7 +348,7 @@ OSTD_EXPORT void subprocess::open_impl(
if (!MultiByteToWideChar( if (!MultiByteToWideChar(
CP_UTF8, 0, cmd.data(), cmd.size() + 1, wcmd.get(), cmd.size() + 1 CP_UTF8, 0, cmd.data(), cmd.size() + 1, wcmd.get(), cmd.size() + 1
)) { )) {
throw process_error{"unicode conversion failed"}; throw subprocess_error{"unicode conversion failed"};
} }
if (!use_path) { if (!use_path) {
cmdpath = wcmd.get(); cmdpath = wcmd.get();
@ -364,7 +364,7 @@ OSTD_EXPORT void subprocess::open_impl(
if (!MultiByteToWideChar( if (!MultiByteToWideChar(
CP_UTF8, 0, astr.data(), astr.size() + 1, cmdline.get(), astr.size() + 1 CP_UTF8, 0, astr.data(), astr.size() + 1, cmdline.get(), astr.size() + 1
)) { )) {
throw process_error{"unicode conversion failed"}; throw subprocess_error{"unicode conversion failed"};
} }
/* owned by CreateProcess, do not close explicitly */ /* owned by CreateProcess, do not close explicitly */
@ -390,7 +390,7 @@ OSTD_EXPORT void subprocess::open_impl(
}; };
if (!success) { if (!success) {
throw process_error{"could not execute subprocess"}; throw subprocess_error{"could not execute subprocess"};
} }
} }
@ -400,7 +400,7 @@ OSTD_EXPORT void subprocess::reset() {
OSTD_EXPORT int subprocess::close() { OSTD_EXPORT int subprocess::close() {
if (!p_current) { if (!p_current) {
throw process_error{"no child process"}; throw subprocess_error{"no child process"};
} }
data *pd = static_cast<data *>(p_current); data *pd = static_cast<data *>(p_current);
@ -409,7 +409,7 @@ OSTD_EXPORT int subprocess::close() {
CloseHandle(pd->process); CloseHandle(pd->process);
CloseHandle(pd->thread); CloseHandle(pd->thread);
reset(); reset();
throw process_error{"child process wait failed"}; throw subprocess_error{"child process wait failed"};
} }
DWORD ec = 0; DWORD ec = 0;
@ -417,7 +417,7 @@ OSTD_EXPORT int subprocess::close() {
CloseHandle(pd->process); CloseHandle(pd->process);
CloseHandle(pd->thread); CloseHandle(pd->thread);
reset(); reset();
throw process_error{"could not retrieve exit code"}; throw subprocess_error{"could not retrieve exit code"};
} }
CloseHandle(pd->process); CloseHandle(pd->process);