30 #ifndef REDI_PSTREAM_H_SEEN
31 #define REDI_PSTREAM_H_SEEN
43 #include <sys/types.h>
45 #include <sys/ioctl.h>
47 # include <sys/filio.h>
52 #if REDI_EVISCERATE_PSTREAMS
58 #define PSTREAMS_VERSION 0x0070 // 0.7.0
79 typedef std::ios_base::openmode
pmode;
97 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
99 :
public std::basic_streambuf<CharT, Traits>
104 typedef CharT char_type;
105 typedef Traits traits_type;
106 typedef typename traits_type::int_type int_type;
107 typedef typename traits_type::off_type off_type;
108 typedef typename traits_type::pos_type pos_type;
128 open(
const std::string& command,
pmode mode);
140 kill(
int signal = SIGTERM);
158 #if REDI_EVISCERATE_PSTREAMS
161 fopen(FILE*& in, FILE*& out, FILE*& err);
183 pbackfail(int_type c = traits_type::eof());
191 xsputn(
const char_type* s, std::streamsize n);
195 write(
const char_type* s, std::streamsize n);
199 read(char_type* s, std::streamsize n);
215 wait(
bool nohang =
false);
230 create_buffers(
pmode mode);
233 destroy_buffers(
pmode mode);
260 char_type* rbuffer_[2];
261 char_type* rbufstate_[3];
269 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
271 :
virtual public std::basic_ios<CharT, Traits>
318 #if REDI_EVISCERATE_PSTREAMS
321 fopen(FILE*& in, FILE*& out, FILE*& err);
340 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
342 :
public std::basic_istream<CharT, Traits>
346 typedef std::basic_istream<CharT, Traits> istream_type;
381 : istream_type(NULL),
pbase_type(command, readable(mode))
398 : istream_type(NULL),
pbase_type(file, argv, readable(mode))
421 this->
do_open(command, readable(mode));
439 this->
do_open(file, argv, readable(mode));
475 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
477 :
public std::basic_ostream<CharT, Traits>
481 typedef std::basic_ostream<CharT, Traits> ostream_type;
584 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
586 :
public std::basic_iostream<CharT, Traits>
590 typedef std::basic_iostream<CharT, Traits> iostream_type;
618 : iostream_type(NULL),
pbase_type(command, mode)
635 : iostream_type(NULL),
pbase_type(file, argv, mode)
675 this->
do_open(file, argv, mode);
723 template <
typename CharT,
typename Traits = std::
char_traits<CharT> >
725 :
public std::basic_ostream<CharT, Traits>
726 ,
private std::basic_istream<CharT, Traits>
730 typedef std::basic_ostream<CharT, Traits> ostream_type;
731 typedef std::basic_istream<CharT, Traits> istream_type;
745 : ostream_type(NULL), istream_type(NULL),
pbase_type()
759 : ostream_type(NULL) , istream_type(NULL) ,
pbase_type(command, mode)
776 : ostream_type(NULL), istream_type(NULL),
pbase_type(file, argv, mode)
812 this->
do_open(file, argv, mode);
865 template <
typename C,
typename T>
866 inline std::basic_ostream<C,T>&
867 peof(std::basic_ostream<C,T>& s)
870 if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
887 template <
typename C,
typename T>
908 template <
typename C,
typename T>
931 template <
typename C,
typename T>
944 open(file, argv, mode);
951 template <
typename C,
typename T>
985 template <
typename C,
typename T>
989 const char * shell_path =
"/bin/sh";
991 const std::string argv[] = {
"sh",
"-c", command };
992 return this->open(shell_path,
argv_type(argv, argv+3), mode);
1002 ::execl(shell_path,
"sh",
"-c", command.c_str(), (
char*)NULL);
1017 create_buffers(mode);
1036 if (fd >= 0 && ::close(fd) == 0)
1054 for (std::size_t i = 0; i < N; ++i)
1087 template <
typename C,
typename T>
1101 fd_type ck_exec[] = { -1, -1 };
1102 if (-1 == ::pipe(ck_exec)
1103 || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
1104 || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
1107 close_fd_array(ck_exec);
1116 char** arg_v =
new char*[argv.size()+1];
1117 for (std::size_t i = 0; i < argv.size(); ++i)
1119 const std::string& src = argv[i];
1120 char*& dest = arg_v[i];
1121 dest =
new char[src.size()+1];
1122 dest[ src.copy(dest, src.size()) ] =
'\0';
1124 arg_v[argv.size()] = NULL;
1126 ::execvp(file.c_str(), arg_v);
1133 ::write(ck_exec[WR], &error_,
sizeof(error_));
1134 ::close(ck_exec[WR]);
1135 ::close(ck_exec[RD]);
1143 close_fd_array(ck_exec);
1150 ::close(ck_exec[WR]);
1151 switch (::read(ck_exec[RD], &error_,
sizeof(error_)))
1155 create_buffers(mode);
1167 ::close(ck_exec[RD]);
1190 template <
typename C,
typename T>
1199 fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
1200 fd_type*
const pin = fd;
1201 fd_type*
const pout = fd+2;
1202 fd_type*
const perr = fd+4;
1211 if (!error_ && mode&pstdin && ::pipe(pin))
1214 if (!error_ && mode&pstdout && ::pipe(pout))
1217 if (!error_ && mode&pstderr && ::pipe(perr))
1235 ::dup2(pin[RD], STDIN_FILENO);
1241 ::dup2(pout[WR], STDOUT_FILENO);
1247 ::dup2(perr[WR], STDERR_FILENO);
1273 rpipe_[rsrc_out] = pout[RD];
1278 rpipe_[rsrc_err] = perr[RD];
1301 template <
typename C,
typename T>
1305 const bool running = is_open();
1312 destroy_buffers(pstdin|pstdout|pstderr);
1316 close_fd_array(rpipe_);
1321 }
while (wait() == -1 && error() == EINTR);
1323 return running ?
this : NULL;
1329 template <
typename C,
typename T>
1333 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1334 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
1335 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
1338 template <
typename C,
typename T>
1340 basic_pstreambuf<C,T>::create_buffers(pmode mode)
1345 wbuffer_ =
new char_type[bufsz];
1346 this->setp(wbuffer_, wbuffer_ + bufsz);
1350 delete[] rbuffer_[rsrc_out];
1351 rbuffer_[rsrc_out] =
new char_type[bufsz];
1353 this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
1354 rbuffer_[rsrc_out] + pbsz);
1358 delete[] rbuffer_[rsrc_err];
1359 rbuffer_[rsrc_err] =
new char_type[bufsz];
1360 if (!(mode & pstdout))
1363 this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
1364 rbuffer_[rsrc_err] + pbsz);
1369 template <
typename C,
typename T>
1371 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
1375 this->setp(NULL, NULL);
1381 if (rsrc_ == rsrc_out)
1382 this->setg(NULL, NULL, NULL);
1383 delete[] rbuffer_[rsrc_out];
1384 rbuffer_[rsrc_out] = NULL;
1388 if (rsrc_ == rsrc_err)
1389 this->setg(NULL, NULL, NULL);
1390 delete[] rbuffer_[rsrc_err];
1391 rbuffer_[rsrc_err] = NULL;
1395 template <
typename C,
typename T>
1396 typename basic_pstreambuf<C,T>::buf_read_src
1397 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
1401 char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
1402 this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
1403 for (std::size_t i = 0; i < 3; ++i)
1404 rbufstate_[i] = tmpbufstate[i];
1426 template <
typename C,
typename T>
1434 switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
1449 destroy_buffers(pstdin);
1469 template <
typename C,
typename T>
1476 if (::kill(ppid_, signal))
1482 if (signal==SIGTERM || signal==SIGKILL)
1498 template <
typename C,
typename T>
1502 return ppid_ == 0 || wait(
true)==1;
1511 template <
typename C,
typename T>
1521 template <
typename C,
typename T>
1532 template <
typename C,
typename T>
1537 destroy_buffers(pstdin);
1551 template <
typename C,
typename T>
1566 template <
typename C,
typename T>
1573 switch_read_buffer(src);
1589 template <
typename C,
typename T>
1590 typename basic_pstreambuf<C,T>::int_type
1593 if (!empty_buffer())
1594 return traits_type::eof();
1595 else if (!traits_type::eq_int_type(c, traits_type::eof()))
1596 return this->sputc(c);
1598 return traits_type::not_eof(c);
1602 template <
typename C,
typename T>
1606 return !exited() && empty_buffer() ? 0 : -1;
1614 template <
typename C,
typename T>
1618 if (n < this->epptr() - this->pptr())
1620 traits_type::copy(this->pptr(), s, n);
1626 for (std::streamsize i = 0; i < n; ++i)
1628 if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof()))
1638 template <
typename C,
typename T>
1642 const std::streamsize count = this->pptr() - this->pbase();
1645 const std::streamsize written = this->write(this->wbuffer_, count);
1648 if (
const std::streamsize unwritten = count - written)
1649 traits_type::move(this->pbase(), this->pbase()+written, unwritten);
1650 this->pbump(-written);
1664 template <
typename C,
typename T>
1665 typename basic_pstreambuf<C,T>::int_type
1668 if (this->gptr() < this->egptr() || fill_buffer())
1669 return traits_type::to_int_type(*this->gptr());
1671 return traits_type::eof();
1682 template <
typename C,
typename T>
1683 typename basic_pstreambuf<C,T>::int_type
1686 if (this->gptr() != this->eback())
1689 if (!traits_type::eq_int_type(c, traits_type::eof()))
1690 *this->gptr() = traits_type::to_char_type(c);
1691 return traits_type::not_eof(c);
1694 return traits_type::eof();
1697 template <
typename C,
typename T>
1702 if (
sizeof(char_type) == 1)
1703 avail = fill_buffer(
true) ? this->egptr() - this->gptr() : -1;
1707 if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
1710 avail /=
sizeof(char_type);
1713 return std::streamsize(avail);
1719 template <
typename C,
typename T>
1723 const std::streamsize pb1 = this->gptr() - this->eback();
1724 const std::streamsize pb2 = pbsz;
1725 const std::streamsize npb = std::min(pb1, pb2);
1727 char_type*
const rbuf = rbuffer();
1729 traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
1731 std::streamsize rc = -1;
1735 const int flags = ::fcntl(rpipe(), F_GETFL);
1738 const bool blocking = !(flags & O_NONBLOCK);
1740 ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK);
1743 rc = read(rbuf + pbsz, bufsz - pbsz);
1745 if (rc == -1 && error_ == EAGAIN)
1751 ::fcntl(rpipe(), F_SETFL, flags);
1755 rc = read(rbuf + pbsz, bufsz - pbsz);
1757 if (rc > 0 || (rc == 0 && non_blocking))
1759 this->setg( rbuf + pbsz - npb,
1766 this->setg(NULL, NULL, NULL);
1778 template <
typename C,
typename T>
1779 inline std::streamsize
1782 std::streamsize nwritten = 0;
1785 nwritten = ::write(wpipe(), s, n *
sizeof(char_type));
1789 nwritten /=
sizeof(char_type);
1801 template <
typename C,
typename T>
1802 inline std::streamsize
1805 std::streamsize nread = 0;
1808 nread = ::read(rpipe(), s, n *
sizeof(char_type));
1812 nread /=
sizeof(char_type);
1818 template <
typename C,
typename T>
1826 template <
typename C,
typename T>
1830 return rpipe_[rsrc_];
1834 template <
typename C,
typename T>
1838 return rpipe_[which];
1842 template <
typename C,
typename T>
1843 inline typename basic_pstreambuf<C,T>::char_type*
1846 return rbuffer_[rsrc_];
1863 template <
typename C,
typename T>
1866 : std::basic_ios<C,T>(NULL)
1881 template <
typename C,
typename T>
1884 : std::basic_ios<C,T>(NULL)
1901 template <
typename C,
typename T>
1906 : std::basic_ios<C,T>(NULL)
1923 template <
typename C,
typename T>
1937 template <
typename C,
typename T>
1941 if (!buf_.open((command_=command), mode))
1942 this->setstate(std::ios_base::failbit);
1954 template <
typename C,
typename T>
1960 if (!buf_.open((command_=file), argv, mode))
1961 this->setstate(std::ios_base::failbit);
1965 template <
typename C,
typename T>
1970 this->setstate(std::ios_base::failbit);
1977 template <
typename C,
typename T>
1981 return buf_.is_open();
1985 template <
typename C,
typename T>
1986 inline const std::string&
1994 template <
typename C,
typename T>
2002 #if REDI_EVISCERATE_PSTREAMS
2035 template <
typename C,
typename T>
2039 in = out = err = NULL;
2040 std::size_t open_files = 0;
2043 if ((in = ::fdopen(wpipe(),
"w")))
2045 open_files |= pstdin;
2048 if (rpipe(rsrc_out) > -1)
2050 if ((out = ::fdopen(rpipe(rsrc_out),
"r")))
2052 open_files |= pstdout;
2055 if (rpipe(rsrc_err) > -1)
2057 if ((err = ::fdopen(rpipe(rsrc_err),
"r")))
2059 open_files |= pstderr;
2075 template <
typename C,
typename T>
2077 pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
2079 return buf_.fopen(fin, fout, ferr);
2082 #endif // REDI_EVISCERATE_PSTREAMS
2092 #endif // REDI_PSTREAM_H_SEEN