00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00031 #ifndef REDI_PSTREAM_H_SEEN
00032 #define REDI_PSTREAM_H_SEEN
00033
00034 #include <ios>
00035 #include <streambuf>
00036 #include <istream>
00037 #include <ostream>
00038 #include <string>
00039 #include <vector>
00040 #include <algorithm>
00041 #include <cstring>
00042 #include <cerrno>
00043 #include <cstddef>
00044 #include <cstdlib>
00045 #include <sys/types.h>
00046 #include <sys/wait.h>
00047 #include <sys/ioctl.h>
00048 #if defined(__sun)
00049 # include <sys/filio.h>
00050 #endif
00051 #include <unistd.h>
00052 #include <signal.h>
00053 #include <fcntl.h>
00054 #if REDI_EVISCERATE_PSTREAMS
00055 # include <stdio.h>
00056 #endif
00057
00058
00060 #define PSTREAMS_VERSION 0x0052 // 0.5.2
00061
00075 namespace redi
00076 {
00078 struct pstreams
00079 {
00081 typedef std::ios_base::openmode pmode;
00082
00084 typedef std::vector<std::string> argv_type;
00085
00087 typedef int fd_type;
00088
00089 static const pmode pstdin = std::ios_base::out;
00090 static const pmode pstdout = std::ios_base::in;
00091 static const pmode pstderr = std::ios_base::app;
00092
00093 protected:
00094 enum { bufsz = 32 };
00095 enum { pbsz = 2 };
00096 };
00097
00099 template <typename CharT, typename Traits = std::char_traits<CharT> >
00100 class basic_pstreambuf
00101 : public std::basic_streambuf<CharT, Traits>
00102 , public pstreams
00103 {
00104 public:
00105
00106 typedef CharT char_type;
00107 typedef Traits traits_type;
00108 typedef typename traits_type::int_type int_type;
00109 typedef typename traits_type::off_type off_type;
00110 typedef typename traits_type::pos_type pos_type;
00112 typedef fd_type fd_t;
00113
00115 basic_pstreambuf();
00116
00118 basic_pstreambuf(const std::string& command, pmode mode);
00119
00121 basic_pstreambuf( const std::string& file,
00122 const argv_type& argv,
00123 pmode mode );
00124
00126 ~basic_pstreambuf();
00127
00129 basic_pstreambuf*
00130 open(const std::string& command, pmode mode);
00131
00133 basic_pstreambuf*
00134 open(const std::string& file, const argv_type& argv, pmode mode);
00135
00137 basic_pstreambuf*
00138 close();
00139
00141 basic_pstreambuf*
00142 kill(int signal = SIGTERM);
00143
00145 void
00146 peof();
00147
00149 bool
00150 read_err(bool readerr = true);
00151
00153 bool
00154 is_open() const;
00155
00157 bool
00158 exited();
00159
00160 #if REDI_EVISCERATE_PSTREAMS
00161
00162 std::size_t
00163 fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00164 #endif
00165
00167 int
00168 status() const;
00169
00171 int
00172 error() const;
00173
00174 protected:
00176 int_type
00177 overflow(int_type c);
00178
00180 int_type
00181 underflow();
00182
00184 int_type
00185 pbackfail(int_type c = traits_type::eof());
00186
00188 int
00189 sync();
00190
00192 std::streamsize
00193 xsputn(const char_type* s, std::streamsize n);
00194
00196 std::streamsize
00197 write(const char_type* s, std::streamsize n);
00198
00200 std::streamsize
00201 read(char_type* s, std::streamsize n);
00202
00204 std::streamsize
00205 showmanyc();
00206
00207 protected:
00209 enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
00210
00212 pid_t
00213 fork(pmode mode);
00214
00216 int
00217 wait(bool nohang = false);
00218
00220 fd_type&
00221 wpipe();
00222
00224 fd_type&
00225 rpipe();
00226
00228 fd_type&
00229 rpipe(buf_read_src which);
00230
00231 void
00232 create_buffers(pmode mode);
00233
00234 void
00235 destroy_buffers(pmode mode);
00236
00238 bool
00239 empty_buffer();
00240
00241 bool
00242 fill_buffer();
00243
00245 char_type*
00246 rbuffer();
00247
00248 buf_read_src
00249 switch_read_buffer(buf_read_src);
00250
00251 private:
00252 basic_pstreambuf(const basic_pstreambuf&);
00253 basic_pstreambuf& operator=(const basic_pstreambuf&);
00254
00255 void
00256 init_rbuffers();
00257
00258 pid_t ppid_;
00259 fd_type wpipe_;
00260 fd_type rpipe_[2];
00261 char_type* wbuffer_;
00262 char_type* rbuffer_[2];
00263 char_type* rbufstate_[3];
00265 buf_read_src rsrc_;
00266 int status_;
00267 int error_;
00268 };
00269
00271 template <typename CharT, typename Traits = std::char_traits<CharT> >
00272 class pstream_common
00273 : virtual public std::basic_ios<CharT, Traits>
00274 , virtual public pstreams
00275 {
00276 protected:
00277 typedef basic_pstreambuf<CharT, Traits> streambuf_type;
00278
00280 pstream_common();
00281
00283 pstream_common(const std::string& command, pmode mode);
00284
00286 pstream_common(const std::string& file, const argv_type& argv, pmode mode);
00287
00289 virtual
00290 ~pstream_common() = 0;
00291
00293 void
00294 do_open(const std::string& command, pmode mode);
00295
00297 void
00298 do_open(const std::string& file, const argv_type& argv, pmode mode);
00299
00300 public:
00302 void
00303 close();
00304
00306 bool
00307 is_open() const;
00308
00310 const std::string&
00311 command() const;
00312
00314 streambuf_type*
00315 rdbuf() const;
00316
00317 #if REDI_EVISCERATE_PSTREAMS
00318
00319 std::size_t
00320 fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00321 #endif
00322
00323 protected:
00324 std::string command_;
00325 streambuf_type buf_;
00326 };
00327
00328
00339 template <typename CharT, typename Traits = std::char_traits<CharT> >
00340 class basic_ipstream
00341 : public std::basic_istream<CharT, Traits>
00342 , public pstream_common<CharT, Traits>
00343 , virtual public pstreams
00344 {
00345 typedef std::basic_istream<CharT, Traits> istream_type;
00346 typedef pstream_common<CharT, Traits> pbase_type;
00347
00348 using pbase_type::buf_;
00349
00350 public:
00352 typedef typename pbase_type::pmode pmode;
00353
00355 typedef typename pbase_type::argv_type argv_type;
00356
00358 basic_ipstream()
00359 : istream_type(NULL), pbase_type()
00360 { }
00361
00372 basic_ipstream(const std::string& command, pmode mode = pstdout)
00373 : istream_type(NULL), pbase_type(command, mode|pstdout)
00374 { }
00375
00387 basic_ipstream( const std::string& file,
00388 const argv_type& argv,
00389 pmode mode = pstdout )
00390 : istream_type(NULL), pbase_type(file, argv, mode|pstdout)
00391 { }
00392
00398 ~basic_ipstream()
00399 { }
00400
00410 void
00411 open(const std::string& command, pmode mode = pstdout)
00412 {
00413 this->do_open(command, mode|pstdout);
00414 }
00415
00426 void
00427 open( const std::string& file,
00428 const argv_type& argv,
00429 pmode mode = pstdout )
00430 {
00431 this->do_open(file, argv, mode|pstdout);
00432 }
00433
00438 basic_ipstream&
00439 out()
00440 {
00441 this->buf_.read_err(false);
00442 return *this;
00443 }
00444
00449 basic_ipstream&
00450 err()
00451 {
00452 this->buf_.read_err(true);
00453 return *this;
00454 }
00455 };
00456
00457
00467 template <typename CharT, typename Traits = std::char_traits<CharT> >
00468 class basic_opstream
00469 : public std::basic_ostream<CharT, Traits>
00470 , public pstream_common<CharT, Traits>
00471 , virtual public pstreams
00472 {
00473 typedef std::basic_ostream<CharT, Traits> ostream_type;
00474 typedef pstream_common<CharT, Traits> pbase_type;
00475
00476 using pbase_type::buf_;
00477
00478 public:
00480 typedef typename pbase_type::pmode pmode;
00481
00483 typedef typename pbase_type::argv_type argv_type;
00484
00486 basic_opstream()
00487 : ostream_type(NULL), pbase_type()
00488 { }
00489
00500 basic_opstream(const std::string& command, pmode mode = pstdin)
00501 : ostream_type(NULL), pbase_type(command, mode|pstdin)
00502 { }
00503
00515 basic_opstream( const std::string& file,
00516 const argv_type& argv,
00517 pmode mode = pstdin )
00518 : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
00519 { }
00520
00526 ~basic_opstream() { }
00527
00537 void
00538 open(const std::string& command, pmode mode = pstdin)
00539 {
00540 this->do_open(command, mode|pstdin);
00541 }
00542
00553 void
00554 open( const std::string& file,
00555 const argv_type& argv,
00556 pmode mode = pstdin)
00557 {
00558 this->do_open(file, argv, mode|pstdin);
00559 }
00560 };
00561
00562
00576 template <typename CharT, typename Traits = std::char_traits<CharT> >
00577 class basic_pstream
00578 : public std::basic_iostream<CharT, Traits>
00579 , public pstream_common<CharT, Traits>
00580 , virtual public pstreams
00581 {
00582 typedef std::basic_iostream<CharT, Traits> iostream_type;
00583 typedef pstream_common<CharT, Traits> pbase_type;
00584
00585 using pbase_type::buf_;
00586
00587 public:
00589 typedef typename pbase_type::pmode pmode;
00590
00592 typedef typename pbase_type::argv_type argv_type;
00593
00595 basic_pstream()
00596 : iostream_type(NULL), pbase_type()
00597 { }
00598
00609 basic_pstream(const std::string& command, pmode mode = pstdout|pstdin)
00610 : iostream_type(NULL), pbase_type(command, mode)
00611 { }
00612
00624 basic_pstream( const std::string& file,
00625 const argv_type& argv,
00626 pmode mode = pstdout|pstdin )
00627 : iostream_type(NULL), pbase_type(file, argv, mode)
00628 { }
00629
00635 ~basic_pstream() { }
00636
00646 void
00647 open(const std::string& command, pmode mode = pstdout|pstdin)
00648 {
00649 this->do_open(command, mode);
00650 }
00651
00662 void
00663 open( const std::string& file,
00664 const argv_type& argv,
00665 pmode mode = pstdout|pstdin )
00666 {
00667 this->do_open(file, argv, mode);
00668 }
00669
00674 basic_pstream&
00675 out()
00676 {
00677 this->buf_.read_err(false);
00678 return *this;
00679 }
00680
00685 basic_pstream&
00686 err()
00687 {
00688 this->buf_.read_err(true);
00689 return *this;
00690 }
00691 };
00692
00693
00715 template <typename CharT, typename Traits = std::char_traits<CharT> >
00716 class basic_rpstream
00717 : public std::basic_ostream<CharT, Traits>
00718 , private std::basic_istream<CharT, Traits>
00719 , private pstream_common<CharT, Traits>
00720 , virtual public pstreams
00721 {
00722 typedef std::basic_ostream<CharT, Traits> ostream_type;
00723 typedef std::basic_istream<CharT, Traits> istream_type;
00724 typedef pstream_common<CharT, Traits> pbase_type;
00725
00726 using pbase_type::buf_;
00727
00728 public:
00730 typedef typename pbase_type::pmode pmode;
00731
00733 typedef typename pbase_type::argv_type argv_type;
00734
00736 basic_rpstream()
00737 : ostream_type(NULL), istream_type(NULL), pbase_type()
00738 { }
00739
00750 basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
00751 : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
00752 { }
00753
00765 basic_rpstream( const std::string& file,
00766 const argv_type& argv,
00767 pmode mode = pstdout|pstdin )
00768 : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
00769 { }
00770
00772 ~basic_rpstream() { }
00773
00783 void
00784 open(const std::string& command, pmode mode = pstdout|pstdin)
00785 {
00786 this->do_open(command, mode);
00787 }
00788
00799 void
00800 open( const std::string& file,
00801 const argv_type& argv,
00802 pmode mode = pstdout|pstdin )
00803 {
00804 this->do_open(file, argv, mode);
00805 }
00806
00812 istream_type&
00813 out()
00814 {
00815 this->buf_.read_err(false);
00816 return *this;
00817 }
00818
00824 istream_type&
00825 err()
00826 {
00827 this->buf_.read_err(true);
00828 return *this;
00829 }
00830 };
00831
00832
00834 typedef basic_pstreambuf<char> pstreambuf;
00836 typedef basic_ipstream<char> ipstream;
00838 typedef basic_opstream<char> opstream;
00840 typedef basic_pstream<char> pstream;
00842 typedef basic_rpstream<char> rpstream;
00843
00844
00857 template <typename C, typename T>
00858 inline std::basic_ostream<C,T>&
00859 peof(std::basic_ostream<C,T>& s)
00860 {
00861 typedef basic_pstreambuf<C,T> pstreambuf;
00862 if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
00863 p->peof();
00864 return s;
00865 }
00866
00867
00868
00869
00870
00871
00872
00879 template <typename C, typename T>
00880 inline
00881 basic_pstreambuf<C,T>::basic_pstreambuf()
00882 : ppid_(-1)
00883 , wpipe_(-1)
00884 , wbuffer_(NULL)
00885 , rsrc_(rsrc_out)
00886 , status_(-1)
00887 , error_(0)
00888 {
00889 init_rbuffers();
00890 }
00891
00900 template <typename C, typename T>
00901 inline
00902 basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
00903 : ppid_(-1)
00904 , wpipe_(-1)
00905 , wbuffer_(NULL)
00906 , rsrc_(rsrc_out)
00907 , status_(-1)
00908 , error_(0)
00909 {
00910 init_rbuffers();
00911 open(command, mode);
00912 }
00913
00923 template <typename C, typename T>
00924 inline
00925 basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
00926 const argv_type& argv,
00927 pmode mode )
00928 : ppid_(-1)
00929 , wpipe_(-1)
00930 , wbuffer_(NULL)
00931 , rsrc_(rsrc_out)
00932 , status_(-1)
00933 , error_(0)
00934 {
00935 init_rbuffers();
00936 open(file, argv, mode);
00937 }
00938
00943 template <typename C, typename T>
00944 inline
00945 basic_pstreambuf<C,T>::~basic_pstreambuf()
00946 {
00947 close();
00948 }
00949
00970 template <typename C, typename T>
00971 basic_pstreambuf<C,T>*
00972 basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
00973 {
00974 #if 0
00975 const std::string argv[] = { "sh", "-c", command };
00976 return this->open("sh", std::vector<std::string>(argv, argv+3), mode);
00977 #else
00978 basic_pstreambuf<C,T>* ret = NULL;
00979
00980 if (!is_open())
00981 {
00982 switch(fork(mode))
00983 {
00984 case 0 :
00985
00986 ::execlp("sh", "sh", "-c", command.c_str(), (void*)NULL);
00987
00988
00989
00990
00991 ::_exit(errno);
00992
00993
00994 case -1 :
00995
00996 break;
00997
00998 default :
00999
01000
01001 create_buffers(mode);
01002 ret = this;
01003 }
01004 }
01005 return ret;
01006 #endif
01007 }
01008
01017 inline void
01018 close_fd(pstreams::fd_type& fd)
01019 {
01020 if (fd >= 0 && ::close(fd) == 0)
01021 fd = -1;
01022 }
01023
01034 template <int N>
01035 inline void
01036 close_fd_array(pstreams::fd_type (&fds)[N])
01037 {
01038 for (std::size_t i = 0; i < N; ++i)
01039 close_fd(fds[i]);
01040 }
01041
01063 template <typename C, typename T>
01064 basic_pstreambuf<C,T>*
01065 basic_pstreambuf<C,T>::open( const std::string& file,
01066 const argv_type& argv,
01067 pmode mode )
01068 {
01069 basic_pstreambuf<C,T>* ret = NULL;
01070
01071 if (!is_open())
01072 {
01073
01074 enum { RD, WR };
01075
01076
01077 fd_type ck_exec[] = { -1, -1 };
01078 if (-1 == ::pipe(ck_exec)
01079 || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
01080 || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
01081 {
01082 error_ = errno;
01083 close_fd_array(ck_exec);
01084 }
01085 else
01086 {
01087 switch(fork(mode))
01088 {
01089 case 0 :
01090
01091 {
01092 char** arg_v = new char*[argv.size()+1];
01093 for (std::size_t i = 0; i < argv.size(); ++i)
01094 {
01095 const std::string& src = argv[i];
01096 char*& dest = arg_v[i];
01097 dest = new char[src.size()+1];
01098 dest[ src.copy(dest, src.size()) ] = '\0';
01099 }
01100 arg_v[argv.size()] = NULL;
01101
01102 ::execvp(file.c_str(), arg_v);
01103
01104
01105
01106
01107 error_ = errno;
01108
01109 ::write(ck_exec[WR], &error_, sizeof(error_));
01110 ::close(ck_exec[WR]);
01111 ::close(ck_exec[RD]);
01112
01113 ::_exit(error_);
01114
01115 }
01116
01117 case -1 :
01118
01119 close_fd_array(ck_exec);
01120 break;
01121
01122 default :
01123
01124
01125
01126 ::close(ck_exec[WR]);
01127 switch (::read(ck_exec[RD], &error_, sizeof(error_)))
01128 {
01129 case 0:
01130
01131 create_buffers(mode);
01132 ret = this;
01133 break;
01134 case -1:
01135 error_ = errno;
01136 break;
01137 default:
01138
01139
01140 this->wait();
01141 break;
01142 }
01143 ::close(ck_exec[RD]);
01144 }
01145 }
01146 }
01147 return ret;
01148 }
01149
01166 template <typename C, typename T>
01167 pid_t
01168 basic_pstreambuf<C,T>::fork(pmode mode)
01169 {
01170 pid_t pid = -1;
01171
01172
01173
01174
01175 fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
01176 fd_type* const pin = fd;
01177 fd_type* const pout = fd+2;
01178 fd_type* const perr = fd+4;
01179
01180
01181 enum { RD, WR };
01182
01183
01184
01185
01186
01187 if (!error_ && mode&pstdin && ::pipe(pin))
01188 error_ = errno;
01189
01190 if (!error_ && mode&pstdout && ::pipe(pout))
01191 error_ = errno;
01192
01193 if (!error_ && mode&pstderr && ::pipe(perr))
01194 error_ = errno;
01195
01196 if (!error_)
01197 {
01198 pid = ::fork();
01199 switch (pid)
01200 {
01201 case 0 :
01202 {
01203
01204
01205
01206
01207
01208 if (*pin >= 0)
01209 {
01210 ::close(pin[WR]);
01211 ::dup2(pin[RD], STDIN_FILENO);
01212 ::close(pin[RD]);
01213 }
01214 if (*pout >= 0)
01215 {
01216 ::close(pout[RD]);
01217 ::dup2(pout[WR], STDOUT_FILENO);
01218 ::close(pout[WR]);
01219 }
01220 if (*perr >= 0)
01221 {
01222 ::close(perr[RD]);
01223 ::dup2(perr[WR], STDERR_FILENO);
01224 ::close(perr[WR]);
01225 }
01226 break;
01227 }
01228 case -1 :
01229 {
01230
01231 error_ = errno;
01232
01233 close_fd_array(fd);
01234 break;
01235 }
01236 default :
01237 {
01238
01239 ppid_ = pid;
01240
01241
01242 if (*pin >= 0)
01243 {
01244 wpipe_ = pin[WR];
01245 ::close(pin[RD]);
01246 }
01247 if (*pout >= 0)
01248 {
01249 rpipe_[rsrc_out] = pout[RD];
01250 ::close(pout[WR]);
01251 }
01252 if (*perr >= 0)
01253 {
01254 rpipe_[rsrc_err] = perr[RD];
01255 ::close(perr[WR]);
01256 }
01257
01258 if (rpipe_[rsrc_out] == -1 && rpipe_[rsrc_err] >= 0)
01259 {
01260
01261 read_err(true);
01262 }
01263 }
01264 }
01265 }
01266 else
01267 {
01268
01269 close_fd_array(fd);
01270 }
01271 return pid;
01272 }
01273
01283 template <typename C, typename T>
01284 basic_pstreambuf<C,T>*
01285 basic_pstreambuf<C,T>::close()
01286 {
01287 basic_pstreambuf<C,T>* ret = NULL;
01288 if (is_open())
01289 {
01290 sync();
01291
01292 destroy_buffers(pstdin|pstdout|pstderr);
01293
01294
01295 close_fd(wpipe_);
01296 close_fd_array(rpipe_);
01297
01298 if (wait() == 1)
01299 {
01300 ret = this;
01301 }
01302 }
01303 return ret;
01304 }
01305
01309 template <typename C, typename T>
01310 inline void
01311 basic_pstreambuf<C,T>::init_rbuffers()
01312 {
01313 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
01314 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
01315 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
01316 }
01317
01318 template <typename C, typename T>
01319 void
01320 basic_pstreambuf<C,T>::create_buffers(pmode mode)
01321 {
01322 if (mode & pstdin)
01323 {
01324 delete[] wbuffer_;
01325 wbuffer_ = new char_type[bufsz];
01326 this->setp(wbuffer_, wbuffer_ + bufsz);
01327 }
01328 if (mode & pstdout)
01329 {
01330 delete[] rbuffer_[rsrc_out];
01331 rbuffer_[rsrc_out] = new char_type[bufsz];
01332 if (rsrc_ == rsrc_out)
01333 this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
01334 rbuffer_[rsrc_out] + pbsz);
01335 }
01336 if (mode & pstderr)
01337 {
01338 delete[] rbuffer_[rsrc_err];
01339 rbuffer_[rsrc_err] = new char_type[bufsz];
01340 if (rsrc_ == rsrc_err)
01341 this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
01342 rbuffer_[rsrc_err] + pbsz);
01343 }
01344 }
01345
01346 template <typename C, typename T>
01347 void
01348 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
01349 {
01350 if (mode & pstdin)
01351 {
01352 this->setp(NULL, NULL);
01353 delete[] wbuffer_;
01354 wbuffer_ = NULL;
01355 }
01356 if (mode & pstdout)
01357 {
01358 if (rsrc_ == rsrc_out)
01359 this->setg(NULL, NULL, NULL);
01360 delete[] rbuffer_[rsrc_out];
01361 rbuffer_[rsrc_out] = NULL;
01362 }
01363 if (mode & pstderr)
01364 {
01365 if (rsrc_ == rsrc_err)
01366 this->setg(NULL, NULL, NULL);
01367 delete[] rbuffer_[rsrc_err];
01368 rbuffer_[rsrc_err] = NULL;
01369 }
01370 }
01371
01372 template <typename C, typename T>
01373 typename basic_pstreambuf<C,T>::buf_read_src
01374 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
01375 {
01376 if (rsrc_ != src)
01377 {
01378 char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
01379 this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
01380 for (std::size_t i = 0; i < 3; ++i)
01381 rbufstate_[i] = tmpbufstate[i];
01382 rsrc_ = src;
01383 }
01384 return rsrc_;
01385 }
01386
01399 template <typename C, typename T>
01400 int
01401 basic_pstreambuf<C,T>::wait(bool nohang)
01402 {
01403 int exited = -1;
01404 if (is_open())
01405 {
01406 int status;
01407 switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
01408 {
01409 case 0 :
01410
01411 exited = 0;
01412 break;
01413 case -1 :
01414 error_ = errno;
01415 break;
01416 default :
01417
01418 ppid_ = 0;
01419 status_ = status;
01420 exited = 1;
01421 destroy_buffers(pstdin|pstdout|pstderr);
01422 close_fd(wpipe_);
01423 close_fd_array(rpipe_);
01424 break;
01425 }
01426 }
01427 return exited;
01428 }
01429
01440 template <typename C, typename T>
01441 inline basic_pstreambuf<C,T>*
01442 basic_pstreambuf<C,T>::kill(int signal)
01443 {
01444 basic_pstreambuf<C,T>* ret = NULL;
01445 if (is_open())
01446 {
01447 if (::kill(ppid_, signal))
01448 error_ = errno;
01449 else
01450 {
01451
01452 ret = this;
01453 }
01454 }
01455 return ret;
01456 }
01457
01462 template <typename C, typename T>
01463 inline bool
01464 basic_pstreambuf<C,T>::exited()
01465 {
01466 return ppid_ == 0 || wait(true)==1;
01467 }
01468
01469
01475 template <typename C, typename T>
01476 inline int
01477 basic_pstreambuf<C,T>::status() const
01478 {
01479 return status_;
01480 }
01481
01485 template <typename C, typename T>
01486 inline int
01487 basic_pstreambuf<C,T>::error() const
01488 {
01489 return error_;
01490 }
01491
01496 template <typename C, typename T>
01497 inline void
01498 basic_pstreambuf<C,T>::peof()
01499 {
01500 sync();
01501 destroy_buffers(pstdin);
01502 close_fd(wpipe_);
01503 }
01504
01515 template <typename C, typename T>
01516 inline bool
01517 basic_pstreambuf<C,T>::is_open() const
01518 {
01519 return ppid_ > 0;
01520 }
01521
01530 template <typename C, typename T>
01531 inline bool
01532 basic_pstreambuf<C,T>::read_err(bool readerr)
01533 {
01534 buf_read_src src = readerr ? rsrc_err : rsrc_out;
01535 if (rpipe_[src]>=0)
01536 {
01537 switch_read_buffer(src);
01538 return true;
01539 }
01540 return false;
01541 }
01542
01552 template <typename C, typename T>
01553 typename basic_pstreambuf<C,T>::int_type
01554 basic_pstreambuf<C,T>::overflow(int_type c)
01555 {
01556 if (!empty_buffer())
01557 return traits_type::eof();
01558 else if (!traits_type::eq_int_type(c, traits_type::eof()))
01559 return this->sputc(c);
01560 else
01561 return traits_type::not_eof(c);
01562 }
01563
01564
01565 template <typename C, typename T>
01566 int
01567 basic_pstreambuf<C,T>::sync()
01568 {
01569 return !exited() && empty_buffer() ? 0 : -1;
01570 }
01571
01577 template <typename C, typename T>
01578 std::streamsize
01579 basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
01580 {
01581 if (n < this->epptr() - this->pptr())
01582 {
01583 std::memcpy(this->pptr(), s, n * sizeof(char_type));
01584 this->pbump(n);
01585 return n;
01586 }
01587 else
01588 {
01589 for (std::streamsize i = 0; i < n; ++i)
01590 {
01591 if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof()))
01592 return i;
01593 }
01594 return n;
01595 }
01596 }
01597
01601 template <typename C, typename T>
01602 bool
01603 basic_pstreambuf<C,T>::empty_buffer()
01604 {
01605 const std::streamsize count = this->pptr() - this->pbase();
01606 const std::streamsize written = this->write(this->wbuffer_, count);
01607 if (count > 0 && written == count)
01608 {
01609 this->pbump(-written);
01610 return true;
01611 }
01612 return false;
01613 }
01614
01622 template <typename C, typename T>
01623 typename basic_pstreambuf<C,T>::int_type
01624 basic_pstreambuf<C,T>::underflow()
01625 {
01626 if (this->gptr() < this->egptr() || fill_buffer())
01627 return traits_type::to_int_type(*this->gptr());
01628 else
01629 return traits_type::eof();
01630 }
01631
01640 template <typename C, typename T>
01641 typename basic_pstreambuf<C,T>::int_type
01642 basic_pstreambuf<C,T>::pbackfail(int_type c)
01643 {
01644 if (this->gptr() != this->eback())
01645 {
01646 this->gbump(-1);
01647 if (!traits_type::eq_int_type(c, traits_type::eof()))
01648 *this->gptr() = traits_type::to_char_type(c);
01649 return traits_type::not_eof(c);
01650 }
01651 else
01652 return traits_type::eof();
01653 }
01654
01655 template <typename C, typename T>
01656 std::streamsize
01657 basic_pstreambuf<C,T>::showmanyc()
01658 {
01659 int avail = 0;
01660 #ifdef FIONREAD
01661 if (ioctl(rpipe(), FIONREAD, &avail) == -1)
01662 avail = -1;
01663 else
01664 #endif
01665 if (const std::ptrdiff_t buflen = this->gptr() - this->eback())
01666 avail += buflen;
01667 return std::streamsize(avail);
01668 }
01669
01673 template <typename C, typename T>
01674 bool
01675 basic_pstreambuf<C,T>::fill_buffer()
01676 {
01677 const std::streamsize pb1 = this->gptr() - this->eback();
01678 const std::streamsize pb2 = pbsz;
01679 const std::streamsize npb = std::min(pb1, pb2);
01680
01681 std::memmove( rbuffer() + pbsz - npb,
01682 this->gptr() - npb,
01683 npb * sizeof(char_type) );
01684
01685 const std::streamsize rc = read(rbuffer() + pbsz, bufsz - pbsz);
01686
01687 if (rc > 0)
01688 {
01689 this->setg( rbuffer() + pbsz - npb,
01690 rbuffer() + pbsz,
01691 rbuffer() + pbsz + rc );
01692 return true;
01693 }
01694 else
01695 {
01696 this->setg(NULL, NULL, NULL);
01697 return false;
01698 }
01699 }
01700
01710 template <typename C, typename T>
01711 inline std::streamsize
01712 basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
01713 {
01714 return wpipe() >= 0 ? ::write(wpipe(), s, n * sizeof(char_type)) : 0;
01715 }
01716
01726 template <typename C, typename T>
01727 inline std::streamsize
01728 basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
01729 {
01730 return rpipe() >= 0 ? ::read(rpipe(), s, n * sizeof(char_type)) : 0;
01731 }
01732
01734 template <typename C, typename T>
01735 inline typename basic_pstreambuf<C,T>::fd_type&
01736 basic_pstreambuf<C,T>::wpipe()
01737 {
01738 return wpipe_;
01739 }
01740
01742 template <typename C, typename T>
01743 inline typename basic_pstreambuf<C,T>::fd_type&
01744 basic_pstreambuf<C,T>::rpipe()
01745 {
01746 return rpipe_[rsrc_];
01747 }
01748
01750 template <typename C, typename T>
01751 inline typename basic_pstreambuf<C,T>::fd_type&
01752 basic_pstreambuf<C,T>::rpipe(buf_read_src which)
01753 {
01754 return rpipe_[which];
01755 }
01756
01758 template <typename C, typename T>
01759 inline typename basic_pstreambuf<C,T>::char_type*
01760 basic_pstreambuf<C,T>::rbuffer()
01761 {
01762 return rbuffer_[rsrc_];
01763 }
01764
01765
01766
01767
01768
01769
01779 template <typename C, typename T>
01780 inline
01781 pstream_common<C,T>::pstream_common()
01782 : std::basic_ios<C,T>(NULL)
01783 , command_()
01784 , buf_()
01785 {
01786 this->init(&buf_);
01787 }
01788
01797 template <typename C, typename T>
01798 inline
01799 pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
01800 : std::basic_ios<C,T>(NULL)
01801 , command_(command)
01802 , buf_()
01803 {
01804 this->init(&buf_);
01805 do_open(command, mode);
01806 }
01807
01817 template <typename C, typename T>
01818 inline
01819 pstream_common<C,T>::pstream_common( const std::string& file,
01820 const argv_type& argv,
01821 pmode mode )
01822 : std::basic_ios<C,T>(NULL)
01823 , command_(file)
01824 , buf_()
01825 {
01826 this->init(&buf_);
01827 do_open(file, argv, mode);
01828 }
01829
01839 template <typename C, typename T>
01840 inline
01841 pstream_common<C,T>::~pstream_common()
01842 {
01843 }
01844
01853 template <typename C, typename T>
01854 inline void
01855 pstream_common<C,T>::do_open(const std::string& command, pmode mode)
01856 {
01857 if (!buf_.open((command_=command), mode))
01858 this->setstate(std::ios_base::failbit);
01859 }
01860
01870 template <typename C, typename T>
01871 inline void
01872 pstream_common<C,T>::do_open( const std::string& file,
01873 const argv_type& argv,
01874 pmode mode )
01875 {
01876 if (!buf_.open((command_=file), argv, mode))
01877 this->setstate(std::ios_base::failbit);
01878 }
01879
01881 template <typename C, typename T>
01882 inline void
01883 pstream_common<C,T>::close()
01884 {
01885 if (!buf_.close())
01886 this->setstate(std::ios_base::failbit);
01887 }
01888
01893 template <typename C, typename T>
01894 inline bool
01895 pstream_common<C,T>::is_open() const
01896 {
01897 return buf_.is_open();
01898 }
01899
01901 template <typename C, typename T>
01902 inline const std::string&
01903 pstream_common<C,T>::command() const
01904 {
01905 return command_;
01906 }
01907
01909
01910 template <typename C, typename T>
01911 inline typename pstream_common<C,T>::streambuf_type*
01912 pstream_common<C,T>::rdbuf() const
01913 {
01914 return const_cast<streambuf_type*>(&buf_);
01915 }
01916
01917
01918 #if REDI_EVISCERATE_PSTREAMS
01951 template <typename C, typename T>
01952 std::size_t
01953 basic_pstreambuf<C,T>::fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err)
01954 {
01955 in = out = err = NULL;
01956 std::size_t open_files = 0;
01957 if (wpipe() > -1)
01958 {
01959 if ((in = ::fdopen(wpipe(), "w")))
01960 {
01961 open_files |= pstdin;
01962 }
01963 }
01964 if (rpipe(rsrc_out) > -1)
01965 {
01966 if ((out = ::fdopen(rpipe(rsrc_out), "r")))
01967 {
01968 open_files |= pstdout;
01969 }
01970 }
01971 if (rpipe(rsrc_err) > -1)
01972 {
01973 if ((err = ::fdopen(rpipe(rsrc_err), "r")))
01974 {
01975 open_files |= pstderr;
01976 }
01977 }
01978 return open_files;
01979 }
01980
01991 template <typename C, typename T>
01992 inline std::size_t
01993 pstream_common<C,T>::fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err)
01994 {
01995 return buf_.fopen(in, out, err);
01996 }
01997
01998 #endif // REDI_EVISCERATE_PSTREAMS
01999
02000
02001 }
02002
02008 #endif // REDI_PSTREAM_H_SEEN
02009
02010
02011