00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00030 #ifndef REDI_PSTREAM_H_SEEN
00031 #define REDI_PSTREAM_H_SEEN
00032
00033 #include <ios>
00034 #include <streambuf>
00035 #include <istream>
00036 #include <ostream>
00037 #include <string>
00038 #include <vector>
00039 #include <algorithm>
00040 #include <cerrno>
00041 #include <cstddef>
00042 #include <cstdlib>
00043 #include <sys/types.h>
00044 #include <sys/wait.h>
00045 #include <sys/ioctl.h>
00046 #if defined(__sun)
00047 # include <sys/filio.h>
00048 #endif
00049 #include <unistd.h>
00050 #include <signal.h>
00051 #include <fcntl.h>
00052 #if REDI_EVISCERATE_PSTREAMS
00053 # include <stdio.h>
00054 #endif
00055
00056
00058 #define PSTREAMS_VERSION 0x0060 // 0.6.0
00059
00073 namespace redi
00074 {
00076 struct pstreams
00077 {
00079 typedef std::ios_base::openmode pmode;
00080
00082 typedef std::vector<std::string> argv_type;
00083
00085 typedef int fd_type;
00086
00087 static const pmode pstdin = std::ios_base::out;
00088 static const pmode pstdout = std::ios_base::in;
00089 static const pmode pstderr = std::ios_base::app;
00090
00091 protected:
00092 enum { bufsz = 32 };
00093 enum { pbsz = 2 };
00094 };
00095
00097 template <typename CharT, typename Traits = std::char_traits<CharT> >
00098 class basic_pstreambuf
00099 : public std::basic_streambuf<CharT, Traits>
00100 , public pstreams
00101 {
00102 public:
00103
00104 typedef CharT char_type;
00105 typedef Traits traits_type;
00106 typedef typename traits_type::int_type int_type;
00107 typedef typename traits_type::off_type off_type;
00108 typedef typename traits_type::pos_type pos_type;
00110 typedef fd_type fd_t;
00111
00113 basic_pstreambuf();
00114
00116 basic_pstreambuf(const std::string& command, pmode mode);
00117
00119 basic_pstreambuf( const std::string& file,
00120 const argv_type& argv,
00121 pmode mode );
00122
00124 ~basic_pstreambuf();
00125
00127 basic_pstreambuf*
00128 open(const std::string& command, pmode mode);
00129
00131 basic_pstreambuf*
00132 open(const std::string& file, const argv_type& argv, pmode mode);
00133
00135 basic_pstreambuf*
00136 close();
00137
00139 basic_pstreambuf*
00140 kill(int signal = SIGTERM);
00141
00143 void
00144 peof();
00145
00147 bool
00148 read_err(bool readerr = true);
00149
00151 bool
00152 is_open() const;
00153
00155 bool
00156 exited();
00157
00158 #if REDI_EVISCERATE_PSTREAMS
00160 std::size_t
00161 fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00162 #endif
00163
00165 int
00166 status() const;
00167
00169 int
00170 error() const;
00171
00172 protected:
00174 int_type
00175 overflow(int_type c);
00176
00178 int_type
00179 underflow();
00180
00182 int_type
00183 pbackfail(int_type c = traits_type::eof());
00184
00186 int
00187 sync();
00188
00190 std::streamsize
00191 xsputn(const char_type* s, std::streamsize n);
00192
00194 std::streamsize
00195 write(const char_type* s, std::streamsize n);
00196
00198 std::streamsize
00199 read(char_type* s, std::streamsize n);
00200
00202 std::streamsize
00203 showmanyc();
00204
00205 protected:
00207 enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
00208
00210 pid_t
00211 fork(pmode mode);
00212
00214 int
00215 wait(bool nohang = false);
00216
00218 fd_type&
00219 wpipe();
00220
00222 fd_type&
00223 rpipe();
00224
00226 fd_type&
00227 rpipe(buf_read_src which);
00228
00229 void
00230 create_buffers(pmode mode);
00231
00232 void
00233 destroy_buffers(pmode mode);
00234
00236 bool
00237 empty_buffer();
00238
00239 bool
00240 fill_buffer(bool non_blocking = false);
00241
00243 char_type*
00244 rbuffer();
00245
00246 buf_read_src
00247 switch_read_buffer(buf_read_src);
00248
00249 private:
00250 basic_pstreambuf(const basic_pstreambuf&);
00251 basic_pstreambuf& operator=(const basic_pstreambuf&);
00252
00253 void
00254 init_rbuffers();
00255
00256 pid_t ppid_;
00257 fd_type wpipe_;
00258 fd_type rpipe_[2];
00259 char_type* wbuffer_;
00260 char_type* rbuffer_[2];
00261 char_type* rbufstate_[3];
00263 buf_read_src rsrc_;
00264 int status_;
00265 int error_;
00266 };
00267
00269 template <typename CharT, typename Traits = std::char_traits<CharT> >
00270 class pstream_common
00271 : virtual public std::basic_ios<CharT, Traits>
00272 , virtual public pstreams
00273 {
00274 protected:
00275 typedef basic_pstreambuf<CharT, Traits> streambuf_type;
00276
00277 #ifdef __SUNPRO_CC
00278 typedef pstreams::pmode pmode;
00279 typedef pstreams::argv_type argv_type;
00280 #endif
00281
00283 pstream_common();
00284
00286 pstream_common(const std::string& command, pmode mode);
00287
00289 pstream_common(const std::string& file, const argv_type& argv, pmode mode);
00290
00292 virtual
00293 ~pstream_common() = 0;
00294
00296 void
00297 do_open(const std::string& command, pmode mode);
00298
00300 void
00301 do_open(const std::string& file, const argv_type& argv, pmode mode);
00302
00303 public:
00305 void
00306 close();
00307
00309 bool
00310 is_open() const;
00311
00313 const std::string&
00314 command() const;
00315
00317 streambuf_type*
00318 rdbuf() const;
00319
00320 #if REDI_EVISCERATE_PSTREAMS
00322 std::size_t
00323 fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00324 #endif
00325
00326 protected:
00327 std::string command_;
00328 streambuf_type buf_;
00329 };
00330
00331
00342 template <typename CharT, typename Traits = std::char_traits<CharT> >
00343 class basic_ipstream
00344 : public std::basic_istream<CharT, Traits>
00345 , public pstream_common<CharT, Traits>
00346 , virtual public pstreams
00347 {
00348 typedef std::basic_istream<CharT, Traits> istream_type;
00349 typedef pstream_common<CharT, Traits> pbase_type;
00350
00351 using pbase_type::buf_;
00352
00353 public:
00355 typedef typename pbase_type::pmode pmode;
00356
00358 typedef typename pbase_type::argv_type argv_type;
00359
00361 basic_ipstream()
00362 : istream_type(NULL), pbase_type()
00363 { }
00364
00375 basic_ipstream(const std::string& command, pmode mode = pstdout)
00376 : istream_type(NULL), pbase_type(command, mode|pstdout)
00377 { }
00378
00390 basic_ipstream( const std::string& file,
00391 const argv_type& argv,
00392 pmode mode = pstdout )
00393 : istream_type(NULL), pbase_type(file, argv, mode|pstdout)
00394 { }
00395
00401 ~basic_ipstream()
00402 { }
00403
00413 void
00414 open(const std::string& command, pmode mode = pstdout)
00415 {
00416 this->do_open(command, mode|pstdout);
00417 }
00418
00429 void
00430 open( const std::string& file,
00431 const argv_type& argv,
00432 pmode mode = pstdout )
00433 {
00434 this->do_open(file, argv, mode|pstdout);
00435 }
00436
00441 basic_ipstream&
00442 out()
00443 {
00444 this->buf_.read_err(false);
00445 return *this;
00446 }
00447
00452 basic_ipstream&
00453 err()
00454 {
00455 this->buf_.read_err(true);
00456 return *this;
00457 }
00458 };
00459
00460
00470 template <typename CharT, typename Traits = std::char_traits<CharT> >
00471 class basic_opstream
00472 : public std::basic_ostream<CharT, Traits>
00473 , public pstream_common<CharT, Traits>
00474 , virtual public pstreams
00475 {
00476 typedef std::basic_ostream<CharT, Traits> ostream_type;
00477 typedef pstream_common<CharT, Traits> pbase_type;
00478
00479 using pbase_type::buf_;
00480
00481 public:
00483 typedef typename pbase_type::pmode pmode;
00484
00486 typedef typename pbase_type::argv_type argv_type;
00487
00489 basic_opstream()
00490 : ostream_type(NULL), pbase_type()
00491 { }
00492
00503 basic_opstream(const std::string& command, pmode mode = pstdin)
00504 : ostream_type(NULL), pbase_type(command, mode|pstdin)
00505 { }
00506
00518 basic_opstream( const std::string& file,
00519 const argv_type& argv,
00520 pmode mode = pstdin )
00521 : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
00522 { }
00523
00529 ~basic_opstream() { }
00530
00540 void
00541 open(const std::string& command, pmode mode = pstdin)
00542 {
00543 this->do_open(command, mode|pstdin);
00544 }
00545
00556 void
00557 open( const std::string& file,
00558 const argv_type& argv,
00559 pmode mode = pstdin)
00560 {
00561 this->do_open(file, argv, mode|pstdin);
00562 }
00563 };
00564
00565
00579 template <typename CharT, typename Traits = std::char_traits<CharT> >
00580 class basic_pstream
00581 : public std::basic_iostream<CharT, Traits>
00582 , public pstream_common<CharT, Traits>
00583 , virtual public pstreams
00584 {
00585 typedef std::basic_iostream<CharT, Traits> iostream_type;
00586 typedef pstream_common<CharT, Traits> pbase_type;
00587
00588 using pbase_type::buf_;
00589
00590 public:
00592 typedef typename pbase_type::pmode pmode;
00593
00595 typedef typename pbase_type::argv_type argv_type;
00596
00598 basic_pstream()
00599 : iostream_type(NULL), pbase_type()
00600 { }
00601
00612 basic_pstream(const std::string& command, pmode mode = pstdout|pstdin)
00613 : iostream_type(NULL), pbase_type(command, mode)
00614 { }
00615
00627 basic_pstream( const std::string& file,
00628 const argv_type& argv,
00629 pmode mode = pstdout|pstdin )
00630 : iostream_type(NULL), pbase_type(file, argv, mode)
00631 { }
00632
00638 ~basic_pstream() { }
00639
00649 void
00650 open(const std::string& command, pmode mode = pstdout|pstdin)
00651 {
00652 this->do_open(command, mode);
00653 }
00654
00665 void
00666 open( const std::string& file,
00667 const argv_type& argv,
00668 pmode mode = pstdout|pstdin )
00669 {
00670 this->do_open(file, argv, mode);
00671 }
00672
00677 basic_pstream&
00678 out()
00679 {
00680 this->buf_.read_err(false);
00681 return *this;
00682 }
00683
00688 basic_pstream&
00689 err()
00690 {
00691 this->buf_.read_err(true);
00692 return *this;
00693 }
00694 };
00695
00696
00718 template <typename CharT, typename Traits = std::char_traits<CharT> >
00719 class basic_rpstream
00720 : public std::basic_ostream<CharT, Traits>
00721 , private std::basic_istream<CharT, Traits>
00722 , private pstream_common<CharT, Traits>
00723 , virtual public pstreams
00724 {
00725 typedef std::basic_ostream<CharT, Traits> ostream_type;
00726 typedef std::basic_istream<CharT, Traits> istream_type;
00727 typedef pstream_common<CharT, Traits> pbase_type;
00728
00729 using pbase_type::buf_;
00730
00731 public:
00733 typedef typename pbase_type::pmode pmode;
00734
00736 typedef typename pbase_type::argv_type argv_type;
00737
00739 basic_rpstream()
00740 : ostream_type(NULL), istream_type(NULL), pbase_type()
00741 { }
00742
00753 basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
00754 : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
00755 { }
00756
00768 basic_rpstream( const std::string& file,
00769 const argv_type& argv,
00770 pmode mode = pstdout|pstdin )
00771 : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
00772 { }
00773
00775 ~basic_rpstream() { }
00776
00786 void
00787 open(const std::string& command, pmode mode = pstdout|pstdin)
00788 {
00789 this->do_open(command, mode);
00790 }
00791
00802 void
00803 open( const std::string& file,
00804 const argv_type& argv,
00805 pmode mode = pstdout|pstdin )
00806 {
00807 this->do_open(file, argv, mode);
00808 }
00809
00815 istream_type&
00816 out()
00817 {
00818 this->buf_.read_err(false);
00819 return *this;
00820 }
00821
00827 istream_type&
00828 err()
00829 {
00830 this->buf_.read_err(true);
00831 return *this;
00832 }
00833 };
00834
00835
00837 typedef basic_pstreambuf<char> pstreambuf;
00839 typedef basic_ipstream<char> ipstream;
00841 typedef basic_opstream<char> opstream;
00843 typedef basic_pstream<char> pstream;
00845 typedef basic_rpstream<char> rpstream;
00846
00847
00860 template <typename C, typename T>
00861 inline std::basic_ostream<C,T>&
00862 peof(std::basic_ostream<C,T>& s)
00863 {
00864 typedef basic_pstreambuf<C,T> pstreambuf;
00865 if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
00866 p->peof();
00867 return s;
00868 }
00869
00870
00871
00872
00873
00874
00875
00882 template <typename C, typename T>
00883 inline
00884 basic_pstreambuf<C,T>::basic_pstreambuf()
00885 : ppid_(-1)
00886 , wpipe_(-1)
00887 , wbuffer_(NULL)
00888 , rsrc_(rsrc_out)
00889 , status_(-1)
00890 , error_(0)
00891 {
00892 init_rbuffers();
00893 }
00894
00903 template <typename C, typename T>
00904 inline
00905 basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
00906 : ppid_(-1)
00907 , wpipe_(-1)
00908 , wbuffer_(NULL)
00909 , rsrc_(rsrc_out)
00910 , status_(-1)
00911 , error_(0)
00912 {
00913 init_rbuffers();
00914 open(command, mode);
00915 }
00916
00926 template <typename C, typename T>
00927 inline
00928 basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
00929 const argv_type& argv,
00930 pmode mode )
00931 : ppid_(-1)
00932 , wpipe_(-1)
00933 , wbuffer_(NULL)
00934 , rsrc_(rsrc_out)
00935 , status_(-1)
00936 , error_(0)
00937 {
00938 init_rbuffers();
00939 open(file, argv, mode);
00940 }
00941
00946 template <typename C, typename T>
00947 inline
00948 basic_pstreambuf<C,T>::~basic_pstreambuf()
00949 {
00950 close();
00951 }
00952
00976 template <typename C, typename T>
00977 basic_pstreambuf<C,T>*
00978 basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
00979 {
00980 const char * shell_path = "/bin/sh";
00981 #if 0
00982 const std::string argv[] = { "sh", "-c", command };
00983 return this->open(shell_path, argv_type(argv, argv+3), mode);
00984 #else
00985 basic_pstreambuf<C,T>* ret = NULL;
00986
00987 if (!is_open())
00988 {
00989 switch(fork(mode))
00990 {
00991 case 0 :
00992
00993 ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
00994
00995
00996
00997
00998 ::_exit(errno);
00999
01000
01001 case -1 :
01002
01003 break;
01004
01005 default :
01006
01007
01008 create_buffers(mode);
01009 ret = this;
01010 }
01011 }
01012 return ret;
01013 #endif
01014 }
01015
01024 inline void
01025 close_fd(pstreams::fd_type& fd)
01026 {
01027 if (fd >= 0 && ::close(fd) == 0)
01028 fd = -1;
01029 }
01030
01041 template <int N>
01042 inline void
01043 close_fd_array(pstreams::fd_type (&fds)[N])
01044 {
01045 for (std::size_t i = 0; i < N; ++i)
01046 close_fd(fds[i]);
01047 }
01048
01074 template <typename C, typename T>
01075 basic_pstreambuf<C,T>*
01076 basic_pstreambuf<C,T>::open( const std::string& file,
01077 const argv_type& argv,
01078 pmode mode )
01079 {
01080 basic_pstreambuf<C,T>* ret = NULL;
01081
01082 if (!is_open())
01083 {
01084
01085 enum { RD, WR };
01086
01087
01088 fd_type ck_exec[] = { -1, -1 };
01089 if (-1 == ::pipe(ck_exec)
01090 || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
01091 || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
01092 {
01093 error_ = errno;
01094 close_fd_array(ck_exec);
01095 }
01096 else
01097 {
01098 switch(fork(mode))
01099 {
01100 case 0 :
01101
01102 {
01103 char** arg_v = new char*[argv.size()+1];
01104 for (std::size_t i = 0; i < argv.size(); ++i)
01105 {
01106 const std::string& src = argv[i];
01107 char*& dest = arg_v[i];
01108 dest = new char[src.size()+1];
01109 dest[ src.copy(dest, src.size()) ] = '\0';
01110 }
01111 arg_v[argv.size()] = NULL;
01112
01113 ::execvp(file.c_str(), arg_v);
01114
01115
01116
01117
01118 error_ = errno;
01119
01120 ::write(ck_exec[WR], &error_, sizeof(error_));
01121 ::close(ck_exec[WR]);
01122 ::close(ck_exec[RD]);
01123
01124 ::_exit(error_);
01125
01126 }
01127
01128 case -1 :
01129
01130 close_fd_array(ck_exec);
01131 break;
01132
01133 default :
01134
01135
01136
01137 ::close(ck_exec[WR]);
01138 switch (::read(ck_exec[RD], &error_, sizeof(error_)))
01139 {
01140 case 0:
01141
01142 create_buffers(mode);
01143 ret = this;
01144 break;
01145 case -1:
01146 error_ = errno;
01147 break;
01148 default:
01149
01150
01151 this->wait();
01152 break;
01153 }
01154 ::close(ck_exec[RD]);
01155 }
01156 }
01157 }
01158 return ret;
01159 }
01160
01177 template <typename C, typename T>
01178 pid_t
01179 basic_pstreambuf<C,T>::fork(pmode mode)
01180 {
01181 pid_t pid = -1;
01182
01183
01184
01185
01186 fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
01187 fd_type* const pin = fd;
01188 fd_type* const pout = fd+2;
01189 fd_type* const perr = fd+4;
01190
01191
01192 enum { RD, WR };
01193
01194
01195
01196
01197
01198 if (!error_ && mode&pstdin && ::pipe(pin))
01199 error_ = errno;
01200
01201 if (!error_ && mode&pstdout && ::pipe(pout))
01202 error_ = errno;
01203
01204 if (!error_ && mode&pstderr && ::pipe(perr))
01205 error_ = errno;
01206
01207 if (!error_)
01208 {
01209 pid = ::fork();
01210 switch (pid)
01211 {
01212 case 0 :
01213 {
01214
01215
01216
01217
01218
01219 if (*pin >= 0)
01220 {
01221 ::close(pin[WR]);
01222 ::dup2(pin[RD], STDIN_FILENO);
01223 ::close(pin[RD]);
01224 }
01225 if (*pout >= 0)
01226 {
01227 ::close(pout[RD]);
01228 ::dup2(pout[WR], STDOUT_FILENO);
01229 ::close(pout[WR]);
01230 }
01231 if (*perr >= 0)
01232 {
01233 ::close(perr[RD]);
01234 ::dup2(perr[WR], STDERR_FILENO);
01235 ::close(perr[WR]);
01236 }
01237 break;
01238 }
01239 case -1 :
01240 {
01241
01242 error_ = errno;
01243
01244 close_fd_array(fd);
01245 break;
01246 }
01247 default :
01248 {
01249
01250 ppid_ = pid;
01251
01252
01253 if (*pin >= 0)
01254 {
01255 wpipe_ = pin[WR];
01256 ::close(pin[RD]);
01257 }
01258 if (*pout >= 0)
01259 {
01260 rpipe_[rsrc_out] = pout[RD];
01261 ::close(pout[WR]);
01262 }
01263 if (*perr >= 0)
01264 {
01265 rpipe_[rsrc_err] = perr[RD];
01266 ::close(perr[WR]);
01267 }
01268
01269 if (rpipe_[rsrc_out] == -1 && rpipe_[rsrc_err] >= 0)
01270 {
01271
01272 read_err(true);
01273 }
01274 }
01275 }
01276 }
01277 else
01278 {
01279
01280 close_fd_array(fd);
01281 }
01282 return pid;
01283 }
01284
01294 template <typename C, typename T>
01295 basic_pstreambuf<C,T>*
01296 basic_pstreambuf<C,T>::close()
01297 {
01298 const bool running = is_open();
01299
01300 sync();
01301
01302
01303
01304
01305 destroy_buffers(pstdin|pstdout|pstderr);
01306
01307
01308 close_fd(wpipe_);
01309 close_fd_array(rpipe_);
01310
01311 do
01312 {
01313 error_ = 0;
01314 } while (wait() == -1 && error() == EINTR);
01315
01316 return running ? this : NULL;
01317 }
01318
01322 template <typename C, typename T>
01323 inline void
01324 basic_pstreambuf<C,T>::init_rbuffers()
01325 {
01326 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
01327 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
01328 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
01329 }
01330
01331 template <typename C, typename T>
01332 void
01333 basic_pstreambuf<C,T>::create_buffers(pmode mode)
01334 {
01335 if (mode & pstdin)
01336 {
01337 delete[] wbuffer_;
01338 wbuffer_ = new char_type[bufsz];
01339 this->setp(wbuffer_, wbuffer_ + bufsz);
01340 }
01341 if (mode & pstdout)
01342 {
01343 delete[] rbuffer_[rsrc_out];
01344 rbuffer_[rsrc_out] = new char_type[bufsz];
01345 if (rsrc_ == rsrc_out)
01346 this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
01347 rbuffer_[rsrc_out] + pbsz);
01348 }
01349 if (mode & pstderr)
01350 {
01351 delete[] rbuffer_[rsrc_err];
01352 rbuffer_[rsrc_err] = new char_type[bufsz];
01353 if (rsrc_ == rsrc_err)
01354 this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
01355 rbuffer_[rsrc_err] + pbsz);
01356 }
01357 }
01358
01359 template <typename C, typename T>
01360 void
01361 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
01362 {
01363 if (mode & pstdin)
01364 {
01365 this->setp(NULL, NULL);
01366 delete[] wbuffer_;
01367 wbuffer_ = NULL;
01368 }
01369 if (mode & pstdout)
01370 {
01371 if (rsrc_ == rsrc_out)
01372 this->setg(NULL, NULL, NULL);
01373 delete[] rbuffer_[rsrc_out];
01374 rbuffer_[rsrc_out] = NULL;
01375 }
01376 if (mode & pstderr)
01377 {
01378 if (rsrc_ == rsrc_err)
01379 this->setg(NULL, NULL, NULL);
01380 delete[] rbuffer_[rsrc_err];
01381 rbuffer_[rsrc_err] = NULL;
01382 }
01383 }
01384
01385 template <typename C, typename T>
01386 typename basic_pstreambuf<C,T>::buf_read_src
01387 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
01388 {
01389 if (rsrc_ != src)
01390 {
01391 char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
01392 this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
01393 for (std::size_t i = 0; i < 3; ++i)
01394 rbufstate_[i] = tmpbufstate[i];
01395 rsrc_ = src;
01396 }
01397 return rsrc_;
01398 }
01399
01416 template <typename C, typename T>
01417 int
01418 basic_pstreambuf<C,T>::wait(bool nohang)
01419 {
01420 int exited = -1;
01421 if (is_open())
01422 {
01423 int status;
01424 switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
01425 {
01426 case 0 :
01427
01428 exited = 0;
01429 break;
01430 case -1 :
01431 error_ = errno;
01432 break;
01433 default :
01434
01435 ppid_ = 0;
01436 status_ = status;
01437 exited = 1;
01438
01439 destroy_buffers(pstdin);
01440 close_fd(wpipe_);
01441
01442
01443 break;
01444 }
01445 }
01446 return exited;
01447 }
01448
01459 template <typename C, typename T>
01460 inline basic_pstreambuf<C,T>*
01461 basic_pstreambuf<C,T>::kill(int signal)
01462 {
01463 basic_pstreambuf<C,T>* ret = NULL;
01464 if (is_open())
01465 {
01466 if (::kill(ppid_, signal))
01467 error_ = errno;
01468 else
01469 {
01470 #if 0
01471
01472 if (signal==SIGTERM || signal==SIGKILL)
01473 this->exited();
01474 #endif
01475 ret = this;
01476 }
01477 }
01478 return ret;
01479 }
01480
01488 template <typename C, typename T>
01489 inline bool
01490 basic_pstreambuf<C,T>::exited()
01491 {
01492 return ppid_ == 0 || wait(true)==1;
01493 }
01494
01495
01501 template <typename C, typename T>
01502 inline int
01503 basic_pstreambuf<C,T>::status() const
01504 {
01505 return status_;
01506 }
01507
01511 template <typename C, typename T>
01512 inline int
01513 basic_pstreambuf<C,T>::error() const
01514 {
01515 return error_;
01516 }
01517
01522 template <typename C, typename T>
01523 inline void
01524 basic_pstreambuf<C,T>::peof()
01525 {
01526 sync();
01527 destroy_buffers(pstdin);
01528 close_fd(wpipe_);
01529 }
01530
01541 template <typename C, typename T>
01542 inline bool
01543 basic_pstreambuf<C,T>::is_open() const
01544 {
01545 return ppid_ > 0;
01546 }
01547
01556 template <typename C, typename T>
01557 inline bool
01558 basic_pstreambuf<C,T>::read_err(bool readerr)
01559 {
01560 buf_read_src src = readerr ? rsrc_err : rsrc_out;
01561 if (rpipe_[src]>=0)
01562 {
01563 switch_read_buffer(src);
01564 return true;
01565 }
01566 return false;
01567 }
01568
01578 template <typename C, typename T>
01579 typename basic_pstreambuf<C,T>::int_type
01580 basic_pstreambuf<C,T>::overflow(int_type c)
01581 {
01582 if (!empty_buffer())
01583 return traits_type::eof();
01584 else if (!traits_type::eq_int_type(c, traits_type::eof()))
01585 return this->sputc(c);
01586 else
01587 return traits_type::not_eof(c);
01588 }
01589
01590
01591 template <typename C, typename T>
01592 int
01593 basic_pstreambuf<C,T>::sync()
01594 {
01595 return !exited() && empty_buffer() ? 0 : -1;
01596 }
01597
01603 template <typename C, typename T>
01604 std::streamsize
01605 basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
01606 {
01607 if (n < this->epptr() - this->pptr())
01608 {
01609 traits_type::copy(this->pptr(), s, n);
01610 this->pbump(n);
01611 return n;
01612 }
01613 else
01614 {
01615 for (std::streamsize i = 0; i < n; ++i)
01616 {
01617 if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof()))
01618 return i;
01619 }
01620 return n;
01621 }
01622 }
01623
01627 template <typename C, typename T>
01628 bool
01629 basic_pstreambuf<C,T>::empty_buffer()
01630 {
01631 const std::streamsize count = this->pptr() - this->pbase();
01632 if (count > 0)
01633 {
01634 const std::streamsize written = this->write(this->wbuffer_, count);
01635 if (written > 0)
01636 {
01637 if (const std::streamsize unwritten = count - written)
01638 traits_type::move(this->pbase(), this->pbase()+written, unwritten);
01639 this->pbump(-written);
01640 return true;
01641 }
01642 }
01643 return false;
01644 }
01645
01653 template <typename C, typename T>
01654 typename basic_pstreambuf<C,T>::int_type
01655 basic_pstreambuf<C,T>::underflow()
01656 {
01657 if (this->gptr() < this->egptr() || fill_buffer())
01658 return traits_type::to_int_type(*this->gptr());
01659 else
01660 return traits_type::eof();
01661 }
01662
01671 template <typename C, typename T>
01672 typename basic_pstreambuf<C,T>::int_type
01673 basic_pstreambuf<C,T>::pbackfail(int_type c)
01674 {
01675 if (this->gptr() != this->eback())
01676 {
01677 this->gbump(-1);
01678 if (!traits_type::eq_int_type(c, traits_type::eof()))
01679 *this->gptr() = traits_type::to_char_type(c);
01680 return traits_type::not_eof(c);
01681 }
01682 else
01683 return traits_type::eof();
01684 }
01685
01686 template <typename C, typename T>
01687 std::streamsize
01688 basic_pstreambuf<C,T>::showmanyc()
01689 {
01690 int avail = 0;
01691 if (sizeof(char_type) == 1)
01692 avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
01693 #ifdef FIONREAD
01694 else
01695 {
01696 if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
01697 avail = -1;
01698 else if (avail)
01699 avail /= sizeof(char_type);
01700 }
01701 #endif
01702 return std::streamsize(avail);
01703 }
01704
01708 template <typename C, typename T>
01709 bool
01710 basic_pstreambuf<C,T>::fill_buffer(bool non_blocking)
01711 {
01712 const std::streamsize pb1 = this->gptr() - this->eback();
01713 const std::streamsize pb2 = pbsz;
01714 const std::streamsize npb = std::min(pb1, pb2);
01715
01716 char_type* const rbuf = rbuffer();
01717
01718 traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
01719
01720 std::streamsize rc = -1;
01721
01722 if (non_blocking)
01723 {
01724 const int flags = ::fcntl(rpipe(), F_GETFL);
01725 if (flags != -1)
01726 {
01727 const bool blocking = !(flags & O_NONBLOCK);
01728 if (blocking)
01729 ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK);
01730
01731 error_ = 0;
01732 rc = read(rbuf + pbsz, bufsz - pbsz);
01733
01734 if (rc == -1 && error_ == EAGAIN)
01735 rc = 0;
01736 else if (rc == 0)
01737 rc = -1;
01738
01739 if (blocking)
01740 ::fcntl(rpipe(), F_SETFL, flags);
01741 }
01742 }
01743 else
01744 rc = read(rbuf + pbsz, bufsz - pbsz);
01745
01746 if (rc > 0 || (rc == 0 && non_blocking))
01747 {
01748 this->setg( rbuf + pbsz - npb,
01749 rbuf + pbsz,
01750 rbuf + pbsz + rc );
01751 return true;
01752 }
01753 else
01754 {
01755 this->setg(NULL, NULL, NULL);
01756 return false;
01757 }
01758 }
01759
01767 template <typename C, typename T>
01768 inline std::streamsize
01769 basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
01770 {
01771 std::streamsize nwritten = 0;
01772 if (wpipe() >= 0)
01773 {
01774 nwritten = ::write(wpipe(), s, n * sizeof(char_type));
01775 if (nwritten == -1)
01776 error_ = errno;
01777 else
01778 nwritten /= sizeof(char_type);
01779 }
01780 return nwritten;
01781 }
01782
01790 template <typename C, typename T>
01791 inline std::streamsize
01792 basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
01793 {
01794 std::streamsize nread = 0;
01795 if (rpipe() >= 0)
01796 {
01797 nread = ::read(rpipe(), s, n * sizeof(char_type));
01798 if (nread == -1)
01799 error_ = errno;
01800 else
01801 nread /= sizeof(char_type);
01802 }
01803 return nread;
01804 }
01805
01807 template <typename C, typename T>
01808 inline typename basic_pstreambuf<C,T>::fd_type&
01809 basic_pstreambuf<C,T>::wpipe()
01810 {
01811 return wpipe_;
01812 }
01813
01815 template <typename C, typename T>
01816 inline typename basic_pstreambuf<C,T>::fd_type&
01817 basic_pstreambuf<C,T>::rpipe()
01818 {
01819 return rpipe_[rsrc_];
01820 }
01821
01823 template <typename C, typename T>
01824 inline typename basic_pstreambuf<C,T>::fd_type&
01825 basic_pstreambuf<C,T>::rpipe(buf_read_src which)
01826 {
01827 return rpipe_[which];
01828 }
01829
01831 template <typename C, typename T>
01832 inline typename basic_pstreambuf<C,T>::char_type*
01833 basic_pstreambuf<C,T>::rbuffer()
01834 {
01835 return rbuffer_[rsrc_];
01836 }
01837
01838
01839
01840
01841
01842
01852 template <typename C, typename T>
01853 inline
01854 pstream_common<C,T>::pstream_common()
01855 : std::basic_ios<C,T>(NULL)
01856 , command_()
01857 , buf_()
01858 {
01859 this->init(&buf_);
01860 }
01861
01870 template <typename C, typename T>
01871 inline
01872 pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
01873 : std::basic_ios<C,T>(NULL)
01874 , command_(command)
01875 , buf_()
01876 {
01877 this->init(&buf_);
01878 do_open(command, mode);
01879 }
01880
01890 template <typename C, typename T>
01891 inline
01892 pstream_common<C,T>::pstream_common( const std::string& file,
01893 const argv_type& argv,
01894 pmode mode )
01895 : std::basic_ios<C,T>(NULL)
01896 , command_(file)
01897 , buf_()
01898 {
01899 this->init(&buf_);
01900 do_open(file, argv, mode);
01901 }
01902
01912 template <typename C, typename T>
01913 inline
01914 pstream_common<C,T>::~pstream_common()
01915 {
01916 }
01917
01926 template <typename C, typename T>
01927 inline void
01928 pstream_common<C,T>::do_open(const std::string& command, pmode mode)
01929 {
01930 if (!buf_.open((command_=command), mode))
01931 this->setstate(std::ios_base::failbit);
01932 }
01933
01943 template <typename C, typename T>
01944 inline void
01945 pstream_common<C,T>::do_open( const std::string& file,
01946 const argv_type& argv,
01947 pmode mode )
01948 {
01949 if (!buf_.open((command_=file), argv, mode))
01950 this->setstate(std::ios_base::failbit);
01951 }
01952
01954 template <typename C, typename T>
01955 inline void
01956 pstream_common<C,T>::close()
01957 {
01958 if (!buf_.close())
01959 this->setstate(std::ios_base::failbit);
01960 }
01961
01966 template <typename C, typename T>
01967 inline bool
01968 pstream_common<C,T>::is_open() const
01969 {
01970 return buf_.is_open();
01971 }
01972
01974 template <typename C, typename T>
01975 inline const std::string&
01976 pstream_common<C,T>::command() const
01977 {
01978 return command_;
01979 }
01980
01982
01983 template <typename C, typename T>
01984 inline typename pstream_common<C,T>::streambuf_type*
01985 pstream_common<C,T>::rdbuf() const
01986 {
01987 return const_cast<streambuf_type*>(&buf_);
01988 }
01989
01990
01991 #if REDI_EVISCERATE_PSTREAMS
01992
02024 template <typename C, typename T>
02025 std::size_t
02026 basic_pstreambuf<C,T>::fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err)
02027 {
02028 in = out = err = NULL;
02029 std::size_t open_files = 0;
02030 if (wpipe() > -1)
02031 {
02032 if ((in = ::fdopen(wpipe(), "w")))
02033 {
02034 open_files |= pstdin;
02035 }
02036 }
02037 if (rpipe(rsrc_out) > -1)
02038 {
02039 if ((out = ::fdopen(rpipe(rsrc_out), "r")))
02040 {
02041 open_files |= pstdout;
02042 }
02043 }
02044 if (rpipe(rsrc_err) > -1)
02045 {
02046 if ((err = ::fdopen(rpipe(rsrc_err), "r")))
02047 {
02048 open_files |= pstderr;
02049 }
02050 }
02051 return open_files;
02052 }
02053
02064 template <typename C, typename T>
02065 inline std::size_t
02066 pstream_common<C,T>::fopen(std::FILE*& fin, std::FILE*& fout, std::FILE*& ferr)
02067 {
02068 return buf_.fopen(fin, fout, ferr);
02069 }
02070
02071 #endif // REDI_EVISCERATE_PSTREAMS
02072
02073
02074 }
02075
02081 #endif // REDI_PSTREAM_H_SEEN
02082
02083
02084