Add Coprocess class

It provides a convenient way to spawn a process and read from/write to
its stdin/stdout.
This commit is contained in:
Andrew Ayer
2015-05-24 18:54:11 -07:00
parent 3db6271492
commit 44f70e6b48
12 changed files with 992 additions and 305 deletions

View File

@@ -162,119 +162,6 @@ std::string our_exe_path ()
}
}
static int execvp (const std::string& file, const std::vector<std::string>& args)
{
std::vector<const char*> args_c_str;
args_c_str.reserve(args.size());
for (std::vector<std::string>::const_iterator arg(args.begin()); arg != args.end(); ++arg) {
args_c_str.push_back(arg->c_str());
}
args_c_str.push_back(NULL);
return execvp(file.c_str(), const_cast<char**>(&args_c_str[0]));
}
int exec_command (const std::vector<std::string>& command)
{
pid_t child = fork();
if (child == -1) {
throw System_error("fork", "", errno);
}
if (child == 0) {
execvp(command[0], command);
perror(command[0].c_str());
_exit(-1);
}
int status = 0;
if (waitpid(child, &status, 0) == -1) {
throw System_error("waitpid", "", errno);
}
return status;
}
int exec_command (const std::vector<std::string>& command, std::ostream& output)
{
int pipefd[2];
if (pipe(pipefd) == -1) {
throw System_error("pipe", "", errno);
}
pid_t child = fork();
if (child == -1) {
int fork_errno = errno;
close(pipefd[0]);
close(pipefd[1]);
throw System_error("fork", "", fork_errno);
}
if (child == 0) {
close(pipefd[0]);
if (pipefd[1] != 1) {
dup2(pipefd[1], 1);
close(pipefd[1]);
}
execvp(command[0], command);
perror(command[0].c_str());
_exit(-1);
}
close(pipefd[1]);
char buffer[1024];
ssize_t bytes_read;
while ((bytes_read = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
output.write(buffer, bytes_read);
}
if (bytes_read == -1) {
int read_errno = errno;
close(pipefd[0]);
throw System_error("read", "", read_errno);
}
close(pipefd[0]);
int status = 0;
if (waitpid(child, &status, 0) == -1) {
throw System_error("waitpid", "", errno);
}
return status;
}
int exec_command_with_input (const std::vector<std::string>& command, const char* p, size_t len)
{
int pipefd[2];
if (pipe(pipefd) == -1) {
throw System_error("pipe", "", errno);
}
pid_t child = fork();
if (child == -1) {
int fork_errno = errno;
close(pipefd[0]);
close(pipefd[1]);
throw System_error("fork", "", fork_errno);
}
if (child == 0) {
close(pipefd[1]);
if (pipefd[0] != 0) {
dup2(pipefd[0], 0);
close(pipefd[0]);
}
execvp(command[0], command);
perror(command[0].c_str());
_exit(-1);
}
close(pipefd[0]);
while (len > 0) {
ssize_t bytes_written = write(pipefd[1], p, len);
if (bytes_written == -1) {
int write_errno = errno;
close(pipefd[1]);
throw System_error("write", "", write_errno);
}
p += bytes_written;
len -= bytes_written;
}
close(pipefd[1]);
int status = 0;
if (waitpid(child, &status, 0) == -1) {
throw System_error("waitpid", "", errno);
}
return status;
}
int exit_status (int wait_status)
{
return wait_status != -1 && WIFEXITED(wait_status) ? WEXITSTATUS(wait_status) : -1;