pstream.h
Go to the documentation of this file.
// PStreams - POSIX Process I/O for C++
// Copyright (C) 2001 - 2020 Jonathan Wakely
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// SPDX-License-Identifier: BSL-1.0
#ifndef REDI_PSTREAM_H_SEEN
#define REDI_PSTREAM_H_SEEN
#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>
#include <string>
#include <vector>
#include <algorithm> // for min()
#include <cerrno> // for errno
#include <cstddef> // for size_t, NULL
#include <cstdlib> // for exit()
#include <sys/types.h> // for pid_t
#include <sys/wait.h> // for waitpid()
#include <sys/ioctl.h> // for ioctl() and FIONREAD
#if defined(__sun)
# include <sys/filio.h> // for FIONREAD on Solaris 2.5
#endif
#include <unistd.h> // for pipe() fork() exec() and filedes functions
#include <signal.h> // for kill()
#include <fcntl.h> // for fcntl()
#if REDI_EVISCERATE_PSTREAMS
# include <stdio.h> // for FILE, fdopen()
#endif
#define PSTREAMS_VERSION 0x0103 // 1.0.3
namespace redi
{
struct pstreams
{
typedef std::ios_base::openmode pmode;
typedef std::vector<std::string> argv_type;
typedef int fd_type;
static const pmode pstdin = std::ios_base::out;
static const pmode pstdout = std::ios_base::in;
static const pmode pstderr = std::ios_base::app;
static const pmode newpg = std::ios_base::trunc;
protected:
enum { bufsz = 32 };
enum { pbsz = 2 };
#if __cplusplus >= 201103L
template<typename T>
using stringable = decltype((void)std::string(std::declval<const T&>()));
#endif
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_pstreambuf
: public std::basic_streambuf<CharT, Traits>
, public pstreams
{
public:
// Type definitions for dependent types
typedef CharT char_type;
typedef Traits traits_type;
typedef typename traits_type::int_type int_type;
typedef typename traits_type::off_type off_type;
typedef typename traits_type::pos_type pos_type;
typedef fd_type fd_t;
basic_pstreambuf();
basic_pstreambuf(const std::string& cmd, pmode mode);
basic_pstreambuf( const std::string& file,
const argv_type& argv,
pmode mode );
#if __cplusplus >= 201103L
basic_pstreambuf(basic_pstreambuf&&) noexcept;
basic_pstreambuf& operator=(basic_pstreambuf&&) noexcept;
void swap(basic_pstreambuf&) noexcept;
#endif
~basic_pstreambuf();
basic_pstreambuf*
open(const std::string& cmd, pmode mode);
basic_pstreambuf*
open(const std::string& file, const argv_type& argv, pmode mode);
basic_pstreambuf*
close();
basic_pstreambuf*
kill(int signal = SIGTERM);
basic_pstreambuf*
killpg(int signal = SIGTERM);
void
peof();
bool
read_err(bool readerr = true);
bool
is_open() const;
bool
exited();
#if REDI_EVISCERATE_PSTREAMS
std::size_t
fopen(FILE*& in, FILE*& out, FILE*& err);
#endif
int
status() const;
int
error() const;
protected:
int_type
overflow(int_type c);
int_type
underflow();
int_type
pbackfail(int_type c = traits_type::eof());
int
sync();
std::streamsize
xsputn(const char_type* s, std::streamsize n);
std::streamsize
write(const char_type* s, std::streamsize n);
std::streamsize
read(char_type* s, std::streamsize n);
std::streamsize
showmanyc();
protected:
enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
pid_t
fork(pmode mode);
int
wait(bool nohang = false);
fd_type&
wpipe();
fd_type&
rpipe();
fd_type&
rpipe(buf_read_src which);
void
create_buffers(pmode mode);
void
destroy_buffers(pmode mode);
bool
empty_buffer();
bool
fill_buffer(bool non_blocking = false);
char_type*
rbuffer();
buf_read_src
switch_read_buffer(buf_read_src);
private:
#if __cplusplus >= 201103L
using basic_streambuf = std::basic_streambuf<char_type, traits_type>;
#else
basic_pstreambuf(const basic_pstreambuf&);
basic_pstreambuf& operator=(const basic_pstreambuf&);
#endif
void
init_rbuffers();
pid_t ppid_; // pid of process
fd_type wpipe_; // pipe used to write to process' stdin
fd_type rpipe_[2]; // two pipes to read from, stdout and stderr
char_type* wbuffer_;
char_type* rbuffer_[2];
char_type* rbufstate_[3];
buf_read_src rsrc_;
int status_; // hold exit status of child process
int error_; // hold errno if fork() or exec() fails
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class pstream_common
: virtual public std::basic_ios<CharT, Traits>
, virtual public pstreams
{
protected:
typedef basic_pstreambuf<CharT, Traits> streambuf_type;
typedef std::basic_ios<CharT, Traits> ios_type;
typedef pstreams::pmode pmode;
typedef pstreams::argv_type argv_type;
pstream_common();
pstream_common(const std::string& cmd, pmode mode);
pstream_common(const std::string& file, const argv_type& argv, pmode mode);
virtual
~pstream_common() = 0;
#if __cplusplus >= 201103L
pstream_common(pstream_common&& rhs) noexcept
: command_(std::move(rhs.command_))
, buf_(std::move(rhs.buf_))
{
/* derived class is responsible for ios_type::move(rhs) happening */
}
pstream_common&
operator=(pstream_common&& rhs) noexcept
{
command_ = std::move(rhs.command_);
buf_ = std::move(rhs.buf_);
return *this;
}
void
swap(pstream_common& rhs) noexcept
{
/* derived class is responsible for ios_type::swap(rhs) happening */
command_.swap(rhs.command_);
buf_.swap(rhs.buf_);
}
#endif // C++11
void
do_open(const std::string& cmd, pmode mode);
void
do_open(const std::string& file, const argv_type& argv, pmode mode);
public:
int
close();
bool
is_open() const;
const std::string&
command() const;
streambuf_type*
rdbuf() const;
#if REDI_EVISCERATE_PSTREAMS
std::size_t
fopen(FILE*& in, FILE*& out, FILE*& err);
#endif
protected:
std::string command_;
streambuf_type buf_;
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_ipstream
: public std::basic_istream<CharT, Traits>
, public pstream_common<CharT, Traits>
, virtual public pstreams
{
typedef std::basic_istream<CharT, Traits> istream_type;
typedef pstream_common<CharT, Traits> pbase_type;
using pbase_type::buf_; // declare name in this scope
// Ensure a basic_ipstream will read from at least one pipe
pmode readable(pmode mode)
{
if (!(mode & (pstdout|pstderr)))
mode |= pstdout;
return mode;
}
public:
typedef typename pbase_type::pmode pmode;
typedef typename pbase_type::argv_type argv_type;
basic_ipstream()
: istream_type(NULL), pbase_type()
{ }
explicit
basic_ipstream(const std::string& cmd, pmode mode = pstdout)
: istream_type(NULL), pbase_type(cmd, readable(mode))
{ }
basic_ipstream( const std::string& file,
const argv_type& argv,
pmode mode = pstdout )
: istream_type(NULL), pbase_type(file, argv, readable(mode))
{ }
explicit
basic_ipstream(const argv_type& argv, pmode mode = pstdout)
: istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode))
{ }
#if __cplusplus >= 201103L
template<typename T, typename = stringable<T>>
explicit
basic_ipstream(std::initializer_list<T> args, pmode mode = pstdout)
: basic_ipstream(argv_type(args.begin(), args.end()), mode)
{ }
basic_ipstream(basic_ipstream&& rhs)
: istream_type(std::move(rhs))
, pbase_type(std::move(rhs))
{ istream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
basic_ipstream&
operator=(basic_ipstream&& rhs)
{
istream_type::operator=(std::move(rhs));
pbase_type::operator=(std::move(rhs));
return *this;
}
void
swap(basic_ipstream& rhs)
{
istream_type::swap(rhs);
pbase_type::swap(rhs);
}
#endif // C++11
~basic_ipstream()
{ }
void
open(const std::string& cmd, pmode mode = pstdout)
{
this->do_open(cmd, readable(mode));
}
void
open( const std::string& file,
const argv_type& argv,
pmode mode = pstdout )
{
this->do_open(file, argv, readable(mode));
}
basic_ipstream&
out()
{
this->buf_.read_err(false);
return *this;
}
basic_ipstream&
err()
{
this->buf_.read_err(true);
return *this;
}
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_opstream
: public std::basic_ostream<CharT, Traits>
, public pstream_common<CharT, Traits>
, virtual public pstreams
{
typedef std::basic_ostream<CharT, Traits> ostream_type;
typedef pstream_common<CharT, Traits> pbase_type;
using pbase_type::buf_; // declare name in this scope
public:
typedef typename pbase_type::pmode pmode;
typedef typename pbase_type::argv_type argv_type;
basic_opstream()
: ostream_type(NULL), pbase_type()
{ }
explicit
basic_opstream(const std::string& cmd, pmode mode = pstdin)
: ostream_type(NULL), pbase_type(cmd, mode|pstdin)
{ }
basic_opstream( const std::string& file,
const argv_type& argv,
pmode mode = pstdin )
: ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
{ }
explicit
basic_opstream(const argv_type& argv, pmode mode = pstdin)
: ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin)
{ }
#if __cplusplus >= 201103L
template<typename T, typename = stringable<T>>
explicit
basic_opstream(std::initializer_list<T> args, pmode mode = pstdin)
: basic_opstream(argv_type(args.begin(), args.end()), mode)
{ }
basic_opstream(basic_opstream&& rhs)
: ostream_type(std::move(rhs))
, pbase_type(std::move(rhs))
{ ostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
basic_opstream&
operator=(basic_opstream&& rhs)
{
ostream_type::operator=(std::move(rhs));
pbase_type::operator=(std::move(rhs));
return *this;
}
void
swap(basic_opstream& rhs)
{
ostream_type::swap(rhs);
pbase_type::swap(rhs);
}
#endif // C++11
~basic_opstream() { }
void
open(const std::string& cmd, pmode mode = pstdin)
{
this->do_open(cmd, mode|pstdin);
}
void
open( const std::string& file,
const argv_type& argv,
pmode mode = pstdin)
{
this->do_open(file, argv, mode|pstdin);
}
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_pstream
: public std::basic_iostream<CharT, Traits>
, public pstream_common<CharT, Traits>
, virtual public pstreams
{
typedef std::basic_iostream<CharT, Traits> iostream_type;
typedef pstream_common<CharT, Traits> pbase_type;
using pbase_type::buf_; // declare name in this scope
public:
typedef typename pbase_type::pmode pmode;
typedef typename pbase_type::argv_type argv_type;
basic_pstream()
: iostream_type(NULL), pbase_type()
{ }
explicit
basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin)
: iostream_type(NULL), pbase_type(cmd, mode)
{ }
basic_pstream( const std::string& file,
const argv_type& argv,
pmode mode = pstdout|pstdin )
: iostream_type(NULL), pbase_type(file, argv, mode)
{ }
explicit
basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin)
: iostream_type(NULL), pbase_type(argv.at(0), argv, mode)
{ }
#if __cplusplus >= 201103L
template<typename T, typename = stringable<T>>
explicit
basic_pstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
: basic_pstream(argv_type(l.begin(), l.end()), mode)
{ }
basic_pstream(basic_pstream&& rhs)
: iostream_type(std::move(rhs))
, pbase_type(std::move(rhs))
{ iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
basic_pstream&
operator=(basic_pstream&& rhs)
{
iostream_type::operator=(std::move(rhs));
pbase_type::operator=(std::move(rhs));
return *this;
}
void
swap(basic_pstream& rhs)
{
iostream_type::swap(rhs);
pbase_type::swap(rhs);
}
#endif // C++11
~basic_pstream() { }
void
open(const std::string& cmd, pmode mode = pstdout|pstdin)
{
this->do_open(cmd, mode);
}
void
open( const std::string& file,
const argv_type& argv,
pmode mode = pstdout|pstdin )
{
this->do_open(file, argv, mode);
}
basic_pstream&
out()
{
this->buf_.read_err(false);
return *this;
}
basic_pstream&
err()
{
this->buf_.read_err(true);
return *this;
}
};
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_rpstream
: public std::basic_ostream<CharT, Traits>
, private std::basic_istream<CharT, Traits>
, private pstream_common<CharT, Traits>
, virtual public pstreams
{
typedef std::basic_ostream<CharT, Traits> ostream_type;
typedef std::basic_istream<CharT, Traits> istream_type;
typedef pstream_common<CharT, Traits> pbase_type;
using pbase_type::buf_; // declare name in this scope
public:
typedef typename pbase_type::pmode pmode;
typedef typename pbase_type::argv_type argv_type;
basic_rpstream()
: ostream_type(NULL), istream_type(NULL), pbase_type()
{ }
explicit
basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin)
: ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode)
{ }
basic_rpstream( const std::string& file,
const argv_type& argv,
pmode mode = pstdout|pstdin )
: ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
{ }
explicit
basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin)
: ostream_type(NULL), istream_type(NULL)
, pbase_type(argv.at(0), argv, mode)
{ }
#if __cplusplus >= 201103L
template<typename T, typename = stringable<T>>
explicit
basic_rpstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
: basic_rpstream(argv_type(l.begin(), l.end()), mode)
{ }
// TODO: figure out how to move istream and ostream bases separately,
// but so the virtual basic_ios base is only modified once.
#if 0
basic_rpstream(basic_rpstream&& rhs)
: iostream_type(std::move(rhs))
, pbase_type(std::move(rhs))
{ iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
basic_rpstream&
operator=(basic_rpstream&& rhs)
{
iostream_type::operator=(std::move(rhs));
pbase_type::operator=(std::move(rhs));
return *this;
}
void
swap(basic_rpstream& rhs)
{
iostream_type::swap(rhs);
pbase_type::swap(rhs);
}
#endif
#endif // C++11
~basic_rpstream() { }
void
open(const std::string& cmd, pmode mode = pstdout|pstdin)
{
this->do_open(cmd, mode);
}
void
open( const std::string& file,
const argv_type& argv,
pmode mode = pstdout|pstdin )
{
this->do_open(file, argv, mode);
}
istream_type&
out()
{
this->buf_.read_err(false);
return *this;
}
istream_type&
err()
{
this->buf_.read_err(true);
return *this;
}
};
typedef basic_pstreambuf<char> pstreambuf;
typedef basic_ipstream<char> ipstream;
typedef basic_opstream<char> opstream;
typedef basic_pstream<char> pstream;
typedef basic_rpstream<char> rpstream;
template <typename C, typename T>
inline std::basic_ostream<C,T>&
peof(std::basic_ostream<C,T>& s)
{
typedef basic_pstreambuf<C,T> pstreambuf_type;
if (pstreambuf_type* p = dynamic_cast<pstreambuf_type*>(s.rdbuf()))
p->peof();
return s;
}
/*
* member definitions for pstreambuf
*/
template <typename C, typename T>
inline
basic_pstreambuf<C,T>::basic_pstreambuf()
: ppid_(-1) // initialise to -1 to indicate no process run yet.
, wpipe_(-1)
, wbuffer_()
, rbuffer_()
, rbufstate_()
, rsrc_(rsrc_out)
, status_(-1)
, error_(0)
{
rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
}
template <typename C, typename T>
inline
basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& cmd, pmode mode)
: ppid_(-1) // initialise to -1 to indicate no process run yet.
, wpipe_(-1)
, wbuffer_()
, rbuffer_()
, rbufstate_()
, rsrc_(rsrc_out)
, status_(-1)
, error_(0)
{
rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
open(cmd, mode);
}
template <typename C, typename T>
inline
basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
const argv_type& argv,
pmode mode )
: ppid_(-1) // initialise to -1 to indicate no process run yet.
, wpipe_(-1)
, wbuffer_()
, rbuffer_()
, rbufstate_()
, rsrc_(rsrc_out)
, status_(-1)
, error_(0)
{
rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
open(file, argv, mode);
}
template <typename C, typename T>
inline
basic_pstreambuf<C,T>::~basic_pstreambuf()
{
close();
}
#if __cplusplus >= 201103L
template <typename C, typename T>
inline
basic_pstreambuf<C,T>::basic_pstreambuf( basic_pstreambuf&& rhs ) noexcept
: basic_streambuf(static_cast<const basic_streambuf&>(rhs))
, ppid_(rhs.ppid_)
, wpipe_(rhs.wpipe_)
, rpipe_{rhs.rpipe_[0], rhs.rpipe_[1]}
, wbuffer_(rhs.wbuffer_)
, rbuffer_{rhs.rbuffer_[0], rhs.rbuffer_[1]}
, rbufstate_{rhs.rbufstate_[0], rhs.rbufstate_[1], rhs.rbufstate_[2]}
, rsrc_(rhs.rsrc_)
, status_(rhs.status_)
, error_(rhs.error_)
{
rhs.ppid_ = -1;
rhs.wpipe_ = -1;
rhs.rpipe_[0] = rhs.rpipe_[1] = -1;
rhs.wbuffer_ = nullptr;
rhs.rbuffer_[0] = rhs.rbuffer_[1] = nullptr;
rhs.rbufstate_[0] = rhs.rbufstate_[1] = rhs.rbufstate_[2] = nullptr;
rhs.rsrc_ = rsrc_out;
rhs.status_ = -1;
rhs.error_ = 0;
rhs.setg(nullptr, nullptr, nullptr);
rhs.setp(nullptr, nullptr);
}
template <typename C, typename T>
inline basic_pstreambuf<C,T>&
basic_pstreambuf<C,T>::operator=( basic_pstreambuf&& rhs ) noexcept
{
close();
basic_streambuf::operator=(static_cast<const basic_streambuf&>(rhs));
swap(rhs);
return *this;
}
template <typename C, typename T>
inline void
basic_pstreambuf<C,T>::swap( basic_pstreambuf& rhs ) noexcept
{
basic_streambuf::swap(static_cast<basic_streambuf&>(rhs));
std::swap(ppid_, rhs.ppid_);
std::swap(wpipe_, rhs.wpipe_);
std::swap(rpipe_, rhs.rpipe_);
std::swap(wbuffer_, rhs.wbuffer_);
std::swap(rbuffer_, rhs.rbuffer_);
std::swap(rbufstate_, rhs.rbufstate_);
std::swap(rsrc_, rhs.rsrc_);
std::swap(status_, rhs.status_);
std::swap(error_, rhs.error_);
}
#endif // C++11
template <typename C, typename T>
basic_pstreambuf<C,T>*
basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
{
const char * shell_path = "/bin/sh";
#if 0
const std::string argv[] = { "sh", "-c", command };
return this->open(shell_path, argv_type(argv, argv+3), mode);
#else
basic_pstreambuf<C,T>* ret = NULL;
if (!is_open())
{
switch(fork(mode))
{
case 0 :
// this is the new process, exec command
::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
// can only reach this point if exec() failed
// parent can get exit code from waitpid()
::_exit(errno);
// using std::exit() would make static dtors run twice
case -1 :
// couldn't fork, error already handled in pstreambuf::fork()
break;
default :
// this is the parent process
// activate buffers
create_buffers(mode);
ret = this;
}
}
return ret;
#endif
}
inline void
close_fd(pstreams::fd_type& fd)
{
if (fd >= 0 && ::close(fd) == 0)
fd = -1;
}
template <int N>
inline void
close_fd_array(pstreams::fd_type (&fds)[N])
{
for (std::size_t i = 0; i < N; ++i)
close_fd(fds[i]);
}
template <typename C, typename T>
basic_pstreambuf<C,T>*
basic_pstreambuf<C,T>::open( const std::string& file,
const argv_type& argv,
pmode mode )
{
basic_pstreambuf<C,T>* ret = NULL;
if (!is_open())
{
// constants for read/write ends of pipe
enum { RD, WR };
// open another pipe and set close-on-exec
fd_type ck_exec[] = { -1, -1 };
if (-1 == ::pipe(ck_exec)
|| -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
|| -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
{
error_ = errno;
close_fd_array(ck_exec);
}
else
{
switch(fork(mode))
{
case 0 :
// this is the new process, exec command
{
char** arg_v = new char*[argv.size()+1];
for (std::size_t i = 0; i < argv.size(); ++i)
{
const std::string& src = argv[i];
char*& dest = arg_v[i];
dest = new char[src.size()+1];
dest[ src.copy(dest, src.size()) ] = '\0';
}
arg_v[argv.size()] = NULL;
::execvp(file.c_str(), arg_v);
// can only reach this point if exec() failed
// parent can get error code from ck_exec pipe
error_ = errno;
while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1
&& errno == EINTR)
{ }
::close(ck_exec[WR]);
::close(ck_exec[RD]);
::_exit(error_);
// using std::exit() would make static dtors run twice
}
case -1 :
// couldn't fork, error already handled in pstreambuf::fork()
close_fd_array(ck_exec);
break;
default :
// this is the parent process
// check child called exec() successfully
::close(ck_exec[WR]);
switch (::read(ck_exec[RD], &error_, sizeof(error_)))
{
case 0:
// activate buffers
create_buffers(mode);
ret = this;
break;
case -1:
error_ = errno;
break;
default:
// error_ contains error code from child
// call wait() to clean up and set ppid_ to 0
this->wait();
break;
}
::close(ck_exec[RD]);
}
}
}
return ret;
}
template <typename C, typename T>
pid_t
basic_pstreambuf<C,T>::fork(pmode mode)
{
pid_t pid = -1;
// Three pairs of file descriptors, for pipes connected to the
// process' stdin, stdout and stderr
// (stored in a single array so close_fd_array() can close all at once)
fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
fd_type* const pin = fd;
fd_type* const pout = fd+2;
fd_type* const perr = fd+4;
// constants for read/write ends of pipe
enum { RD, WR };
// N.B.
// For the pstreambuf pin is an output stream and
// pout and perr are input streams.
if (!error_ && mode&pstdin && ::pipe(pin))
error_ = errno;
if (!error_ && mode&pstdout && ::pipe(pout))
error_ = errno;
if (!error_ && mode&pstderr && ::pipe(perr))
error_ = errno;
if (!error_)
{
pid = ::fork();
switch (pid)
{
case 0 :
{
// this is the new process
// for each open pipe close one end and redirect the
// respective standard stream to the other end
if (*pin >= 0)
{
::close(pin[WR]);
::dup2(pin[RD], STDIN_FILENO);
::close(pin[RD]);
}
if (*pout >= 0)
{
::close(pout[RD]);
::dup2(pout[WR], STDOUT_FILENO);
::close(pout[WR]);
}
if (*perr >= 0)
{
::close(perr[RD]);
::dup2(perr[WR], STDERR_FILENO);
::close(perr[WR]);
}
#ifdef _POSIX_JOB_CONTROL
if (mode&newpg)
::setpgid(0, 0); // Change to a new process group
#endif
break;
}
case -1 :
{
// couldn't fork for some reason
error_ = errno;
// close any open pipes
close_fd_array(fd);
break;
}
default :
{
// this is the parent process, store process' pid
ppid_ = pid;
// store one end of open pipes and close other end
if (*pin >= 0)
{
wpipe_ = pin[WR];
::close(pin[RD]);
}
if (*pout >= 0)
{
rpipe_[rsrc_out] = pout[RD];
::close(pout[WR]);
}
if (*perr >= 0)
{
rpipe_[rsrc_err] = perr[RD];
::close(perr[WR]);
}
}
}
}
else
{
// close any pipes we opened before failure
close_fd_array(fd);
}
return pid;
}
template <typename C, typename T>
basic_pstreambuf<C,T>*
basic_pstreambuf<C,T>::close()
{
const bool running = is_open();
sync(); // this might call wait() and reap the child process
// rather than trying to work out whether or not we need to clean up
// just do it anyway, all cleanup functions are safe to call twice.
destroy_buffers(pstdin|pstdout|pstderr);
// close pipes before wait() so child gets EOF/SIGPIPE
close_fd(wpipe_);
close_fd_array(rpipe_);
do
{
error_ = 0;
} while (wait() == -1 && error() == EINTR);
return running ? this : NULL;
}
template <typename C, typename T>
#if __cplusplus >= 201402L && __has_cpp_attribute(deprecated)
[[deprecated]]
#elif __GNUC__
__attribute__((deprecated))
#endif
inline void
basic_pstreambuf<C,T>::init_rbuffers()
{
rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
}
template <typename C, typename T>
void
basic_pstreambuf<C,T>::create_buffers(pmode mode)
{
if (mode & pstdin)
{
delete[] wbuffer_;
wbuffer_ = new char_type[bufsz];
this->setp(wbuffer_, wbuffer_ + bufsz);
}
if (mode & pstdout)
{
delete[] rbuffer_[rsrc_out];
rbuffer_[rsrc_out] = new char_type[bufsz];
rsrc_ = rsrc_out;
this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
rbuffer_[rsrc_out] + pbsz);
}
if (mode & pstderr)
{
delete[] rbuffer_[rsrc_err];
rbuffer_[rsrc_err] = new char_type[bufsz];
if (!(mode & pstdout))
{
rsrc_ = rsrc_err;
this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
rbuffer_[rsrc_err] + pbsz);
}
}
}
template <typename C, typename T>
void
basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
{
if (mode & pstdin)
{
this->setp(NULL, NULL);
delete[] wbuffer_;
wbuffer_ = NULL;
}
if (mode & pstdout)
{
if (rsrc_ == rsrc_out)
this->setg(NULL, NULL, NULL);
delete[] rbuffer_[rsrc_out];
rbuffer_[rsrc_out] = NULL;
}
if (mode & pstderr)
{
if (rsrc_ == rsrc_err)
this->setg(NULL, NULL, NULL);
delete[] rbuffer_[rsrc_err];
rbuffer_[rsrc_err] = NULL;
}
}
template <typename C, typename T>
typename basic_pstreambuf<C,T>::buf_read_src
basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
{
if (rsrc_ != src)
{
char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
for (std::size_t i = 0; i < 3; ++i)
rbufstate_[i] = tmpbufstate[i];
rsrc_ = src;
}
return rsrc_;
}
template <typename C, typename T>
int
basic_pstreambuf<C,T>::wait(bool nohang)
{
int child_exited = -1;
if (is_open())
{
int exit_status;
switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0))
{
case 0 :
// nohang was true and process has not exited
child_exited = 0;
break;
case -1 :
error_ = errno;
break;
default :
// process has exited
ppid_ = 0;
status_ = exit_status;
child_exited = 1;
// Close wpipe, would get SIGPIPE if we used it.
destroy_buffers(pstdin);
close_fd(wpipe_);
// Must free read buffers and pipes on destruction
// or next call to open()/close()
break;
}
}
return child_exited;
}
template <typename C, typename T>
inline basic_pstreambuf<C,T>*
basic_pstreambuf<C,T>::kill(int signal)
{
basic_pstreambuf<C,T>* ret = NULL;
if (is_open())
{
if (::kill(ppid_, signal))
error_ = errno;
else
{
#if 0
// TODO call exited() to check for exit and clean up? leave to user?
if (signal==SIGTERM || signal==SIGKILL)
this->exited();
#endif
ret = this;
}
}
return ret;
}
template <typename C, typename T>
inline basic_pstreambuf<C,T>*
basic_pstreambuf<C,T>::killpg(int signal)
{
basic_pstreambuf<C,T>* ret = NULL;
#ifdef _POSIX_JOB_CONTROL
if (is_open())
{
pid_t pgid = ::getpgid(ppid_);
if (pgid == -1)
error_ = errno;
else if (pgid == ::getpgrp())
error_ = EPERM; // Don't commit suicide
else if (::killpg(pgid, signal))
error_ = errno;
else
ret = this;
}
#else
error_ = ENOTSUP;
#endif
return ret;
}
template <typename C, typename T>
inline bool
basic_pstreambuf<C,T>::exited()
{
return ppid_ == 0 || wait(true)==1;
}
template <typename C, typename T>
inline int
basic_pstreambuf<C,T>::status() const
{
return status_;
}
template <typename C, typename T>
inline int
basic_pstreambuf<C,T>::error() const
{
return error_;
}
template <typename C, typename T>
inline void
basic_pstreambuf<C,T>::peof()
{
sync();
destroy_buffers(pstdin);
close_fd(wpipe_);
}
template <typename C, typename T>
inline bool
basic_pstreambuf<C,T>::is_open() const
{
return ppid_ > 0;
}
template <typename C, typename T>
inline bool
basic_pstreambuf<C,T>::read_err(bool readerr)
{
buf_read_src src = readerr ? rsrc_err : rsrc_out;
if (rpipe_[src]>=0)
{
switch_read_buffer(src);
return true;
}
return false;
}
template <typename C, typename T>
typename basic_pstreambuf<C,T>::int_type
basic_pstreambuf<C,T>::overflow(int_type c)
{
if (!empty_buffer())
return traits_type::eof();
else if (!traits_type::eq_int_type(c, traits_type::eof()))
return this->sputc(c);
else
return traits_type::not_eof(c);
}
template <typename C, typename T>
int
basic_pstreambuf<C,T>::sync()
{
return !exited() && empty_buffer() ? 0 : -1;
}
template <typename C, typename T>
std::streamsize
basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
{
std::streamsize done = 0;
while (done < n)
{
if (std::streamsize nbuf = this->epptr() - this->pptr())
{
nbuf = std::min(nbuf, n - done);
traits_type::copy(this->pptr(), s + done, nbuf);
this->pbump(nbuf);
done += nbuf;
}
else if (!empty_buffer())
break;
}
return done;
}
template <typename C, typename T>
bool
basic_pstreambuf<C,T>::empty_buffer()
{
const std::streamsize count = this->pptr() - this->pbase();
if (count > 0)
{
const std::streamsize written = this->write(this->wbuffer_, count);
if (written > 0)
{
if (const std::streamsize unwritten = count - written)
traits_type::move(this->pbase(), this->pbase()+written, unwritten);
this->pbump(-written);
return true;
}
}
return false;
}
template <typename C, typename T>
typename basic_pstreambuf<C,T>::int_type
basic_pstreambuf<C,T>::underflow()
{
if (this->gptr() < this->egptr() || fill_buffer())
return traits_type::to_int_type(*this->gptr());
else
return traits_type::eof();
}
template <typename C, typename T>
typename basic_pstreambuf<C,T>::int_type
basic_pstreambuf<C,T>::pbackfail(int_type c)
{
if (this->gptr() != this->eback())
{
this->gbump(-1);
if (!traits_type::eq_int_type(c, traits_type::eof()))
*this->gptr() = traits_type::to_char_type(c);
return traits_type::not_eof(c);
}
else
return traits_type::eof();
}
template <typename C, typename T>
std::streamsize
basic_pstreambuf<C,T>::showmanyc()
{
int avail = 0;
if (sizeof(char_type) == 1)
avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
#ifdef FIONREAD
else
{
if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
avail = -1;
else if (avail)
avail /= sizeof(char_type);
}
#endif
return std::streamsize(avail);
}
template <typename C, typename T>
bool
basic_pstreambuf<C,T>::fill_buffer(bool non_blocking)
{
const std::streamsize pb1 = this->gptr() - this->eback();
const std::streamsize pb2 = pbsz;
const std::streamsize npb = std::min(pb1, pb2);
char_type* const rbuf = rbuffer();
if (npb)
traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
std::streamsize rc = -1;
if (non_blocking)
{
const int flags = ::fcntl(rpipe(), F_GETFL);
if (flags != -1)
{
const bool blocking = !(flags & O_NONBLOCK);
if (blocking)
::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking
error_ = 0;
rc = read(rbuf + pbsz, bufsz - pbsz);
if (rc == -1 && error_ == EAGAIN) // nothing available
rc = 0;
else if (rc == 0) // EOF
rc = -1;
if (blocking)
::fcntl(rpipe(), F_SETFL, flags); // restore
}
}
else
rc = read(rbuf + pbsz, bufsz - pbsz);
if (rc > 0 || (rc == 0 && non_blocking))
{
this->setg( rbuf + pbsz - npb,
rbuf + pbsz,
rbuf + pbsz + rc );
return true;
}
else
{
this->setg(NULL, NULL, NULL);
return false;
}
}
template <typename C, typename T>
inline std::streamsize
basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
{
std::streamsize nwritten = 0;
if (wpipe() >= 0)
{
nwritten = ::write(wpipe(), s, n * sizeof(char_type));
if (nwritten == -1)
error_ = errno;
else
nwritten /= sizeof(char_type);
}
return nwritten;
}
template <typename C, typename T>
inline std::streamsize
basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
{
std::streamsize nread = 0;
if (rpipe() >= 0)
{
nread = ::read(rpipe(), s, n * sizeof(char_type));
if (nread == -1)
error_ = errno;
else
nread /= sizeof(char_type);
}
return nread;
}
template <typename C, typename T>
inline pstreams::fd_type&
basic_pstreambuf<C,T>::wpipe()
{
return wpipe_;
}
template <typename C, typename T>
inline pstreams::fd_type&
basic_pstreambuf<C,T>::rpipe()
{
return rpipe_[rsrc_];
}
template <typename C, typename T>
inline pstreams::fd_type&
basic_pstreambuf<C,T>::rpipe(buf_read_src which)
{
return rpipe_[which];
}
template <typename C, typename T>
inline typename basic_pstreambuf<C,T>::char_type*
basic_pstreambuf<C,T>::rbuffer()
{
return rbuffer_[rsrc_];
}
/*
* member definitions for pstream_common
*/
template <typename C, typename T>
inline
pstream_common<C,T>::pstream_common()
: std::basic_ios<C,T>(NULL)
, command_()
, buf_()
{
this->std::basic_ios<C,T>::rdbuf(&buf_);
}
template <typename C, typename T>
inline
pstream_common<C,T>::pstream_common(const std::string& cmd, pmode mode)
: std::basic_ios<C,T>(NULL)
, command_(cmd)
, buf_()
{
this->std::basic_ios<C,T>::rdbuf(&buf_);
do_open(cmd, mode);
}
template <typename C, typename T>
inline
pstream_common<C,T>::pstream_common( const std::string& file,
const argv_type& argv,
pmode mode )
: std::basic_ios<C,T>(NULL)
, command_(file)
, buf_()
{
this->std::basic_ios<C,T>::rdbuf(&buf_);
do_open(file, argv, mode);
}
template <typename C, typename T>
inline
pstream_common<C,T>::~pstream_common()
{
}
template <typename C, typename T>
inline void
pstream_common<C,T>::do_open(const std::string& cmd, pmode mode)
{
if (!buf_.open((command_=cmd), mode))
this->setstate(std::ios_base::failbit);
}
template <typename C, typename T>
inline void
pstream_common<C,T>::do_open( const std::string& file,
const argv_type& argv,
pmode mode )
{
if (!buf_.open((command_=file), argv, mode))
this->setstate(std::ios_base::failbit);
}
template <typename C, typename T>
inline int
pstream_common<C,T>::close()
{
if (!buf_.close())
this->setstate(std::ios_base::failbit);
return buf_.status();
}
template <typename C, typename T>
inline bool
pstream_common<C,T>::is_open() const
{
return buf_.is_open();
}
template <typename C, typename T>
inline const std::string&
pstream_common<C,T>::command() const
{
return command_;
}
// TODO document behaviour if buffer replaced.
template <typename C, typename T>
inline typename pstream_common<C,T>::streambuf_type*
pstream_common<C,T>::rdbuf() const
{
return const_cast<streambuf_type*>(&buf_);
}
#if REDI_EVISCERATE_PSTREAMS
template <typename C, typename T>
std::size_t
basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
{
in = out = err = NULL;
std::size_t open_files = 0;
if (wpipe() > -1)
{
if ((in = ::fdopen(wpipe(), "w")))
{
open_files |= pstdin;
}
}
if (rpipe(rsrc_out) > -1)
{
if ((out = ::fdopen(rpipe(rsrc_out), "r")))
{
open_files |= pstdout;
}
}
if (rpipe(rsrc_err) > -1)
{
if ((err = ::fdopen(rpipe(rsrc_err), "r")))
{
open_files |= pstderr;
}
}
return open_files;
}
template <typename C, typename T>
inline std::size_t
pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
{
return buf_.fopen(fin, fout, ferr);
}
#endif // REDI_EVISCERATE_PSTREAMS
} // namespace redi
#endif // REDI_PSTREAM_H_SEEN
// vim: ts=2 sw=2 expandtab
redi::basic_rpstream::argv_type
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:926
redi::basic_pstreambuf::xsputn
std::streamsize xsputn(const char_type *s, std::streamsize n)
Insert multiple characters into the pipe.
Definition: pstream.h:1973
redi::pstream_common::~pstream_common
virtual ~pstream_common()=0
Pure virtual destructor.
Definition: pstream.h:2282
redi::basic_ipstream::pmode
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:399
redi::basic_pstreambuf::rpipe
fd_type & rpipe(buf_read_src which)
Return the file descriptor for the specified input pipe.
Definition: pstream.h:2193
redi::basic_opstream
Class template for Output PStreams.
Definition: pstream.h:563
redi::opstream
basic_opstream< char > opstream
Type definition for common template specialisation.
Definition: pstream.h:1087
redi::basic_rpstream::open
void open(const std::string &cmd, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:1033
redi::basic_opstream::basic_opstream
basic_opstream(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:607
redi::basic_pstreambuf::~basic_pstreambuf
~basic_pstreambuf()
Destructor.
Definition: pstream.h:1200
redi::pstream_common
Class template for common base class.
Definition: pstream.h:284
redi::basic_pstreambuf::buf_read_src
buf_read_src
Enumerated type to indicate whether stdout or stderr is to be read.
Definition: pstream.h:214
redi::basic_rpstream::out
istream_type & out()
Obtain a reference to the istream that reads the process' stdout.
Definition: pstream.h:1062
redi::basic_pstreambuf::open
basic_pstreambuf * open(const std::string &cmd, pmode mode)
Initialise the stream buffer with cmd.
Definition: pstream.h:1292
redi::rpstream
basic_rpstream< char > rpstream
Type definition for common template specialisation.
Definition: pstream.h:1091
redi::basic_pstreambuf::empty_buffer
bool empty_buffer()
Writes buffered characters to the process' stdin pipe.
Definition: pstream.h:1996
redi::basic_rpstream::open
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:1049
redi::basic_rpstream::basic_rpstream
basic_rpstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:929
redi::basic_ipstream::basic_ipstream
basic_ipstream(const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:452
redi::basic_pstreambuf::fork
pid_t fork(pmode mode)
Initialise pipes and fork process.
Definition: pstream.h:1500
redi::basic_pstream::~basic_pstream
~basic_pstream()
Destructor.
Definition: pstream.h:828
redi::basic_opstream::basic_opstream
basic_opstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:577
redi::basic_opstream::basic_opstream
basic_opstream(const std::string &cmd, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:592
redi::basic_opstream::pmode
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:571
redi::pstream_common::pstream_common
pstream_common(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:2260
redi::pstreams::argv_type
std::vector< std::string > argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:71
redi::basic_pstreambuf::wait
int wait(bool nohang=false)
Wait for the child process to exit.
Definition: pstream.h:1748
redi::basic_ipstream::open
void open(const std::string &cmd, pmode mode=pstdout)
Start a process.
Definition: pstream.h:502
redi::pstream_common::buf_
streambuf_type buf_
The stream buffer.
Definition: pstream.h:364
redi::basic_pstream::open
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:856
redi::basic_pstreambuf::rpipe
fd_type & rpipe()
Return the file descriptor for the active input pipe.
Definition: pstream.h:2185
redi::basic_pstream::basic_pstream
basic_pstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:767
redi::basic_rpstream::basic_rpstream
basic_rpstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:976
redi::pstream_common::command
const std::string & command() const
Return the command used to initialise the stream.
Definition: pstream.h:2346
redi::pstreams::pstderr
static const pmode pstderr
Read from stderr.
Definition: pstream.h:78
redi::basic_pstreambuf::killpg
basic_pstreambuf * killpg(int signal=SIGTERM)
Send a signal to the process' process group.
Definition: pstream.h:1826
redi::basic_pstreambuf::peof
void peof()
Close the pipe connected to the process' stdin.
Definition: pstream.h:1891
redi::basic_pstreambuf::overflow
int_type overflow(int_type c)
Transfer characters to the pipe when character buffer overflows.
Definition: pstream.h:1948
redi::basic_pstreambuf::write
std::streamsize write(const char_type *s, std::streamsize n)
Insert a sequence of characters into the pipe.
Definition: pstream.h:2137
redi::pstream_common::pstream_common
pstream_common()
Default constructor.
Definition: pstream.h:2222
redi::basic_ipstream::argv_type
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:402
redi::basic_ipstream::err
basic_ipstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:541
redi::pstream_common::is_open
bool is_open() const
Report whether the stream's buffer has been initialised.
Definition: pstream.h:2338
redi::basic_pstream::err
basic_pstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:879
redi::pstreams::pstdout
static const pmode pstdout
Read from stdout.
Definition: pstream.h:77
redi::ipstream
basic_ipstream< char > ipstream
Type definition for common template specialisation.
Definition: pstream.h:1085
redi::basic_ipstream::basic_ipstream
basic_ipstream(const std::string &cmd, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:420
redi::basic_pstreambuf
Class template for stream buffer.
Definition: pstream.h:98
redi::basic_pstreambuf::showmanyc
std::streamsize showmanyc()
Report how many characters can be read from active input without blocking.
Definition: pstream.h:2055
redi::basic_pstream::basic_pstream
basic_pstream(const std::string &cmd, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:752
redi::basic_pstreambuf::kill
basic_pstreambuf * kill(int signal=SIGTERM)
Send a signal to the process.
Definition: pstream.h:1791
redi::pstream_common::command_
std::string command_
The command used to start the process.
Definition: pstream.h:363
redi::basic_pstream::out
basic_pstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:868
redi::pstream_common::close
int close()
Definition: pstream.h:2325
redi::basic_pstreambuf::close_fd
void close_fd(pstreams::fd_type &fd)
Helper function to close a file descriptor.
Definition: pstream.h:1339
redi::pstreams
Common base class providing constants and typenames.
Definition: pstream.h:66
redi::basic_rpstream::basic_rpstream
basic_rpstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:959
redi::pstream_common::do_open
void do_open(const std::string &file, const argv_type &argv, pmode mode)
Start a process.
Definition: pstream.h:2313
redi::basic_opstream::argv_type
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:574
redi::basic_pstream
Class template for Bidirectional PStreams.
Definition: pstream.h:723
redi::pstreams::fd_type
int fd_type
Type used for file descriptors.
Definition: pstream.h:74
redi::basic_pstreambuf::rbuffer
char_type * rbuffer()
Return the active input buffer.
Definition: pstream.h:2201
redi::pstreambuf
basic_pstreambuf< char > pstreambuf
Type definition for common template specialisation.
Definition: pstream.h:1083
redi::pstream
basic_pstream< char > pstream
Type definition for common template specialisation.
Definition: pstream.h:1089
redi::basic_ipstream::basic_ipstream
basic_ipstream(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:435
redi::pstreams::newpg
static const pmode newpg
Create a new process group for the child process.
Definition: pstream.h:81
redi::basic_opstream::basic_opstream
basic_opstream(const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:624
redi::basic_ipstream::out
basic_ipstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:530
redi::basic_pstreambuf::fill_buffer
bool fill_buffer(bool non_blocking=false)
Definition: pstream.h:2077
redi::basic_ipstream::basic_ipstream
basic_ipstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:405
redi::pstream_common::rdbuf
streambuf_type * rdbuf() const
Return a pointer to the stream buffer.
Definition: pstream.h:2355
redi::basic_pstreambuf::error
int error() const
Return the error number (errno) for the most recent failed operation.
Definition: pstream.h:1880
redi::basic_rpstream::pmode
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:923
redi::basic_opstream::peof
std::basic_ostream< C, T > & peof(std::basic_ostream< C, T > &s)
Manipulator to close the pipe connected to the process' stdin.
Definition: pstream.h:1108
redi::basic_rpstream::~basic_rpstream
~basic_rpstream()
Destructor.
Definition: pstream.h:1021
redi::basic_pstreambuf::basic_pstreambuf
basic_pstreambuf()
Default constructor.
Definition: pstream.h:1130
redi::basic_pstreambuf::underflow
int_type underflow()
Transfer characters from the pipe when the character buffer is empty.
Definition: pstream.h:2022
redi::basic_pstreambuf::close_fd_array
void close_fd_array(pstreams::fd_type(&fds)[N])
Helper function to close an array of file descriptors.
Definition: pstream.h:1357
redi::basic_pstream::basic_pstream
basic_pstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:784
redi::basic_pstream::argv_type
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:734
redi::pstream_common::do_open
void do_open(const std::string &cmd, pmode mode)
Start a process.
Definition: pstream.h:2296
redi::basic_pstreambuf::fd_t
fd_type fd_t
Definition: pstream.h:107
redi::basic_pstreambuf::wpipe
fd_type & wpipe()
Return the file descriptor for the output pipe.
Definition: pstream.h:2177
redi
All PStreams classes are declared in namespace redi.
redi::basic_ipstream
Class template for Input PStreams.
Definition: pstream.h:383
redi::basic_pstreambuf::status
int status() const
Return the exit status of the process.
Definition: pstream.h:1870
redi::basic_ipstream::open
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Start a process.
Definition: pstream.h:518
redi::pstreams::pmode
std::ios_base::openmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:68
redi::basic_pstreambuf::is_open
bool is_open() const
Report whether the stream buffer has been initialised.
Definition: pstream.h:1910
redi::basic_pstreambuf::pbackfail
int_type pbackfail(int_type c=traits_type::eof())
Make a character available to be returned by the next extraction.
Definition: pstream.h:2040
redi::basic_pstreambuf::read
std::streamsize read(char_type *s, std::streamsize n)
Extract a sequence of characters from the pipe.
Definition: pstream.h:2160
redi::basic_pstream::pmode
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:731
redi::basic_opstream::open
void open(const std::string &cmd, pmode mode=pstdin)
Start a process.
Definition: pstream.h:680
redi::basic_pstreambuf::open
basic_pstreambuf * open(const std::string &file, const argv_type &argv, pmode mode)
Initialise the stream buffer with file and argv.
Definition: pstream.h:1394
redi::basic_pstreambuf::basic_pstreambuf
basic_pstreambuf(const std::string &cmd, pmode mode)
Constructor that initialises the buffer with cmd.
Definition: pstream.h:1153
redi::basic_ipstream::~basic_ipstream
~basic_ipstream()
Destructor.
Definition: pstream.h:489
redi::basic_pstream::open
void open(const std::string &cmd, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:840
redi::basic_pstreambuf::read_err
bool read_err(bool readerr=true)
Change active input source.
Definition: pstream.h:1925
redi::basic_pstreambuf::sync
int sync()
Write any buffered characters to the stream.
Definition: pstream.h:1961
redi::basic_pstream::basic_pstream
basic_pstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:737
redi::basic_opstream::open
void open(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Start a process.
Definition: pstream.h:696
redi::basic_pstreambuf::exited
bool exited()
Report whether the process has exited.
Definition: pstream.h:1857
redi::pstream_common::pstream_common
pstream_common(const std::string &cmd, pmode mode)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:2240
redi::basic_opstream::~basic_opstream
~basic_opstream()
Destructor.
Definition: pstream.h:668
redi::basic_pstreambuf::basic_pstreambuf
basic_pstreambuf(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the buffer with file and argv.
Definition: pstream.h:1178
redi::basic_rpstream::err
istream_type & err()
Obtain a reference to the istream that reads the process' stderr.
Definition: pstream.h:1074
redi::basic_rpstream
Class template for Restricted PStreams.
Definition: pstream.h:914
redi::basic_pstreambuf::close
basic_pstreambuf * close()
Close the stream buffer and wait for the process to exit.
Definition: pstream.h:1617
redi::pstreams::pstdin
static const pmode pstdin
Write to stdin.
Definition: pstream.h:76
redi::basic_rpstream::basic_rpstream
basic_rpstream(const std::string &cmd, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:944