Main Page | Namespace List | Class Hierarchy | Compound List | File List | Namespace Members | Compound Members | File Members

pstream.h

Go to the documentation of this file.
00001 /* $Id: pstream.h,v 1.52 2002/11/08 02:51:51 redi Exp $
00002 PStreams - POSIX Process I/O for C++
00003 Copyright (C) 2001,2002 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
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>  // for pid_t
00044 #include <sys/wait.h>   // for waitpid()
00045 #include <unistd.h>     // for pipe() fork() exec() and filedes functions
00046 #include <signal.h>     // for kill()
00047 
00048 
00049 // TODO   add input buffering to pstreambuf
00050 
00051 // TODO   abstract process creation and control to a process class.
00052 
00053 // TODO   capitalise class names ?
00054 // basic_pstreambuf -> BasicPStreamBuf
00055 // basic_opstream   -> BasicOPStream
00056 // basic_ipstream   -> BasicIPStream
00057 // basic_pstream    -> BasicPStream
00058 // basic_rpstream   -> BasicRPStream
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       // Type definitions for dependent types
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_;        // pid of process
00258       fd_t          wpipe_;       // pipe used to write to process' stdin
00259       fd_t          rpipe_[2];    // two pipes to read from, stdout and stderr
00260       char_type*                wbuffer_;
00261       char_type*                rbuffer_[2];
00262       char_type*                rbufstate_[3];
00264       buf_read_src  rsrc_;
00265       int           status_;      // hold exit status of child process
00266       int           error_;       // hold errno if fork() or exec() fails
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       //dynamic_cast<basic_pstreambuf<C,T>*>(s.rdbuf())->peof();
00684       return s;
00685     }
00686 
00687 
00688   /*
00689    * member definitions for pstreambuf
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             // this is the new process, exec command
00794             ::execlp("sh", "sh", "-c", command.c_str(), 0);
00795 
00796             // can only reach this point if exec() failed
00797 
00798             // parent can get exit code from waitpid()
00799             std::exit(errno);
00800           }
00801           case -1 :
00802           {
00803             // couldn't fork, error already handled in pstreambuf::fork()
00804             break;
00805           }
00806           default :
00807           {
00808             // this is the parent process
00809 #if 0
00810             // check process not exited already
00811             // very unlikely, since not enough time for shell to parse cmd!
00812 
00813             switch (wait(true))
00814             {
00815               case 0 :
00816                 // activate buffers
00817                 create_buffers(mode);
00818                 ret = this;
00819                 break;
00820               case 1:
00821                 // child exited already
00822                 sync();
00823                 close_fd_array(&wpipe_, 1);
00824                 close_fd_array(rpipe_, 2);
00825                 break;
00826               default :
00827                 break;
00828             }
00829 #else
00830             // activate buffers
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             // this is the new process, exec command
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             // can only reach this point if exec() failed
00883 
00884             // parent can get exit code from waitpid()
00885             std::exit(errno);
00886           }
00887           case -1 :
00888           {
00889             // couldn't fork, error already handled in pstreambuf::fork()
00890             break;
00891           }
00892           default :
00893           {
00894             // this is the parent process
00895 #if 0
00896             // check process not exited already
00897             // very unlikely, since not enough time for shell to parse cmd!
00898 
00899             switch (wait(true))
00900             {
00901               case 0 :
00902                 // activate buffers
00903                 create_buffers(mode);
00904                 ret = this;
00905                 break;
00906               case 1:
00907                 // child exited already
00908                 sync();
00909                 close_fd_array(&wpipe_, 1);
00910                 close_fd_array(rpipe_, 2);
00911                 break;
00912               default :
00913                 break;
00914             }
00915 #else
00916             // activate buffers
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       // three pairs of file descriptors, for pipes connected to the
00965       // process' stdin, stdout and stderr
00966       // (stored in a single array so close_fd_array() can close all at once)
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       // constants for read/write ends of pipe
00973       const int RD = 0;
00974       const int WR = 1;
00975 
00976       // N.B.
00977       // For the pstreambuf pin is an output stream and
00978       // pout and perr are input streams.
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             // this is the new process
00997 
00998             // for each open pipe close one end and redirect the
00999             // respective standard stream to the other end
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             // couldn't fork for some reason
01024             error_ = errno;
01025             // close any open pipes
01026             close_fd_array(fd, 6);
01027             break;
01028           }
01029           default :
01030           {
01031             // this is the parent process, store process' pid
01032             ppid_ = pid;
01033 
01034             // store one end of open pipes and close other end
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               // reading stderr but not stdout, so use stderr for all reads
01054               read_err(true);
01055             }
01056           }
01057         }
01058       }
01059       else
01060       {
01061         // close any pipes we opened before failure
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             // nohang was true and process has not exited
01207             exited = 0;
01208             break;
01209           case -1 :
01210             error_ = errno;
01211             break;
01212           default :
01213             // process has exited
01214             ppid_ = 0;
01215             status_ = status;
01216             exited = 1;
01217             // TODO  close pipes with close_fd_array() ?
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       // TODO  should close() if is_open() and has exited
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    * member definitions for pstream_common
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   // TODO  document behaviour if buffer replaced.
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 } // namespace redi
01799 
01805 #endif  // REDI_PSTREAM_H
01806 
01807 // vim: ts=2 sw=2 expandtab

Generated on Mon Jul 5 10:39:09 2004 for PStreams by doxygen 1.3.2