Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

pstream.h

Go to the documentation of this file.
00001 /* $Id: pstream.h,v 1.90 2005/06/11 09:25:06 redi Exp $
00002 PStreams - POSIX Process I/O for C++
00003 Copyright (C) 2001,2002,2003,2004 Jonathan Wakely
00004 
00005 This file is part of PStreams.
00006 
00007 PStreams is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU Lesser General Public License as
00009 published by the Free Software Foundation; either version 2.1 of
00010 the License, or (at your option) any later version.
00011 
00012 PStreams is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU Lesser General Public License for more details.
00016 
00017 You should have received a copy of the GNU Lesser General Public License
00018 along with PStreams; if not, write to the Free Software Foundation, Inc.,
00019 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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>    // for min()
00041 #include <cstring>      // for memcpy(), memmove() etc.
00042 #include <cerrno>       // for errno
00043 #include <cstddef>      // for size_t
00044 #include <cstdlib>      // for exit()
00045 #include <sys/types.h>  // for pid_t
00046 #include <sys/wait.h>   // for waitpid()
00047 #include <sys/ioctl.h>  // for ioctl() and FIONREAD
00048 #if defined(__sun)
00049 # include <sys/filio.h> // for FIONREAD on Solaris 2.5
00050 #endif
00051 #include <unistd.h>     // for pipe() fork() exec() and filedes functions
00052 #include <signal.h>     // for kill()
00053 #include <fcntl.h>      // for fcntl()
00054 #if REDI_EVISCERATE_PSTREAMS
00055 # include <stdio.h>     // for FILE, fdopen()
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       // Type definitions for dependent types
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_;        // pid of process
00259       fd_type       wpipe_;       // pipe used to write to process' stdin
00260       fd_type       rpipe_[2];    // two pipes to read from, stdout and stderr
00261       char_type*    wbuffer_;
00262       char_type*    rbuffer_[2];
00263       char_type*    rbufstate_[3];
00265       buf_read_src  rsrc_;
00266       int           status_;      // hold exit status of child process
00267       int           error_;       // hold errno if fork() or exec() fails
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_;  // declare name in this scope
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_;  // declare name in this scope
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_;  // declare name in this scope
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_;  // declare name in this scope
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    * member definitions for pstreambuf
00870    */
00871 
00872 
00879   template <typename C, typename T>
00880     inline
00881     basic_pstreambuf<C,T>::basic_pstreambuf()
00882     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
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)   // initialise to -1 to indicate no process run yet.
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)   // initialise to -1 to indicate no process run yet.
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           // this is the new process, exec command
00986           ::execlp("sh", "sh", "-c", command.c_str(), (void*)NULL);
00987 
00988           // can only reach this point if exec() failed
00989 
00990           // parent can get exit code from waitpid()
00991           ::_exit(errno);
00992           // using std::exit() would make static dtors run twice
00993 
00994         case -1 :
00995           // couldn't fork, error already handled in pstreambuf::fork()
00996           break;
00997 
00998         default :
00999           // this is the parent process
01000           // activate buffers
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         // constants for read/write ends of pipe
01074         enum { RD, WR };
01075 
01076         // open another pipe and set close-on-exec
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             // this is the new process, exec command
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               // can only reach this point if exec() failed
01105 
01106               // parent can get error code from ck_exec pipe
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               // using std::exit() would make static dtors run twice
01115             }
01116 
01117           case -1 :
01118             // couldn't fork, error already handled in pstreambuf::fork()
01119             close_fd_array(ck_exec);
01120             break;
01121 
01122           default :
01123             // this is the parent process
01124 
01125             // check child called exec() successfully
01126             ::close(ck_exec[WR]);
01127             switch (::read(ck_exec[RD], &error_, sizeof(error_)))
01128             {
01129             case 0:
01130               // activate buffers
01131               create_buffers(mode);
01132               ret = this;
01133               break;
01134             case -1:
01135               error_ = errno;
01136               break;
01137             default:
01138               // error_ contains error code from child
01139               // call wait() to clean up and set ppid_ to 0
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       // Three pairs of file descriptors, for pipes connected to the
01173       // process' stdin, stdout and stderr
01174       // (stored in a single array so close_fd_array() can close all at once)
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       // constants for read/write ends of pipe
01181       enum { RD, WR };
01182 
01183       // N.B.
01184       // For the pstreambuf pin is an output stream and
01185       // pout and perr are input streams.
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             // this is the new process
01204 
01205             // for each open pipe close one end and redirect the
01206             // respective standard stream to the other end
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             // couldn't fork for some reason
01231             error_ = errno;
01232             // close any open pipes
01233             close_fd_array(fd);
01234             break;
01235           }
01236           default :
01237           {
01238             // this is the parent process, store process' pid
01239             ppid_ = pid;
01240 
01241             // store one end of open pipes and close other end
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               // reading stderr but not stdout, so use stderr for all reads
01261               read_err(true);
01262             }
01263           }
01264         }
01265       }
01266       else
01267       {
01268         // close any pipes we opened before failure
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         // close pipes before wait() so child gets EOF/SIGPIPE
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             // nohang was true and process has not exited
01411             exited = 0;
01412             break;
01413           case -1 :
01414             error_ = errno;
01415             break;
01416           default :
01417             // process has exited
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           // TODO call exited() to check for exit and clean up? leave to user?
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    * member definitions for pstream_common
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   // TODO  document behaviour if buffer replaced.
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
01919 
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 } // namespace redi
02002 
02008 #endif  // REDI_PSTREAM_H_SEEN
02009 
02010 // vim: ts=2 sw=2 expandtab
02011 

Generated on Tue Jul 26 22:29:46 2005 for PStreams by  doxygen 1.4.3-20050530