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
00032 #define REDI_PSTREAM_H
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 <sys/types.h>
00044 #include <sys/wait.h>
00045 #include <unistd.h>
00046 #include <signal.h>
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00063 #define PSTREAMS_VERSION 0x002a // 0.42
00064
00065
00079 namespace redi
00080 {
00082 struct pstreams
00083 {
00085 typedef std::ios_base::openmode pmode;
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 static const size_t bufsz = 32;
00093 static const size_t pbsz = 2;
00094 };
00095
00097 template <typename CharT, typename Traits>
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 int fd_t;
00111
00113 basic_pstreambuf();
00114
00116 basic_pstreambuf(const std::string& command, pmode mode);
00117
00119 basic_pstreambuf(const std::string& file, const std::vector<std::string>& argv, pmode mode);
00120
00122 ~basic_pstreambuf();
00123
00125 basic_pstreambuf*
00126 open(const std::string& command, pmode mode);
00127
00129 basic_pstreambuf*
00130 open(const std::string& file, const std::vector<std::string>& argv, pmode mode);
00131
00133 basic_pstreambuf*
00134 close();
00135
00137 basic_pstreambuf*
00138 kill(int signal = SIGTERM);
00139
00141 void
00142 peof();
00143
00145 bool
00146 read_err(bool readerr = true);
00147
00149 bool
00150 is_open() const;
00151
00153 bool
00154 exited();
00155
00156 #if REDI_EVISCERATE_PSTREAMS
00157
00158 size_t
00159 fopen(FILE*& in, FILE*& out, FILE*& err);
00160 #endif
00161
00163 int
00164 status() const;
00165
00167 int
00168 error() const;
00169
00170 protected:
00172 int_type
00173 overflow(int_type c);
00174
00176 int_type
00177 underflow();
00178
00180 int_type
00181 pbackfail(int_type c = traits_type::eof());
00182
00184 int
00185 sync();
00186
00187 std::streamsize
00188 xsputn(const char_type* s, std::streamsize n);
00189
00191 bool
00192 write(char_type c);
00193
00195 bool
00196 read(char_type& c);
00197
00199 std::streamsize
00200 write(char_type* s, std::streamsize n);
00201
00203 std::streamsize
00204 read(char_type* s, std::streamsize n);
00205
00206 protected:
00208 enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
00209
00211 pid_t
00212 fork(pmode mode);
00213
00215 int
00216 wait(bool nohang = false);
00217
00219 fd_t&
00220 wpipe();
00221
00223 fd_t&
00224 rpipe();
00225
00227 fd_t&
00228 rpipe(buf_read_src which);
00229
00230 void
00231 create_buffers(pmode mode);
00232
00233 void
00234 destroy_buffers(pmode mode);
00235
00237 bool
00238 empty_buffer();
00239
00240 bool
00241 fill_buffer();
00242
00244 char_type*
00245 rbuffer();
00246
00247 buf_read_src
00248 switch_read_buffer(buf_read_src);
00249
00250 private:
00251 basic_pstreambuf(const basic_pstreambuf&);
00252 basic_pstreambuf& operator=(const basic_pstreambuf&);
00253
00254 void
00255 init_rbuffers();
00256
00257 pid_t ppid_;
00258 fd_t wpipe_;
00259 fd_t rpipe_[2];
00260 char_type* wbuffer_;
00261 char_type* rbuffer_[2];
00262 char_type* rbufstate_[3];
00264 buf_read_src rsrc_;
00265 int status_;
00266 int error_;
00267 };
00268
00270 template <typename CharT, typename Traits = std::char_traits<CharT> >
00271 class pstream_common
00272 : virtual public std::basic_ios<CharT, Traits>
00273 , public pstreams
00274 {
00275 protected:
00276 typedef basic_pstreambuf<CharT, Traits> streambuf_type;
00277
00278 public:
00280 typedef typename streambuf_type::pmode pmode;
00281
00283 pstream_common();
00284
00286 pstream_common(const std::string& command, pmode mode);
00287
00289 pstream_common(const std::string& file, const std::vector<std::string>& argv, pmode mode);
00290
00292 virtual void
00293 open(const std::string& command, pmode mode);
00294
00296 virtual void
00297 open(const std::string& file, const std::vector<std::string>& argv, pmode mode);
00298
00300 void
00301 close();
00302
00304 bool
00305 is_open() const;
00306
00308 const std::string&
00309 command() const;
00310
00312 streambuf_type*
00313 rdbuf() const;
00314
00315 #if REDI_EVISCERATE_PSTREAMS
00316
00317 size_t
00318 fopen(FILE*& in, FILE*& out, FILE*& err);
00319 #endif
00320
00321 protected:
00323 virtual
00324 ~pstream_common() = 0;
00325
00326 std::string command_;
00327 streambuf_type buf_;
00328 };
00329
00330
00341 template <typename CharT, typename Traits = std::char_traits<CharT> >
00342 class basic_ipstream
00343 : public std::basic_istream<CharT, Traits>
00344 , public pstream_common<CharT, Traits>
00345 {
00346 typedef std::basic_istream<CharT, Traits> istream_type;
00347 typedef pstream_common<CharT, Traits> pbase_type;
00348 typedef typename pbase_type::streambuf_type streambuf_type;
00349
00350 public:
00352 typedef typename pbase_type::pmode pmode;
00353
00355 basic_ipstream()
00356 : istream_type(NULL), pbase_type()
00357 {}
00358
00369 basic_ipstream(const std::string& command, pmode mode = std::ios_base::in)
00370 : istream_type(NULL), pbase_type(command, mode)
00371 {}
00372
00384 basic_ipstream(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::in)
00385 : istream_type(NULL), pbase_type(file, argv, mode)
00386 {}
00387
00393 ~basic_ipstream()
00394 {}
00395
00406 void
00407 open(const std::string& command, pmode mode = std::ios_base::in)
00408 { pbase_type::open(command, mode); }
00409
00421 void
00422 open(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::in)
00423 { pbase_type::open(file, argv, mode); }
00424
00429 basic_ipstream&
00430 out()
00431 {
00432 buf_.read_err(false);
00433 return *this;
00434 }
00435
00440 basic_ipstream&
00441 err()
00442 {
00443 buf_.read_err(true);
00444 return *this;
00445 }
00446 };
00447
00448
00458 template <typename CharT, typename Traits = std::char_traits<CharT> >
00459 class basic_opstream
00460 : public std::basic_ostream<CharT, Traits>
00461 , public pstream_common<CharT, Traits>
00462 {
00463 typedef std::basic_ostream<CharT, Traits> ostream_type;
00464 typedef pstream_common<CharT, Traits> pbase_type;
00465 typedef typename pbase_type::streambuf_type streambuf_type;
00466
00467 public:
00469 typedef typename pbase_type::pmode pmode;
00470
00472 basic_opstream()
00473 : ostream_type(NULL), pbase_type()
00474 {}
00475
00486 basic_opstream(const std::string& command, pmode mode = std::ios_base::out)
00487 : ostream_type(NULL), pbase_type(command, mode)
00488 {}
00489
00501 basic_opstream(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::out)
00502 : ostream_type(NULL), pbase_type(file, argv, mode)
00503 {}
00504
00510 ~basic_opstream() { }
00511
00518 void
00519 open(const std::string& command, pmode mode = std::ios_base::out)
00520 { pbase_type::open(command, mode); }
00521
00529 void
00530 open(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::out)
00531 { pbase_type::open(file, argv, mode); }
00532 };
00533
00534
00548 template <typename CharT, typename Traits = std::char_traits<CharT> >
00549 class basic_pstream
00550 : public std::basic_iostream<CharT, Traits>
00551 , public pstream_common<CharT, Traits>
00552 {
00553 typedef std::basic_iostream<CharT, Traits> iostream_type;
00554 typedef pstream_common<CharT, Traits> pbase_type;
00555 typedef typename pbase_type::streambuf_type streambuf_type;
00556
00557 public:
00559 typedef typename pbase_type::pmode pmode;
00560
00562 basic_pstream()
00563 : iostream_type(NULL), pbase_type()
00564 {}
00565
00576 basic_pstream(const std::string& command, pmode mode = std::ios_base::in|std::ios_base::out)
00577 : iostream_type(NULL), pbase_type(command, mode)
00578 {}
00579
00591 basic_pstream(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::in|std::ios_base::out)
00592 : iostream_type(NULL), pbase_type(file, argv, mode)
00593 {}
00594
00600 ~basic_pstream() { }
00601
00608 void
00609 open(const std::string& command, pmode mode = std::ios_base::in|std::ios_base::out)
00610 { pbase_type::open(command, mode); }
00611
00619 void
00620 open(const std::string& file, const std::vector<std::string>& argv, pmode mode = std::ios_base::in|std::ios_base::out)
00621 { pbase_type::open(file, argv, mode); }
00622
00627 basic_pstream&
00628 out()
00629 {
00630 buf_.read_err(false);
00631 return *this;
00632 }
00633
00638 basic_pstream&
00639 err()
00640 {
00641 buf_.read_err(true);
00642 return *this;
00643 }
00644 };
00645
00646
00648 typedef basic_pstreambuf<char, std::char_traits<char> > pstreambuf;
00650 typedef basic_ipstream<char> ipstream;
00652 typedef basic_opstream<char> opstream;
00654 typedef basic_pstream<char> pstream;
00655
00656
00657 template <typename C, typename T>
00658 std::basic_ostream<C,T>&
00659 peof(std::basic_ostream<C,T>& s);
00660
00678 template <typename C, typename T>
00679 std::basic_ostream<C,T>&
00680 peof(std::basic_ostream<C,T>& s)
00681 {
00682 static_cast<basic_pstreambuf<C,T>*>(s.rdbuf())->peof();
00683
00684 return s;
00685 }
00686
00687
00688
00689
00690
00691
00692
00699 template <typename C, typename T>
00700 inline
00701 basic_pstreambuf<C,T>::basic_pstreambuf()
00702 : ppid_(0)
00703 , wpipe_(-1)
00704 , wbuffer_(0)
00705 , rsrc_(rsrc_out)
00706 , status_(-1)
00707 , error_(0)
00708 {
00709 init_rbuffers();
00710 }
00711
00712
00721 template <typename C, typename T>
00722 inline
00723 basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
00724 : ppid_(0)
00725 , wpipe_(-1)
00726 , wbuffer_(0)
00727 , rsrc_(rsrc_out)
00728 , status_(-1)
00729 , error_(0)
00730 {
00731 init_rbuffers();
00732 open(command, mode);
00733 }
00734
00744 template <typename C, typename T>
00745 inline
00746 basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& file, const std::vector<std::string>& argv, pmode mode)
00747 : ppid_(0)
00748 , wpipe_(-1)
00749 , wbuffer_(0)
00750 , rsrc_(rsrc_out)
00751 , status_(-1)
00752 , error_(0)
00753 {
00754 init_rbuffers();
00755 open(file, argv, mode);
00756 }
00757
00762 template <typename C, typename T>
00763 inline
00764 basic_pstreambuf<C,T>::~basic_pstreambuf()
00765 {
00766 close();
00767 }
00768
00781 template <typename C, typename T>
00782 inline basic_pstreambuf<C,T>*
00783 basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
00784 {
00785 basic_pstreambuf<C,T>* ret = NULL;
00786
00787 if (!is_open())
00788 {
00789 switch(fork(mode))
00790 {
00791 case 0 :
00792 {
00793
00794 ::execlp("sh", "sh", "-c", command.c_str(), 0);
00795
00796
00797
00798
00799 std::exit(errno);
00800 }
00801 case -1 :
00802 {
00803
00804 break;
00805 }
00806 default :
00807 {
00808
00809 #if 0
00810
00811
00812
00813 switch (wait(true))
00814 {
00815 case 0 :
00816
00817 create_buffers(mode);
00818 ret = this;
00819 break;
00820 case 1:
00821
00822 sync();
00823 close_fd_array(&wpipe_, 1);
00824 close_fd_array(rpipe_, 2);
00825 break;
00826 default :
00827 break;
00828 }
00829 #else
00830
00831 create_buffers(mode);
00832 ret = this;
00833 #endif
00834 }
00835 }
00836 }
00837 return ret;
00838 }
00839
00840
00856 template <typename C, typename T>
00857 inline basic_pstreambuf<C,T>*
00858 basic_pstreambuf<C,T>::open(const std::string& file, const std::vector<std::string>& argv, pmode mode)
00859 {
00860 basic_pstreambuf<C,T>* ret = NULL;
00861
00862 if (!is_open())
00863 {
00864 switch(fork(mode))
00865 {
00866 case 0 :
00867 {
00868
00869
00870 char** arg_v = new char*[argv.size()+1];
00871 for (size_t i = 0; i < argv.size(); ++i)
00872 {
00873 const std::string& src = argv[i];
00874 char*& dest = arg_v[i];
00875 dest = new char[src.size()+1];
00876 dest[ src.copy(dest, src.size()) ] = 0;
00877 }
00878 arg_v[argv.size()] = 0;
00879
00880 ::execvp(file.c_str(), arg_v);
00881
00882
00883
00884
00885 std::exit(errno);
00886 }
00887 case -1 :
00888 {
00889
00890 break;
00891 }
00892 default :
00893 {
00894
00895 #if 0
00896
00897
00898
00899 switch (wait(true))
00900 {
00901 case 0 :
00902
00903 create_buffers(mode);
00904 ret = this;
00905 break;
00906 case 1:
00907
00908 sync();
00909 close_fd_array(&wpipe_, 1);
00910 close_fd_array(rpipe_, 2);
00911 break;
00912 default :
00913 break;
00914 }
00915 #else
00916
00917 create_buffers(mode);
00918 ret = this;
00919 #endif
00920 }
00921 }
00922 }
00923 return ret;
00924 }
00925
00933 inline void
00934 close_fd_array(int* filedes, size_t count)
00935 {
00936 for (size_t i = 0; i < count; ++i)
00937 if (filedes[i] >= 0)
00938 if (::close(filedes[i]) == 0)
00939 filedes[i] = -1;
00940 }
00941
00958 template <typename C, typename T>
00959 pid_t
00960 basic_pstreambuf<C,T>::fork(pmode mode)
00961 {
00962 pid_t pid = -1;
00963
00964
00965
00966
00967 fd_t fd[6] = {-1, -1, -1, -1, -1, -1};
00968 fd_t* pin = fd;
00969 fd_t* pout = fd+2;
00970 fd_t* perr = fd+4;
00971
00972
00973 const int RD = 0;
00974 const int WR = 1;
00975
00976
00977
00978
00979
00980 if (!error_ && mode&pstdin && ::pipe(pin))
00981 error_ = errno;
00982
00983 if (!error_ && mode&pstdout && ::pipe(pout))
00984 error_ = errno;
00985
00986 if (!error_ && mode&pstderr && ::pipe(perr))
00987 error_ = errno;
00988
00989 if (!error_)
00990 {
00991 pid = ::fork();
00992 switch (pid)
00993 {
00994 case 0 :
00995 {
00996
00997
00998
00999
01000
01001 if (*pin >= 0)
01002 {
01003 ::close(pin[WR]);
01004 ::dup2(pin[RD], STDIN_FILENO);
01005 ::close(pin[RD]);
01006 }
01007 if (*pout >= 0)
01008 {
01009 ::close(pout[RD]);
01010 ::dup2(pout[WR], STDOUT_FILENO);
01011 ::close(pout[WR]);
01012 }
01013 if (*perr >= 0)
01014 {
01015 ::close(perr[RD]);
01016 ::dup2(perr[WR], STDERR_FILENO);
01017 ::close(perr[WR]);
01018 }
01019 break;
01020 }
01021 case -1 :
01022 {
01023
01024 error_ = errno;
01025
01026 close_fd_array(fd, 6);
01027 break;
01028 }
01029 default :
01030 {
01031
01032 ppid_ = pid;
01033
01034
01035 if (*pin >= 0)
01036 {
01037 wpipe_ = pin[WR];
01038 ::close(pin[RD]);
01039 }
01040 if (*pout >= 0)
01041 {
01042 rpipe_[rsrc_out] = pout[RD];
01043 ::close(pout[WR]);
01044 }
01045 if (*perr >= 0)
01046 {
01047 rpipe_[rsrc_err] = perr[RD];
01048 ::close(perr[WR]);
01049 }
01050
01051 if (rpipe_[rsrc_out] == -1 && rpipe_[rsrc_err] >= 0)
01052 {
01053
01054 read_err(true);
01055 }
01056 }
01057 }
01058 }
01059 else
01060 {
01061
01062 close_fd_array(fd, 6);
01063 }
01064 return pid;
01065 }
01066
01067
01076 template <typename C, typename T>
01077 inline basic_pstreambuf<C,T>*
01078 basic_pstreambuf<C,T>::close()
01079 {
01080 basic_pstreambuf<C,T>* ret = NULL;
01081 if (is_open())
01082 {
01083 sync();
01084 destroy_buffers(pstdin|pstdout|pstderr);
01085
01086 close_fd_array(&wpipe_, 1);
01087 close_fd_array(rpipe_, 2);
01088
01089 if (wait() == 1)
01090 {
01091 ret = this;
01092 }
01093 }
01094 return ret;
01095 }
01096
01097
01101 template <typename C, typename T>
01102 inline void
01103 basic_pstreambuf<C,T>::init_rbuffers()
01104 {
01105 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
01106 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = 0;
01107 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = 0;
01108 }
01109
01110
01111 template <typename C, typename T>
01112 void
01113 basic_pstreambuf<C,T>::create_buffers(pmode mode)
01114 {
01115 if (mode & pstdin)
01116 {
01117 delete[] wbuffer_;
01118 wbuffer_ = new char_type[bufsz];
01119 setp(wbuffer_, wbuffer_ + bufsz);
01120 }
01121 if (mode & pstdout)
01122 {
01123 delete[] rbuffer_[rsrc_out];
01124 rbuffer_[rsrc_out] = new char_type[bufsz];
01125 if (rsrc_ == rsrc_out)
01126 setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
01127 rbuffer_[rsrc_out] + pbsz);
01128 }
01129 if (mode & pstderr)
01130 {
01131 delete[] rbuffer_[rsrc_err];
01132 rbuffer_[rsrc_err] = new char_type[bufsz];
01133 if (rsrc_ == rsrc_err)
01134 setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
01135 rbuffer_[rsrc_err] + pbsz);
01136 }
01137 }
01138
01139
01140 template <typename C, typename T>
01141 void
01142 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
01143 {
01144 if (mode & pstdin)
01145 {
01146 setp(0, 0);
01147 delete[] wbuffer_;
01148 wbuffer_ = 0;
01149 }
01150 if (mode & pstdout)
01151 {
01152 if (rsrc_ == rsrc_out)
01153 setg(0, 0, 0);
01154 delete[] rbuffer_[rsrc_out];
01155 rbuffer_[rsrc_out] = 0;
01156 }
01157 if (mode & pstderr)
01158 {
01159 if (rsrc_ == rsrc_err)
01160 setg(0, 0, 0);
01161 delete[] rbuffer_[rsrc_err];
01162 rbuffer_[rsrc_err] = 0;
01163 }
01164 }
01165
01166 template <typename C, typename T>
01167 typename basic_pstreambuf<C,T>::buf_read_src
01168 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
01169 {
01170 if (rsrc_ != src)
01171 {
01172 char_type* tmpbufstate[3];
01173 tmpbufstate[0] = eback();
01174 tmpbufstate[1] = gptr();
01175 tmpbufstate[2] = egptr();
01176 setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
01177 for (size_t i = 0; i < 3; ++i)
01178 rbufstate_[i] = tmpbufstate[i];
01179 }
01180 return rsrc_;
01181 }
01182
01183
01195 template <typename C, typename T>
01196 inline int
01197 basic_pstreambuf<C,T>::wait(bool nohang)
01198 {
01199 int exited = -1;
01200 if (is_open())
01201 {
01202 int status;
01203 switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
01204 {
01205 case 0 :
01206
01207 exited = 0;
01208 break;
01209 case -1 :
01210 error_ = errno;
01211 break;
01212 default :
01213
01214 ppid_ = 0;
01215 status_ = status;
01216 exited = 1;
01217
01218 break;
01219 }
01220 }
01221 return exited;
01222 }
01223
01224
01235 template <typename C, typename T>
01236 inline basic_pstreambuf<C,T>*
01237 basic_pstreambuf<C,T>::kill(int signal)
01238 {
01239 basic_pstreambuf<C,T>* ret = NULL;
01240 if (is_open())
01241 {
01242 if (::kill(ppid_, signal))
01243 error_ = errno;
01244 else
01245 ret = this;
01246 }
01247 return ret;
01248 }
01249
01250
01255 template <typename C, typename T>
01256 inline bool
01257 basic_pstreambuf<C,T>::exited()
01258 {
01259
01260 return wait(true)==1;
01261 }
01262
01263
01269 template <typename C, typename T>
01270 inline int
01271 basic_pstreambuf<C,T>::status() const
01272 {
01273 return status_;
01274 }
01275
01279 template <typename C, typename T>
01280 inline int
01281 basic_pstreambuf<C,T>::error() const
01282 {
01283 return error_;
01284 }
01285
01292 template <typename C, typename T>
01293 inline void
01294 basic_pstreambuf<C,T>::peof()
01295 {
01296 sync();
01297 destroy_buffers(pstdin);
01298 close_fd_array(&wpipe_, 1);
01299 }
01300
01309 template <typename C, typename T>
01310 inline bool
01311 basic_pstreambuf<C,T>::is_open() const
01312 {
01313 return bool(ppid_>0);
01314 }
01315
01324 template <typename C, typename T>
01325 inline bool
01326 basic_pstreambuf<C,T>::read_err(bool readerr)
01327 {
01328 buf_read_src src = readerr ? rsrc_err : rsrc_out;
01329 if (rpipe_[src]>=0)
01330 {
01331 rsrc_ = src;
01332 return true;
01333 }
01334 return false;
01335 }
01336
01347 template <typename C, typename T>
01348 typename basic_pstreambuf<C,T>::int_type
01349 basic_pstreambuf<C,T>::overflow(int_type c)
01350 {
01351 if (!empty_buffer())
01352 return traits_type::eof();
01353 else if (!traits_type::eq_int_type(c, traits_type::eof()))
01354 return sputc(c);
01355 else
01356 return traits_type::not_eof(c);
01357 }
01358
01359
01360 template <typename C, typename T>
01361 int
01362 basic_pstreambuf<C,T>::sync()
01363 {
01364 return (empty_buffer() ? 0 : -1);
01365 }
01366
01367
01368 template <typename C, typename T>
01369 std::streamsize
01370 basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
01371 {
01372 if (n < epptr() - pptr())
01373 {
01374 memcpy(pptr(), s, n * sizeof(char_type));
01375 pbump(n);
01376 return n;
01377 }
01378 else
01379 {
01380 for (std::streamsize i = 0; i < n; ++i)
01381 {
01382 if (traits_type::eq_int_type(sputc(s[i]), traits_type::eof()))
01383 return i;
01384 }
01385 return n;
01386 }
01387 }
01388
01389
01393 template <typename C, typename T>
01394 bool
01395 basic_pstreambuf<C,T>::empty_buffer()
01396 {
01397 int count = pptr() - pbase();
01398 std::streamsize written = write(wbuffer_, count);
01399 if (count > 0 && written == count)
01400 {
01401 pbump(-written);
01402 return true;
01403 }
01404 return false;
01405 }
01406
01407
01416 template <typename C, typename T>
01417 typename basic_pstreambuf<C,T>::int_type
01418 basic_pstreambuf<C,T>::underflow()
01419 {
01420 if (gptr() < egptr() || fill_buffer())
01421 return traits_type::to_int_type(*gptr());
01422 else
01423 return traits_type::eof();
01424 }
01425
01426
01435 template <typename C, typename T>
01436 typename basic_pstreambuf<C,T>::int_type
01437 basic_pstreambuf<C,T>::pbackfail(int_type c)
01438 {
01439 if (gptr() != eback())
01440 {
01441 gbump(-1);
01442 if (!traits_type::eq_int_type(c, traits_type::eof()))
01443 *gptr() = traits_type::to_char_type(c);
01444 return traits_type::not_eof(c);
01445 }
01446 else
01447 return traits_type::eof();
01448 }
01449
01453 template <typename C, typename T>
01454 bool
01455 basic_pstreambuf<C,T>::fill_buffer()
01456 {
01457 int npb = std::min(gptr()-eback(), static_cast<int>(pbsz));
01458
01459 std::memmove(rbuffer()+pbsz-npb, gptr()-npb, npb*sizeof(char_type));
01460
01461 std::streamsize rc = read(rbuffer() + pbsz, bufsz - pbsz);
01462
01463 if (rc > 0)
01464 {
01465 setg(rbuffer()+pbsz-npb, rbuffer()+pbsz, rbuffer()+pbsz+rc);
01466 return true;
01467 }
01468 else
01469 {
01470 setg(0, 0, 0);
01471 return false;
01472 }
01473 }
01474
01475
01483 template <typename C, typename T>
01484 inline bool
01485 basic_pstreambuf<C,T>::write(char_type c)
01486 {
01487 return (write(&c, 1) == 1);
01488 }
01489
01498 template <typename C, typename T>
01499 inline bool
01500 basic_pstreambuf<C,T>::read(char_type& c)
01501 {
01502 return (read(&c, 1) == 1);
01503 }
01504
01514 template <typename C, typename T>
01515 inline std::streamsize
01516 basic_pstreambuf<C,T>::write(char_type* s, std::streamsize n)
01517 {
01518 return (wpipe() >= 0 ? ::write(wpipe(), s, n * sizeof(char_type)) : 0);
01519 }
01520
01530 template <typename C, typename T>
01531 inline std::streamsize
01532 basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
01533 {
01534 return (rpipe() >= 0 ? ::read(rpipe(), s, n * sizeof(char_type)) : 0);
01535 }
01536
01537
01539 template <typename C, typename T>
01540 inline typename basic_pstreambuf<C,T>::fd_t&
01541 basic_pstreambuf<C,T>::wpipe()
01542 {
01543 return wpipe_;
01544 }
01545
01547 template <typename C, typename T>
01548 inline typename basic_pstreambuf<C,T>::fd_t&
01549 basic_pstreambuf<C,T>::rpipe()
01550 {
01551 return rpipe_[rsrc_];
01552 }
01553
01555 template <typename C, typename T>
01556 inline typename basic_pstreambuf<C,T>::fd_t&
01557 basic_pstreambuf<C,T>::rpipe(buf_read_src which)
01558 {
01559 return rpipe_[which];
01560 }
01561
01563 template <typename C, typename T>
01564 inline typename basic_pstreambuf<C,T>::char_type*
01565 basic_pstreambuf<C,T>::rbuffer()
01566 {
01567 return rbuffer_[rsrc_];
01568 }
01569
01570
01571
01572
01573
01574
01584 template <typename C, typename T>
01585 inline
01586 pstream_common<C,T>::pstream_common()
01587 : std::basic_ios<C,T>(NULL)
01588 , command_()
01589 , buf_()
01590 {
01591 init(&buf_);
01592 }
01593
01602 template <typename C, typename T>
01603 inline
01604 pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
01605 : std::basic_ios<C,T>(NULL)
01606 , command_(command)
01607 , buf_()
01608 {
01609 init(&buf_);
01610 open(command, mode);
01611 }
01612
01622 template <typename C, typename T>
01623 inline
01624 pstream_common<C,T>::pstream_common(const std::string& file, const std::vector<std::string>& argv, pmode mode)
01625 : std::basic_ios<C,T>(NULL)
01626 , command_(file)
01627 , buf_()
01628 {
01629 init(&buf_);
01630 open(file, argv, mode);
01631 }
01632
01642 template <typename C, typename T>
01643 inline
01644 pstream_common<C,T>::~pstream_common()
01645 {
01646 }
01647
01656 template <typename C, typename T>
01657 inline void
01658 pstream_common<C,T>::open(const std::string& command, pmode mode)
01659 {
01660 if (!buf_.open((command_=command), mode))
01661 setstate(std::ios_base::failbit);
01662 }
01663
01673 template <typename C, typename T>
01674 inline void
01675 pstream_common<C,T>::open(const std::string& file, const std::vector<std::string>& argv, pmode mode)
01676 {
01677 if (!buf_.open((command_=file), argv, mode))
01678 setstate(std::ios_base::failbit);
01679 }
01680
01682 template <typename C, typename T>
01683 inline void
01684 pstream_common<C,T>::close()
01685 {
01686 if (!buf_.close())
01687 setstate(std::ios_base::failbit);
01688 }
01689
01694 template <typename C, typename T>
01695 inline bool
01696 pstream_common<C,T>::is_open() const
01697 {
01698 return buf_.is_open();
01699 }
01700
01702 template <typename C, typename T>
01703 inline const std::string&
01704 pstream_common<C,T>::command() const
01705 {
01706 return command_;
01707 }
01708
01710
01711 template <typename C, typename T>
01712 inline typename pstream_common<C,T>::streambuf_type*
01713 pstream_common<C,T>::rdbuf() const
01714 {
01715 return const_cast<streambuf_type*>(&buf_);
01716 }
01717
01718 #if REDI_EVISCERATE_PSTREAMS
01719
01748 template <typename C, typename T>
01749 inline size_t
01750 basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
01751 {
01752 in = out = err = NULL;
01753 size_t open_files = 0;
01754 if (wpipe() > -1)
01755 {
01756 if (in = ::fdopen(wpipe(), "w"))
01757 {
01758 open_files |= pstdin;
01759 }
01760 }
01761 if (rpipe(rsrc_out) > -1)
01762 {
01763 if (out = ::fdopen(rpipe(rsrc_out), "r"))
01764 {
01765 open_files |= pstdout;
01766 }
01767 }
01768 if (rpipe(rsrc_err) > -1)
01769 {
01770 if (err = ::fdopen(rpipe(rsrc_err), "r"))
01771 {
01772 open_files |= pstderr;
01773 }
01774 }
01775 return open_files;
01776 }
01777
01788 template <typename C, typename T>
01789 inline size_t
01790 pstream_common<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
01791 {
01792 return buf_.fopen(in, out, err);
01793 }
01794
01795 #endif // REDI_EVISCERATE_PSTREAMS
01796
01797
01798 }
01799
01805 #endif // REDI_PSTREAM_H
01806
01807