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.84 2004/10/17 15:43:16 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 <unistd.h>     // for pipe() fork() exec() and filedes functions
00048 #include <signal.h>     // for kill()
00049 #if REDI_EVISCERATE_PSTREAMS
00050 #include <stdio.h>       // for FILE, fdopen()
00051 #endif
00052 
00053 
00055 #define PSTREAMS_VERSION 0x0050   // 0.5.0
00056 
00070 namespace redi
00071 {
00073   struct pstreams
00074   {
00076     typedef std::ios_base::openmode           pmode;
00077 
00079     typedef std::vector<std::string>          argv_type;
00080 
00081     static const pmode pstdin  = std::ios_base::out; 
00082     static const pmode pstdout = std::ios_base::in;  
00083     static const pmode pstderr = std::ios_base::app; 
00084 
00085   protected:
00086     enum { bufsz = 32 };  
00087     enum { pbsz  = 2 };   
00088   };
00089 
00091   template <typename CharT, typename Traits = std::char_traits<CharT> >
00092     class basic_pstreambuf
00093     : public std::basic_streambuf<CharT, Traits>
00094     , public pstreams
00095     {
00096     public:
00097       // Type definitions for dependent types
00098       typedef CharT                             char_type;
00099       typedef Traits                            traits_type;
00100       typedef typename traits_type::int_type    int_type;
00101       typedef typename traits_type::off_type    off_type;
00102       typedef typename traits_type::pos_type    pos_type;
00104       typedef int                               fd_type;
00106       typedef fd_type                           fd_t;
00107 
00109       basic_pstreambuf();
00110 
00112       basic_pstreambuf(const std::string& command, pmode mode);
00113 
00115       basic_pstreambuf( const std::string& file,
00116                         const argv_type& argv,
00117                         pmode mode );
00118 
00120       ~basic_pstreambuf();
00121 
00123       basic_pstreambuf*
00124       open(const std::string& command, pmode mode);
00125 
00127       basic_pstreambuf*
00128       open(const std::string& file, const argv_type& argv, pmode mode);
00129 
00131       basic_pstreambuf*
00132       close();
00133 
00135       basic_pstreambuf*
00136       kill(int signal = SIGTERM);
00137 
00139       void
00140       peof();
00141 
00143       bool
00144       read_err(bool readerr = true);
00145 
00147       bool
00148       is_open() const;
00149 
00151       bool
00152       exited();
00153 
00154 #if REDI_EVISCERATE_PSTREAMS
00155 
00156       std::size_t
00157       fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00158 #endif
00159 
00161       int
00162       status() const;
00163 
00165       int
00166       error() const;
00167 
00168     protected:
00170       int_type
00171       overflow(int_type c);
00172 
00174       int_type
00175       underflow();
00176 
00178       int_type
00179       pbackfail(int_type c = traits_type::eof());
00180 
00182       int
00183       sync();
00184 
00186       std::streamsize
00187       xsputn(const char_type* s, std::streamsize n);
00188 
00190       std::streamsize
00191       write(char_type* s, std::streamsize n);
00192 
00194       std::streamsize
00195       read(char_type* s, std::streamsize n);
00196 
00197     protected:
00199       enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
00200 
00202       pid_t
00203       fork(pmode mode);
00204 
00206       int
00207       wait(bool nohang = false);
00208 
00210       fd_type&
00211       wpipe();
00212 
00214       fd_type&
00215       rpipe();
00216 
00218       fd_type&
00219       rpipe(buf_read_src which);
00220 
00221       void
00222       create_buffers(pmode mode);
00223 
00224       void
00225       destroy_buffers(pmode mode);
00226 
00228       bool
00229       empty_buffer();
00230 
00231       bool
00232       fill_buffer();
00233 
00235       char_type*
00236       rbuffer();
00237 
00238       buf_read_src
00239       switch_read_buffer(buf_read_src);
00240 
00241     private:
00242       basic_pstreambuf(const basic_pstreambuf&);
00243       basic_pstreambuf& operator=(const basic_pstreambuf&);
00244 
00245       void
00246       init_rbuffers();
00247 
00248       pid_t         ppid_;        // pid of process
00249       fd_type       wpipe_;       // pipe used to write to process' stdin
00250       fd_type       rpipe_[2];    // two pipes to read from, stdout and stderr
00251       char_type*    wbuffer_;
00252       char_type*    rbuffer_[2];
00253       char_type*    rbufstate_[3];
00255       buf_read_src  rsrc_;
00256       int           status_;      // hold exit status of child process
00257       int           error_;       // hold errno if fork() or exec() fails
00258     };
00259 
00261   template <typename CharT, typename Traits = std::char_traits<CharT> >
00262     class pstream_common
00263     : virtual public std::basic_ios<CharT, Traits>
00264     , virtual public pstreams
00265     {
00266     protected:
00267       typedef basic_pstreambuf<CharT, Traits>       streambuf_type;
00268 
00270       pstream_common();
00271 
00273       pstream_common(const std::string& command, pmode mode);
00274 
00276       pstream_common( const std::string& file,
00277                       const argv_type& argv,
00278                       pmode mode );
00279 
00281       virtual
00282       ~pstream_common() = 0;
00283 
00285       void
00286       do_open(const std::string& command, pmode mode);
00287 
00289       void
00290       do_open(const std::string& file, const argv_type& argv, pmode mode);
00291 
00292     public:
00294       void
00295       close();
00296 
00298       bool
00299       is_open() const;
00300 
00302       const std::string&
00303       command() const;
00304 
00306       streambuf_type*
00307       rdbuf() const;
00308 
00309 #if REDI_EVISCERATE_PSTREAMS
00310 
00311       std::size_t
00312       fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err);
00313 #endif
00314 
00315     protected:
00316       std::string       command_; 
00317       streambuf_type    buf_;     
00318     };
00319 
00320 
00331   template <typename CharT, typename Traits = std::char_traits<CharT> >
00332     class basic_ipstream
00333     : public std::basic_istream<CharT, Traits>
00334     , public pstream_common<CharT, Traits>
00335     , virtual public pstreams
00336     {
00337       typedef std::basic_istream<CharT, Traits>     istream_type;
00338       typedef pstream_common<CharT, Traits>         pbase_type;
00339 
00340       using pbase_type::buf_;  // declare name in this scope
00341 
00342     public:
00344       typedef typename pbase_type::pmode            pmode;
00345 
00347       typedef typename pbase_type::argv_type        argv_type;
00348 
00350       basic_ipstream()
00351       : istream_type(NULL), pbase_type()
00352       { }
00353 
00364       basic_ipstream(const std::string& command, pmode mode = pstdout)
00365       : istream_type(NULL), pbase_type(command, mode|pstdout)
00366       { }
00367 
00379       basic_ipstream( const std::string& file,
00380                       const argv_type& argv,
00381                       pmode mode = pstdout )
00382       : istream_type(NULL), pbase_type(file, argv, mode|pstdout)
00383       { }
00384 
00390       ~basic_ipstream()
00391       { }
00392 
00402       void
00403       open(const std::string& command, pmode mode = pstdout)
00404       {
00405         this->do_open(command, mode|pstdout);
00406       }
00407 
00418       void
00419       open( const std::string& file,
00420             const argv_type& argv,
00421             pmode mode = pstdout )
00422       {
00423         this->do_open(file, argv, mode|pstdout);
00424       }
00425 
00430       basic_ipstream&
00431       out()
00432       {
00433         this->buf_.read_err(false);
00434         return *this;
00435       }
00436 
00441       basic_ipstream&
00442       err()
00443       {
00444         this->buf_.read_err(true);
00445         return *this;
00446       }
00447     };
00448 
00449 
00459   template <typename CharT, typename Traits = std::char_traits<CharT> >
00460     class basic_opstream
00461     : public std::basic_ostream<CharT, Traits>
00462     , public pstream_common<CharT, Traits>
00463     , virtual public pstreams
00464     {
00465       typedef std::basic_ostream<CharT, Traits>     ostream_type;
00466       typedef pstream_common<CharT, Traits>         pbase_type;
00467 
00468       using pbase_type::buf_;  // declare name in this scope
00469 
00470     public:
00472       typedef typename pbase_type::pmode            pmode;
00473 
00475       typedef typename pbase_type::argv_type        argv_type;
00476 
00478       basic_opstream()
00479       : ostream_type(NULL), pbase_type()
00480       { }
00481 
00492       basic_opstream(const std::string& command, pmode mode = pstdin)
00493       : ostream_type(NULL), pbase_type(command, mode|pstdin)
00494       { }
00495 
00507       basic_opstream( const std::string& file,
00508                       const argv_type& argv,
00509                       pmode mode = pstdin )
00510       : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
00511       { }
00512 
00518       ~basic_opstream() { }
00519 
00529       void
00530       open(const std::string& command, pmode mode = pstdin)
00531       {
00532         this->do_open(command, mode|pstdin);
00533       }
00534 
00545       void
00546       open( const std::string& file,
00547             const argv_type& argv,
00548             pmode mode = pstdin)
00549       {
00550         this->do_open(file, argv, mode|pstdin);
00551       }
00552     };
00553 
00554 
00568   template <typename CharT, typename Traits = std::char_traits<CharT> >
00569     class basic_pstream
00570     : public std::basic_iostream<CharT, Traits>
00571     , public pstream_common<CharT, Traits>
00572     , virtual public pstreams
00573     {
00574       typedef std::basic_iostream<CharT, Traits>    iostream_type;
00575       typedef pstream_common<CharT, Traits>         pbase_type;
00576 
00577       using pbase_type::buf_;  // declare name in this scope
00578 
00579     public:
00581       typedef typename pbase_type::pmode            pmode;
00582 
00584       typedef typename pbase_type::argv_type        argv_type;
00585 
00587       basic_pstream()
00588       : iostream_type(NULL), pbase_type()
00589       { }
00590 
00601       basic_pstream( const std::string& command,
00602                      pmode mode = pstdout|pstdin )
00603       : iostream_type(NULL), pbase_type(command, mode)
00604       { }
00605 
00617       basic_pstream( const std::string& file,
00618                      const argv_type& argv,
00619                      pmode mode = pstdout|pstdin )
00620       : iostream_type(NULL), pbase_type(file, argv, mode)
00621       { }
00622 
00628       ~basic_pstream() { }
00629 
00639       void
00640       open(const std::string& command, pmode mode = pstdout|pstdin)
00641       {
00642         this->do_open(command, mode);
00643       }
00644 
00655       void
00656       open( const std::string& file,
00657             const argv_type& argv,
00658             pmode mode = pstdout|pstdin )
00659       {
00660         this->do_open(file, argv, mode);
00661       }
00662 
00667       basic_pstream&
00668       out()
00669       {
00670         this->buf_.read_err(false);
00671         return *this;
00672       }
00673 
00678       basic_pstream&
00679       err()
00680       {
00681         this->buf_.read_err(true);
00682         return *this;
00683       }
00684     };
00685 
00686 
00708   template <typename CharT, typename Traits = std::char_traits<CharT> >
00709     class basic_rpstream
00710     : public std::basic_ostream<CharT, Traits>
00711     , private std::basic_istream<CharT, Traits>
00712     , private pstream_common<CharT, Traits>
00713     , virtual public pstreams
00714     {
00715       typedef std::basic_ostream<CharT, Traits>     ostream_type;
00716       typedef std::basic_istream<CharT, Traits>     istream_type;
00717       typedef pstream_common<CharT, Traits>         pbase_type;
00718 
00719       using pbase_type::buf_;  // declare name in this scope
00720 
00721     public:
00723       typedef typename pbase_type::pmode            pmode;
00724 
00726       typedef typename pbase_type::argv_type        argv_type;
00727 
00729       basic_rpstream()
00730       : ostream_type(NULL) , istream_type(NULL) , pbase_type()
00731       { }
00732 
00743       basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
00744       : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
00745       { }
00746 
00758       basic_rpstream( const std::string& file,
00759                       const argv_type& argv,
00760                       pmode mode = pstdout|pstdin )
00761       : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
00762       { }
00763 
00765       ~basic_rpstream() { }
00766 
00776       void
00777       open(const std::string& command, pmode mode = pstdout|pstdin)
00778       {
00779         this->do_open(command, mode);
00780       }
00781 
00792       void
00793       open( const std::string& file,
00794             const argv_type& argv,
00795             pmode mode = pstdout|pstdin )
00796       {
00797         this->do_open(file, argv, mode);
00798       }
00799 
00805       istream_type&
00806       out()
00807       {
00808         this->buf_.read_err(false);
00809         return *this;
00810       }
00811 
00817       istream_type&
00818       err()
00819       {
00820         this->buf_.read_err(true);
00821         return *this;
00822       }
00823     };
00824 
00825 
00827   typedef basic_pstreambuf<char> pstreambuf;
00829   typedef basic_ipstream<char> ipstream;
00831   typedef basic_opstream<char> opstream;
00833   typedef basic_pstream<char> pstream;
00835   typedef basic_rpstream<char> rpstream;
00836 
00837 
00850   template <typename C, typename T>
00851     inline std::basic_ostream<C,T>&
00852     peof(std::basic_ostream<C,T>& s)
00853     {
00854       typedef basic_pstreambuf<C,T> pstreambuf;
00855       if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
00856         p->peof();
00857       return s;
00858     }
00859 
00860 
00861   /*
00862    * member definitions for pstreambuf
00863    */
00864 
00865 
00872   template <typename C, typename T>
00873     inline
00874     basic_pstreambuf<C,T>::basic_pstreambuf()
00875     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
00876     , wpipe_(-1)
00877     , wbuffer_(NULL)
00878     , rsrc_(rsrc_out)
00879     , status_(-1)
00880     , error_(0)
00881     {
00882       init_rbuffers();
00883     }
00884 
00893   template <typename C, typename T>
00894     inline
00895     basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
00896     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
00897     , wpipe_(-1)
00898     , wbuffer_(NULL)
00899     , rsrc_(rsrc_out)
00900     , status_(-1)
00901     , error_(0)
00902     {
00903       init_rbuffers();
00904       open(command, mode);
00905     }
00906 
00916   template <typename C, typename T>
00917     inline
00918     basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
00919                                              const argv_type& argv,
00920                                              pmode mode )
00921     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
00922     , wpipe_(-1)
00923     , wbuffer_(NULL)
00924     , rsrc_(rsrc_out)
00925     , status_(-1)
00926     , error_(0)
00927     {
00928       init_rbuffers();
00929       open(file, argv, mode);
00930     }
00931 
00936   template <typename C, typename T>
00937     inline
00938     basic_pstreambuf<C,T>::~basic_pstreambuf()
00939     {
00940       close();
00941     }
00942 
00957   template <typename C, typename T>
00958     basic_pstreambuf<C,T>*
00959     basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
00960     {
00961       basic_pstreambuf<C,T>* ret = NULL;
00962 
00963       if (!is_open())
00964       {
00965         switch(fork(mode))
00966         {
00967           case 0 :
00968           {
00969             // this is the new process, exec command
00970             ::execlp("sh", "sh", "-c", command.c_str(), (void*)NULL);
00971 
00972             // can only reach this point if exec() failed
00973 
00974             // parent can get exit code from waitpid()
00975             ::_exit(errno);
00976             // using std::exit() would make static dtors run twice
00977           }
00978           case -1 :
00979           {
00980             // couldn't fork, error already handled in pstreambuf::fork()
00981             break;
00982           }
00983           default :
00984           {
00985             // this is the parent process
00986             // activate buffers
00987             create_buffers(mode);
00988             ret = this;
00989           }
00990         }
00991       }
00992       return ret;
00993     }
00994 
01011   template <typename C, typename T>
01012     basic_pstreambuf<C,T>*
01013     basic_pstreambuf<C,T>::open( const std::string& file,
01014                                  const argv_type& argv,
01015                                  pmode mode )
01016     {
01017       basic_pstreambuf<C,T>* ret = NULL;
01018 
01019       if (!is_open())
01020       {
01021         switch(fork(mode))
01022         {
01023           case 0 :
01024           {
01025             // this is the new process, exec command
01026 
01027             char** arg_v = new char*[argv.size()+1];
01028             for (std::size_t i = 0; i < argv.size(); ++i)
01029             {
01030               const std::string& src = argv[i];
01031               char*& dest = arg_v[i];
01032               dest = new char[src.size()+1];
01033               dest[ src.copy(dest, src.size()) ] = '\0';
01034             }
01035             arg_v[argv.size()] = NULL;
01036 
01037             ::execvp(file.c_str(), arg_v);
01038 
01039             // can only reach this point if exec() failed
01040 
01041             // parent can get exit code from waitpid()
01042             ::_exit(errno);
01043             // using std::exit() would make static dtors run twice
01044           }
01045           case -1 :
01046           {
01047             // couldn't fork, error already handled in pstreambuf::fork()
01048             break;
01049           }
01050           default :
01051           {
01052             // this is the parent process
01053             // activate buffers
01054             create_buffers(mode);
01055             ret = this;
01056           }
01057         }
01058       }
01059       return ret;
01060     }
01061 
01071   inline void
01072   close_fd_array(int* filedes, std::size_t count)
01073   {
01074     for (std::size_t i = 0; i < count; ++i)
01075       if (filedes[i] >= 0)
01076         if (::close(filedes[i]) == 0)
01077           filedes[i] = -1;
01078   }
01079 
01096   template <typename C, typename T>
01097     pid_t
01098     basic_pstreambuf<C,T>::fork(pmode mode)
01099     {
01100       pid_t pid = -1;
01101 
01102       // three pairs of file descriptors, for pipes connected to the
01103       // process' stdin, stdout and stderr
01104       // (stored in a single array so close_fd_array() can close all at once)
01105       fd_type fd[6] =  {-1, -1, -1, -1, -1, -1};
01106       fd_type* const pin = fd;
01107       fd_type* const pout = fd+2;
01108       fd_type* const perr = fd+4;
01109 
01110       // constants for read/write ends of pipe
01111       const int RD = 0;
01112       const int WR = 1;
01113 
01114       // N.B.
01115       // For the pstreambuf pin is an output stream and
01116       // pout and perr are input streams.
01117 
01118       if (!error_ && mode&pstdin && ::pipe(pin))
01119         error_ = errno;
01120 
01121       if (!error_ && mode&pstdout && ::pipe(pout))
01122         error_ = errno;
01123 
01124       if (!error_ && mode&pstderr && ::pipe(perr))
01125         error_ = errno;
01126 
01127       if (!error_)
01128       {
01129         pid = ::fork();
01130         switch (pid)
01131         {
01132           case 0 :
01133           {
01134             // this is the new process
01135 
01136             // for each open pipe close one end and redirect the
01137             // respective standard stream to the other end
01138 
01139             if (*pin >= 0)
01140             {
01141               ::close(pin[WR]);
01142               ::dup2(pin[RD], STDIN_FILENO);
01143               ::close(pin[RD]);
01144             }
01145             if (*pout >= 0)
01146             {
01147               ::close(pout[RD]);
01148               ::dup2(pout[WR], STDOUT_FILENO);
01149               ::close(pout[WR]);
01150             }
01151             if (*perr >= 0)
01152             {
01153               ::close(perr[RD]);
01154               ::dup2(perr[WR], STDERR_FILENO);
01155               ::close(perr[WR]);
01156             }
01157             break;
01158           }
01159           case -1 :
01160           {
01161             // couldn't fork for some reason
01162             error_ = errno;
01163             // close any open pipes
01164             close_fd_array(fd, 6);
01165             break;
01166           }
01167           default :
01168           {
01169             // this is the parent process, store process' pid
01170             ppid_ = pid;
01171 
01172             // store one end of open pipes and close other end
01173             if (*pin >= 0)
01174             {
01175               wpipe_ = pin[WR];
01176               ::close(pin[RD]);
01177             }
01178             if (*pout >= 0)
01179             {
01180               rpipe_[rsrc_out] = pout[RD];
01181               ::close(pout[WR]);
01182             }
01183             if (*perr >= 0)
01184             {
01185               rpipe_[rsrc_err] = perr[RD];
01186               ::close(perr[WR]);
01187             }
01188 
01189             if (rpipe_[rsrc_out] == -1 && rpipe_[rsrc_err] >= 0)
01190             {
01191               // reading stderr but not stdout, so use stderr for all reads
01192               read_err(true);
01193             }
01194           }
01195         }
01196       }
01197       else
01198       {
01199         // close any pipes we opened before failure
01200         close_fd_array(fd, 6);
01201       }
01202       return pid;
01203     }
01204 
01214   template <typename C, typename T>
01215     basic_pstreambuf<C,T>*
01216     basic_pstreambuf<C,T>::close()
01217     {
01218       basic_pstreambuf<C,T>* ret = NULL;
01219       if (is_open())
01220       {
01221         sync();
01222 
01223         destroy_buffers(pstdin|pstdout|pstderr);
01224 
01225         // close pipes before wait() so child gets EOF/SIGPIPE
01226         close_fd_array(&wpipe_, 1);
01227         close_fd_array(rpipe_, 2);
01228 
01229         if (wait() == 1)
01230         {
01231           ret = this;
01232         }
01233       }
01234       return ret;
01235     }
01236 
01240   template <typename C, typename T>
01241     inline void
01242     basic_pstreambuf<C,T>::init_rbuffers()
01243     {
01244       rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
01245       rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
01246       rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
01247     }
01248 
01249   template <typename C, typename T>
01250     void
01251     basic_pstreambuf<C,T>::create_buffers(pmode mode)
01252     {
01253       if (mode & pstdin)
01254       {
01255         delete[] wbuffer_;
01256         wbuffer_ = new char_type[bufsz];
01257         this->setp(wbuffer_, wbuffer_ + bufsz);
01258       }
01259       if (mode & pstdout)
01260       {
01261         delete[] rbuffer_[rsrc_out];
01262         rbuffer_[rsrc_out] = new char_type[bufsz];
01263         if (rsrc_ == rsrc_out)
01264           this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
01265               rbuffer_[rsrc_out] + pbsz);
01266       }
01267       if (mode & pstderr)
01268       {
01269         delete[] rbuffer_[rsrc_err];
01270         rbuffer_[rsrc_err] = new char_type[bufsz];
01271         if (rsrc_ == rsrc_err)
01272           this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
01273               rbuffer_[rsrc_err] + pbsz);
01274       }
01275     }
01276 
01277   template <typename C, typename T>
01278     void
01279     basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
01280     {
01281       if (mode & pstdin)
01282       {
01283         this->setp(NULL, NULL);
01284         delete[] wbuffer_;
01285         wbuffer_ = NULL;
01286       }
01287       if (mode & pstdout)
01288       {
01289         if (rsrc_ == rsrc_out)
01290           this->setg(NULL, NULL, NULL);
01291         delete[] rbuffer_[rsrc_out];
01292         rbuffer_[rsrc_out] = NULL;
01293       }
01294       if (mode & pstderr)
01295       {
01296         if (rsrc_ == rsrc_err)
01297           this->setg(NULL, NULL, NULL);
01298         delete[] rbuffer_[rsrc_err];
01299         rbuffer_[rsrc_err] = NULL;
01300       }
01301     }
01302 
01303   template <typename C, typename T>
01304     typename basic_pstreambuf<C,T>::buf_read_src
01305     basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
01306     {
01307       if (rsrc_ != src)
01308       {
01309         char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
01310         this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
01311         for (std::size_t i = 0; i < 3; ++i)
01312           rbufstate_[i] = tmpbufstate[i];
01313         rsrc_ = src;
01314       }
01315       return rsrc_;
01316     }
01317 
01330   template <typename C, typename T>
01331     int
01332     basic_pstreambuf<C,T>::wait(bool nohang)
01333     {
01334       int exited = -1;
01335       if (is_open())
01336       {
01337         int status;
01338         switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
01339         {
01340           case 0 :
01341             // nohang was true and process has not exited
01342             exited = 0;
01343             break;
01344           case -1 :
01345             error_ = errno;
01346             break;
01347           default :
01348             // process has exited
01349             ppid_ = 0;
01350             status_ = status;
01351             exited = 1;
01352             destroy_buffers(pstdin|pstdout|pstderr);
01353             close_fd_array(&wpipe_, 1);
01354             close_fd_array(rpipe_, 2);
01355             break;
01356         }
01357       }
01358       return exited;
01359     }
01360 
01371   template <typename C, typename T>
01372     inline basic_pstreambuf<C,T>*
01373     basic_pstreambuf<C,T>::kill(int signal)
01374     {
01375       basic_pstreambuf<C,T>* ret = NULL;
01376       if (is_open())
01377       {
01378         if (::kill(ppid_, signal))
01379           error_ = errno;
01380         else
01381         {
01382           // TODO call exited() to check for exit and clean up? leave to user?
01383           ret = this;
01384         }
01385       }
01386       return ret;
01387     }
01388 
01393   template <typename C, typename T>
01394     inline bool
01395     basic_pstreambuf<C,T>::exited()
01396     {
01397       return ppid_ == 0 || wait(true)==1;
01398     }
01399 
01400 
01406   template <typename C, typename T>
01407     inline int
01408     basic_pstreambuf<C,T>::status() const
01409     {
01410       return status_;
01411     }
01412 
01416   template <typename C, typename T>
01417     inline int
01418     basic_pstreambuf<C,T>::error() const
01419     {
01420       return error_;
01421     }
01422 
01427   template <typename C, typename T>
01428     inline void
01429     basic_pstreambuf<C,T>::peof()
01430     {
01431       sync();
01432       destroy_buffers(pstdin);
01433       close_fd_array(&wpipe_, 1);
01434     }
01435 
01446   template <typename C, typename T>
01447     inline bool
01448     basic_pstreambuf<C,T>::is_open() const
01449     {
01450       return ppid_ > 0;
01451     }
01452 
01461   template <typename C, typename T>
01462     inline bool
01463     basic_pstreambuf<C,T>::read_err(bool readerr)
01464     {
01465       buf_read_src src = readerr ? rsrc_err : rsrc_out;
01466       if (rpipe_[src]>=0)
01467       {
01468         switch_read_buffer(src);
01469         return true;
01470       }
01471       return false;
01472     }
01473 
01484   template <typename C, typename T>
01485     typename basic_pstreambuf<C,T>::int_type
01486     basic_pstreambuf<C,T>::overflow(int_type c)
01487     {
01488       if (!empty_buffer())
01489         return traits_type::eof();
01490       else if (!traits_type::eq_int_type(c, traits_type::eof()))
01491         return this->sputc(c);
01492       else
01493         return traits_type::not_eof(c);
01494     }
01495 
01496 
01497   template <typename C, typename T>
01498     int
01499     basic_pstreambuf<C,T>::sync()
01500     {
01501       return !exited() && empty_buffer() ? 0 : -1;
01502     }
01503 
01509   template <typename C, typename T>
01510     std::streamsize
01511     basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
01512     {
01513       if (n < this->epptr() - this->pptr())
01514       {
01515         std::memcpy(this->pptr(), s, n * sizeof(char_type));
01516         this->pbump(n);
01517         return n;
01518       }
01519       else
01520       {
01521         for (std::streamsize i = 0; i < n; ++i)
01522         {
01523           if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof()))
01524             return i;
01525         }
01526         return n;
01527       }
01528     }
01529 
01533   template <typename C, typename T>
01534     bool
01535     basic_pstreambuf<C,T>::empty_buffer()
01536     {
01537       const std::streamsize count = this->pptr() - this->pbase();
01538       const std::streamsize written = this->write(this->wbuffer_, count);
01539       if (count > 0 && written == count)
01540       {
01541         this->pbump(-written);
01542         return true;
01543       }
01544       return false;
01545     }
01546 
01555   template <typename C, typename T>
01556     typename basic_pstreambuf<C,T>::int_type
01557     basic_pstreambuf<C,T>::underflow()
01558     {
01559       if (this->gptr() < this->egptr() || fill_buffer())
01560         return traits_type::to_int_type(*this->gptr());
01561       else
01562         return traits_type::eof();
01563     }
01564 
01573   template <typename C, typename T>
01574     typename basic_pstreambuf<C,T>::int_type
01575     basic_pstreambuf<C,T>::pbackfail(int_type c)
01576     {
01577       if (this->gptr() != this->eback())
01578       {
01579         this->gbump(-1);
01580         if (!traits_type::eq_int_type(c, traits_type::eof()))
01581           *this->gptr() = traits_type::to_char_type(c);
01582         return traits_type::not_eof(c);
01583       }
01584       else
01585          return traits_type::eof();
01586     }
01587 
01591   template <typename C, typename T>
01592     bool
01593     basic_pstreambuf<C,T>::fill_buffer()
01594     {
01595       const std::streamsize pb1 = this->gptr() - this->eback();
01596       const std::streamsize pb2 = pbsz;
01597       const std::streamsize npb = std::min(pb1, pb2);
01598 
01599       std::memmove( rbuffer() + pbsz - npb,
01600                     this->gptr() - npb,
01601                     npb * sizeof(char_type) );
01602 
01603       const std::streamsize rc = read(rbuffer() + pbsz, bufsz - pbsz);
01604 
01605       if (rc > 0)
01606       {
01607         this->setg( rbuffer() + pbsz - npb,
01608                     rbuffer() + pbsz,
01609                     rbuffer() + pbsz + rc );
01610         return true;
01611       }
01612       else
01613       {
01614         this->setg(NULL, NULL, NULL);
01615         return false;
01616       }
01617     }
01618 
01628   template <typename C, typename T>
01629     inline std::streamsize
01630     basic_pstreambuf<C,T>::write(char_type* s, std::streamsize n)
01631     {
01632       return wpipe() >= 0 ? ::write(wpipe(), s, n * sizeof(char_type)) : 0;
01633     }
01634 
01644   template <typename C, typename T>
01645     inline std::streamsize
01646     basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
01647     {
01648       return rpipe() >= 0 ? ::read(rpipe(), s, n * sizeof(char_type)) : 0;
01649     }
01650 
01652   template <typename C, typename T>
01653     inline typename basic_pstreambuf<C,T>::fd_type&
01654     basic_pstreambuf<C,T>::wpipe()
01655     {
01656       return wpipe_;
01657     }
01658 
01660   template <typename C, typename T>
01661     inline typename basic_pstreambuf<C,T>::fd_type&
01662     basic_pstreambuf<C,T>::rpipe()
01663     {
01664       return rpipe_[rsrc_];
01665     }
01666 
01668   template <typename C, typename T>
01669     inline typename basic_pstreambuf<C,T>::fd_type&
01670     basic_pstreambuf<C,T>::rpipe(buf_read_src which)
01671     {
01672       return rpipe_[which];
01673     }
01674 
01676   template <typename C, typename T>
01677     inline typename basic_pstreambuf<C,T>::char_type*
01678     basic_pstreambuf<C,T>::rbuffer()
01679     {
01680       return rbuffer_[rsrc_];
01681     }
01682 
01683 
01684   /*
01685    * member definitions for pstream_common
01686    */
01687 
01697   template <typename C, typename T>
01698     inline
01699     pstream_common<C,T>::pstream_common()
01700     : std::basic_ios<C,T>(NULL)
01701     , command_()
01702     , buf_()
01703     {
01704       this->init(&buf_);
01705     }
01706 
01715   template <typename C, typename T>
01716     inline
01717     pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
01718     : std::basic_ios<C,T>(NULL)
01719     , command_(command)
01720     , buf_()
01721     {
01722       this->init(&buf_);
01723       do_open(command, mode);
01724     }
01725 
01735   template <typename C, typename T>
01736     inline
01737     pstream_common<C,T>::pstream_common( const std::string& file,
01738                                          const argv_type& argv,
01739                                          pmode mode )
01740     : std::basic_ios<C,T>(NULL)
01741     , command_(file)
01742     , buf_()
01743     {
01744       this->init(&buf_);
01745       do_open(file, argv, mode);
01746     }
01747 
01757   template <typename C, typename T>
01758     inline
01759     pstream_common<C,T>::~pstream_common()
01760     {
01761     }
01762 
01771   template <typename C, typename T>
01772     inline void
01773     pstream_common<C,T>::do_open(const std::string& command, pmode mode)
01774     {
01775       if (!buf_.open((command_=command), mode))
01776         this->setstate(std::ios_base::failbit);
01777     }
01778 
01788   template <typename C, typename T>
01789     inline void
01790     pstream_common<C,T>::do_open( const std::string& file,
01791                                   const argv_type& argv,
01792                                   pmode mode )
01793     {
01794       if (!buf_.open((command_=file), argv, mode))
01795         this->setstate(std::ios_base::failbit);
01796     }
01797 
01799   template <typename C, typename T>
01800     inline void
01801     pstream_common<C,T>::close()
01802     {
01803       if (!buf_.close())
01804         this->setstate(std::ios_base::failbit);
01805     }
01806 
01811   template <typename C, typename T>
01812     inline bool
01813     pstream_common<C,T>::is_open() const
01814     {
01815       return buf_.is_open();
01816     }
01817 
01819   template <typename C, typename T>
01820     inline const std::string&
01821     pstream_common<C,T>::command() const
01822     {
01823       return command_;
01824     }
01825 
01827   // TODO  document behaviour if buffer replaced.
01828   template <typename C, typename T>
01829     inline typename pstream_common<C,T>::streambuf_type*
01830     pstream_common<C,T>::rdbuf() const
01831     {
01832       return const_cast<streambuf_type*>(&buf_);
01833     }
01834 
01835 
01836 #if REDI_EVISCERATE_PSTREAMS
01837 
01866   template <typename C, typename T>
01867     std::size_t
01868     basic_pstreambuf<C,T>::fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err)
01869     {
01870       in = out = err = NULL;
01871       std::size_t open_files = 0;
01872       if (wpipe() > -1)
01873       {
01874         if ((in = ::fdopen(wpipe(), "w")))
01875         {
01876             open_files |= pstdin;
01877         }
01878       }
01879       if (rpipe(rsrc_out) > -1)
01880       {
01881         if ((out = ::fdopen(rpipe(rsrc_out), "r")))
01882         {
01883             open_files |= pstdout;
01884         }
01885       }
01886       if (rpipe(rsrc_err) > -1)
01887       {
01888         if ((err = ::fdopen(rpipe(rsrc_err), "r")))
01889         {
01890             open_files |= pstderr;
01891         }
01892       }
01893       return open_files;
01894     }
01895 
01906   template <typename C, typename T>
01907     inline std::size_t
01908     pstream_common<C,T>::fopen(std::FILE*& in, std::FILE*& out, std::FILE*& err)
01909     {
01910       return buf_.fopen(in, out, err);
01911     }
01912 
01913 #endif // REDI_EVISCERATE_PSTREAMS
01914 
01915 
01916 } // namespace redi
01917 
01923 #endif  // REDI_PSTREAM_H_SEEN
01924 
01925 // vim: ts=2 sw=2 expandtab
01926 

Generated on Fri Apr 15 09:04:59 2005 for PStreams by  doxygen 1.4.2