Get rid of GNU-specific C++ type. Trim down to features actually needed by Textsuggest. Index: lib/subprocess.hpp --- lib/subprocess.hpp.orig +++ lib/subprocess.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -27,71 +27,66 @@ class popen public: popen(const std::string& cmd, std::vector argv) - : in_filebuf(nullptr), out_filebuf(nullptr), err_filebuf(nullptr), in_stream(nullptr), out_stream(nullptr), err_stream(nullptr) { - if (pipe(in_pipe) == -1 || - pipe(out_pipe) == -1 || - pipe(err_pipe) == -1 ) - { - throw std::system_error(errno, std::system_category()); - } - + out_stream = new std::stringstream; + err_stream = new std::stringstream; + open_pipes(); run(cmd, argv); } - popen(const std::string& cmd, std::vector argv, std::ostream& pipe_stdout) - : in_filebuf(nullptr), out_filebuf(nullptr), err_filebuf(nullptr), in_stream(nullptr), out_stream(nullptr), err_stream(nullptr) - { - auto filebuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(pipe_stdout.rdbuf()); - out_pipe[READ] = -1; - out_pipe[WRITE] = filebuf->fd(); - - if (pipe(in_pipe) == -1 || - pipe(err_pipe) == -1 ) - { - throw std::system_error(errno, std::system_category()); - } - - run(cmd, argv); - } - ~popen() { - delete in_filebuf; - delete in_stream; - if (out_filebuf != nullptr) delete out_filebuf; - if (out_stream != nullptr) delete out_stream; - delete err_filebuf; + close_pipe(in_pipe); + close_pipe(err_pipe); + close_pipe(out_pipe); + delete out_stream; delete err_stream; } - std::ostream& stdin() { return *in_stream; }; + std::istream& get_stdout() { return *out_stream; }; + std::istream& get_stderr() { return *err_stream; }; - std::istream& stdout() - { - if (out_stream == nullptr) throw std::system_error(EBADF, std::system_category()); - return *out_stream; - }; + int wait(void) { return WEXITSTATUS(status); } + +private: - std::istream& stderr() { return *err_stream; }; - - int wait() + enum ends_of_pipe { READ = 0, WRITE = 1 }; + + void open_pipes(void) { - int status = 0; - waitpid(pid, &status, 0); - return WEXITSTATUS(status); - }; + if (pipe(in_pipe) == -1) + throw std::system_error(errno, std::system_category()); - void close() + if (pipe(out_pipe) == -1) + { + int pipe_errno = errno; + close_pipe(in_pipe); + throw std::system_error(pipe_errno, std::system_category()); + } + if (pipe(err_pipe) == -1 ) + { + int pipe_errno = errno; + close_pipe(in_pipe); + close_pipe(out_pipe); + throw std::system_error(pipe_errno, std::system_category()); + } + } + + void close_pipe_end(int pipe[2], enum ends_of_pipe end) { - in_filebuf->close(); + if (pipe[end] != -1) + { + ::close(pipe[end]); + pipe[end] = -1; + } } - - -private: - - enum ends_of_pipe { READ = 0, WRITE = 1 }; + void close_pipe(int pipe[2]) + { + close_pipe_end(pipe, READ); + close_pipe_end(pipe, WRITE); + } + struct raii_char_str { raii_char_str(std::string s) : buf(s.c_str(), s.c_str() + s.size() + 1) { }; @@ -99,6 +94,22 @@ class popen mutable std::vector buf; }; + void slurp_pipe(int fd, std::stringstream *&sink) + { + char buf[4096]; + + while (1) + { + ssize_t ret = read(out_pipe[READ], buf, sizeof(buf)); + if (ret == -1) + throw std::system_error(errno, std::system_category()); + else if (ret > 0) + sink->write(buf, ret); + else + break; + } + } + void run(const std::string& cmd, std::vector argv) { argv.insert(argv.begin(), cmd); @@ -107,21 +118,17 @@ class popen if (pid == 0) child(argv); - ::close(in_pipe[READ]); - ::close(out_pipe[WRITE]); - ::close(err_pipe[WRITE]); + close_pipe_end(in_pipe, READ); + close_pipe_end(out_pipe, WRITE); + close_pipe_end(err_pipe, WRITE); - in_filebuf = new __gnu_cxx::stdio_filebuf(in_pipe[WRITE], std::ios_base::out, 1); - in_stream = new std::ostream(in_filebuf); - - if (out_pipe[READ] != -1) - { - out_filebuf = new __gnu_cxx::stdio_filebuf(out_pipe[READ], std::ios_base::in, 1); - out_stream = new std::istream(out_filebuf); - } - - err_filebuf = new __gnu_cxx::stdio_filebuf(err_pipe[READ], std::ios_base::in, 1); - err_stream = new std::istream(err_filebuf); + slurp_pipe(out_pipe[READ], out_stream); + slurp_pipe(err_pipe[READ], err_stream); + + close_pipe_end(out_pipe, READ); + close_pipe_end(err_pipe, READ); + + waitpid(pid, &status, 0); } void child(const std::vector& argv) @@ -134,12 +141,9 @@ class popen return; } - ::close(in_pipe[READ]); - ::close(in_pipe[WRITE]); - if (out_pipe[READ] != -1) ::close(out_pipe[READ]); - ::close(out_pipe[WRITE]); - ::close(err_pipe[READ]); - ::close(err_pipe[WRITE]); + close_pipe(in_pipe); + close_pipe_end(out_pipe, WRITE); + close_pipe_end(err_pipe, WRITE); std::vector real_args(argv.begin(), argv.end()); std::vector cargs(real_args.begin(), real_args.end()); @@ -153,18 +157,14 @@ class popen } pid_t pid; + int status; int in_pipe[2]; int out_pipe[2]; int err_pipe[2]; - __gnu_cxx::stdio_filebuf* in_filebuf; - __gnu_cxx::stdio_filebuf* out_filebuf; - __gnu_cxx::stdio_filebuf* err_filebuf; - - std::ostream* in_stream; - std::istream* out_stream; - std::istream* err_stream; + std::stringstream *out_stream; + std::stringstream *err_stream; }; } // namespace: subprocess