Advertisement
vaclavz

PStream.hpp

Mar 25th, 2019
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 71.04 KB | None | 0 0
  1. /*
  2. PStreams - POSIX Process I/O for C++
  3. Copyright (C) 2001-2016 Jonathan Wakely
  4.  
  5. This file is part of PStreams.
  6.  
  7. PStreams is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU Lesser General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or
  10. (at your option) any later version.
  11.  
  12. PStreams is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU Lesser General Public License for more details.
  16.  
  17. You should have received a copy of the GNU Lesser General Public License
  18. along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19. */
  20.  
  21. /**
  22.  * @file PStream.hpp
  23.  * @brief Declares all PStreams classes.
  24.  * @author Jonathan Wakely
  25.  *
  26.  * Defines classes redi::ipstream, redi::opstream, redi::pstream
  27.  * and redi::rpstream.
  28.  */
  29.  
  30. #ifndef REDI_PSTREAM_H_SEEN
  31. #define REDI_PSTREAM_H_SEEN
  32.  
  33. #include <ios>
  34. #include <streambuf>
  35. #include <istream>
  36. #include <ostream>
  37. #include <string>
  38. #include <vector>
  39. #include <algorithm>    // for min()
  40. #include <cerrno>       // for errno
  41. #include <cstddef>      // for size_t, NULL
  42. #include <cstdlib>      // for exit()
  43. #include <sys/types.h>  // for pid_t
  44. #include <sys/wait.h>   // for waitpid()
  45. #include <sys/ioctl.h>  // for ioctl() and FIONREAD
  46. #if defined(__sun)
  47. # include <sys/filio.h> // for FIONREAD on Solaris 2.5
  48. #endif
  49. #include <unistd.h>     // for pipe() fork() exec() and filedes functions
  50. #include <signal.h>     // for kill()
  51. #include <fcntl.h>      // for fcntl()
  52. #if REDI_EVISCERATE_PSTREAMS
  53. # include <stdio.h>     // for FILE, fdopen()
  54. #endif
  55.  
  56.  
  57. /// The library version.
  58. #define PSTREAMS_VERSION 0x0100   // 1.0.0
  59.  
  60. /**
  61.  *  @namespace redi
  62.  *  @brief  All PStreams classes are declared in namespace redi.
  63.  *
  64.  *  Like the standard iostreams, PStreams is a set of class templates,
  65.  *  taking a character type and traits type. As with the standard streams
  66.  *  they are most likely to be used with @c char and the default
  67.  *  traits type, so typedefs for this most common case are provided.
  68.  *
  69.  *  The @c pstream_common class template is not intended to be used directly,
  70.  *  it is used internally to provide the common functionality for the
  71.  *  other stream classes.
  72.  */
  73. namespace redi
  74. {
  75.   /// Common base class providing constants and typenames.
  76.   struct pstreams
  77.   {
  78.     /// Type used to specify how to connect to the process.
  79.     typedef std::ios_base::openmode           pmode;
  80.  
  81.     /// Type used to hold the arguments for a command.
  82.     typedef std::vector<std::string>          argv_type;
  83.  
  84.     /// Type used for file descriptors.
  85.     typedef int                               fd_type;
  86.  
  87.     static const pmode pstdin  = std::ios_base::out; ///< Write to stdin
  88.     static const pmode pstdout = std::ios_base::in;  ///< Read from stdout
  89.     static const pmode pstderr = std::ios_base::app; ///< Read from stderr
  90.  
  91.     /// Create a new process group for the child process.
  92.     static const pmode newpg   = std::ios_base::trunc;
  93.  
  94.   protected:
  95.     enum { bufsz = 32 };  ///< Size of pstreambuf buffers.
  96.     enum { pbsz  = 2 };   ///< Number of putback characters kept.
  97.   };
  98.  
  99.   /// Class template for stream buffer.
  100.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  101.     class basic_pstreambuf
  102.     : public std::basic_streambuf<CharT, Traits>
  103.     , public pstreams
  104.     {
  105.     public:
  106.       // Type definitions for dependent types
  107.       typedef CharT                             char_type;
  108.       typedef Traits                            traits_type;
  109.       typedef typename traits_type::int_type    int_type;
  110.       typedef typename traits_type::off_type    off_type;
  111.       typedef typename traits_type::pos_type    pos_type;
  112.       /** @deprecated use pstreams::fd_type instead. */
  113.       typedef fd_type                           fd_t;
  114.  
  115.       /// Default constructor.
  116.       basic_pstreambuf();
  117.  
  118.       /// Constructor that initialises the buffer with @a cmd.
  119.       basic_pstreambuf(const std::string& cmd, pmode mode);
  120.  
  121.       /// Constructor that initialises the buffer with @a file and @a argv.
  122.       basic_pstreambuf( const std::string& file,
  123.                         const argv_type& argv,
  124.                         pmode mode );
  125.  
  126.       /// Destructor.
  127.       ~basic_pstreambuf();
  128.  
  129.       /// Initialise the stream buffer with @a cmd.
  130.       basic_pstreambuf*
  131.       open(const std::string& cmd, pmode mode);
  132.  
  133.       /// Initialise the stream buffer with @a file and @a argv.
  134.       basic_pstreambuf*
  135.       open(const std::string& file, const argv_type& argv, pmode mode);
  136.  
  137.       /// Close the stream buffer and wait for the process to exit.
  138.       basic_pstreambuf*
  139.       close();
  140.  
  141.       /// Send a signal to the process.
  142.       basic_pstreambuf*
  143.       kill(int signal = SIGTERM);
  144.  
  145.       /// Send a signal to the process' process group.
  146.       basic_pstreambuf*
  147.       killpg(int signal = SIGTERM);
  148.  
  149.       /// Close the pipe connected to the process' stdin.
  150.       void
  151.       peof();
  152.  
  153.       /// Change active input source.
  154.       bool
  155.       read_err(bool readerr = true);
  156.  
  157.       /// Report whether the stream buffer has been initialised.
  158.       bool
  159.       is_open() const;
  160.  
  161.       /// Report whether the process has exited.
  162.       bool
  163.       exited();
  164.  
  165. #if REDI_EVISCERATE_PSTREAMS
  166.       /// Obtain FILE pointers for each of the process' standard streams.
  167.       std::size_t
  168.       fopen(FILE*& in, FILE*& out, FILE*& err);
  169. #endif
  170.  
  171.       /// Return the exit status of the process.
  172.       int
  173.       status() const;
  174.  
  175.       /// Return the error number (errno) for the most recent failed operation.
  176.       int
  177.       error() const;
  178.  
  179.     protected:
  180.       /// Transfer characters to the pipe when character buffer overflows.
  181.       int_type
  182.       overflow(int_type c);
  183.  
  184.       /// Transfer characters from the pipe when the character buffer is empty.
  185.       int_type
  186.       underflow();
  187.  
  188.       /// Make a character available to be returned by the next extraction.
  189.       int_type
  190.       pbackfail(int_type c = traits_type::eof());
  191.  
  192.       /// Write any buffered characters to the stream.
  193.       int
  194.       sync();
  195.  
  196.       /// Insert multiple characters into the pipe.
  197.       std::streamsize
  198.       xsputn(const char_type* s, std::streamsize n);
  199.  
  200.       /// Insert a sequence of characters into the pipe.
  201.       std::streamsize
  202.       write(const char_type* s, std::streamsize n);
  203.  
  204.       /// Extract a sequence of characters from the pipe.
  205.       std::streamsize
  206.       read(char_type* s, std::streamsize n);
  207.  
  208.       /// Report how many characters can be read from active input without blocking.
  209.       std::streamsize
  210.       showmanyc();
  211.  
  212.     protected:
  213.       /// Enumerated type to indicate whether stdout or stderr is to be read.
  214.       enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
  215.  
  216.       /// Initialise pipes and fork process.
  217.       pid_t
  218.       fork(pmode mode);
  219.  
  220.       /// Wait for the child process to exit.
  221.       int
  222.       wait(bool nohang = false);
  223.  
  224.       /// Return the file descriptor for the output pipe.
  225.       fd_type&
  226.       wpipe();
  227.  
  228.       /// Return the file descriptor for the active input pipe.
  229.       fd_type&
  230.       rpipe();
  231.  
  232.       /// Return the file descriptor for the specified input pipe.
  233.       fd_type&
  234.       rpipe(buf_read_src which);
  235.  
  236.       void
  237.       create_buffers(pmode mode);
  238.  
  239.       void
  240.       destroy_buffers(pmode mode);
  241.  
  242.       /// Writes buffered characters to the process' stdin pipe.
  243.       bool
  244.       empty_buffer();
  245.  
  246.       bool
  247.       fill_buffer(bool non_blocking = false);
  248.  
  249.       /// Return the active input buffer.
  250.       char_type*
  251.       rbuffer();
  252.  
  253.       buf_read_src
  254.       switch_read_buffer(buf_read_src);
  255.  
  256.     private:
  257.       basic_pstreambuf(const basic_pstreambuf&);
  258.       basic_pstreambuf& operator=(const basic_pstreambuf&);
  259.  
  260.       void
  261.       init_rbuffers();
  262.  
  263.       pid_t         ppid_;        // pid of process
  264.       fd_type       wpipe_;       // pipe used to write to process' stdin
  265.       fd_type       rpipe_[2];    // two pipes to read from, stdout and stderr
  266.       char_type*    wbuffer_;
  267.       char_type*    rbuffer_[2];
  268.       char_type*    rbufstate_[3];
  269.       /// Index into rpipe_[] to indicate active source for read operations.
  270.       buf_read_src  rsrc_;
  271.       int           status_;      // hold exit status of child process
  272.       int           error_;       // hold errno if fork() or exec() fails
  273.     };
  274.  
  275.   /// Class template for common base class.
  276.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  277.     class pstream_common
  278.     : virtual public std::basic_ios<CharT, Traits>
  279.     , virtual public pstreams
  280.     {
  281.     protected:
  282.       typedef basic_pstreambuf<CharT, Traits>       streambuf_type;
  283.  
  284.       typedef pstreams::pmode                       pmode;
  285.       typedef pstreams::argv_type                   argv_type;
  286.  
  287.       /// Default constructor.
  288.       pstream_common();
  289.  
  290.       /// Constructor that initialises the stream by starting a process.
  291.       pstream_common(const std::string& cmd, pmode mode);
  292.  
  293.       /// Constructor that initialises the stream by starting a process.
  294.       pstream_common(const std::string& file, const argv_type& argv, pmode mode);
  295.  
  296.       /// Pure virtual destructor.
  297.       virtual
  298.       ~pstream_common() = 0;
  299.  
  300.       /// Start a process.
  301.       void
  302.       do_open(const std::string& cmd, pmode mode);
  303.  
  304.       /// Start a process.
  305.       void
  306.       do_open(const std::string& file, const argv_type& argv, pmode mode);
  307.  
  308.     public:
  309.       /// Close the pipe.
  310.       void
  311.       close();
  312.  
  313.       /// Report whether the stream's buffer has been initialised.
  314.       bool
  315.       is_open() const;
  316.  
  317.       /// Return the command used to initialise the stream.
  318.       const std::string&
  319.       command() const;
  320.  
  321.       /// Return a pointer to the stream buffer.
  322.       streambuf_type*
  323.       rdbuf() const;
  324.  
  325. #if REDI_EVISCERATE_PSTREAMS
  326.       /// Obtain FILE pointers for each of the process' standard streams.
  327.       std::size_t
  328.       fopen(FILE*& in, FILE*& out, FILE*& err);
  329. #endif
  330.  
  331.     protected:
  332.       std::string       command_; ///< The command used to start the process.
  333.       streambuf_type    buf_;     ///< The stream buffer.
  334.     };
  335.  
  336.  
  337.   /**
  338.    * @class basic_ipstream
  339.    * @brief Class template for Input PStreams.
  340.    *
  341.    * Reading from an ipstream reads the command's standard output and/or
  342.    * standard error (depending on how the ipstream is opened)
  343.    * and the command's standard input is the same as that of the process
  344.    * that created the object, unless altered by the command itself.
  345.    */
  346.  
  347.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  348.     class basic_ipstream
  349.     : public std::basic_istream<CharT, Traits>
  350.     , public pstream_common<CharT, Traits>
  351.     , virtual public pstreams
  352.     {
  353.       typedef std::basic_istream<CharT, Traits>     istream_type;
  354.       typedef pstream_common<CharT, Traits>         pbase_type;
  355.  
  356.       using pbase_type::buf_;  // declare name in this scope
  357.  
  358.       // Ensure a basic_ipstream will read from at least one pipe
  359.       pmode readable(pmode mode)
  360.       {
  361.         if (!(mode & (pstdout|pstderr)))
  362.           mode |= pstdout;
  363.         return mode;
  364.       }
  365.  
  366.     public:
  367.       /// Type used to specify how to connect to the process.
  368.       typedef typename pbase_type::pmode            pmode;
  369.  
  370.       /// Type used to hold the arguments for a command.
  371.       typedef typename pbase_type::argv_type        argv_type;
  372.  
  373.       /// Default constructor, creates an uninitialised stream.
  374.       basic_ipstream()
  375.       : istream_type(NULL), pbase_type()
  376.       { }
  377.  
  378.       /**
  379.        * @brief Constructor that initialises the stream by starting a process.
  380.        *
  381.        * Initialises the stream buffer by calling do_open() with the supplied
  382.        * arguments.
  383.        *
  384.        * @param cmd   a string containing a shell command.
  385.        * @param mode  the I/O mode to use when opening the pipe.
  386.        * @see   do_open(const std::string&, pmode)
  387.        */
  388.       explicit
  389.       basic_ipstream(const std::string& cmd, pmode mode = pstdout)
  390.       : istream_type(NULL), pbase_type(cmd, readable(mode))
  391.       { }
  392.  
  393.       /**
  394.        * @brief Constructor that initialises the stream by starting a process.
  395.        *
  396.        * Initialises the stream buffer by calling do_open() with the supplied
  397.        * arguments.
  398.        *
  399.        * @param file  a string containing the pathname of a program to execute.
  400.        * @param argv  a vector of argument strings passed to the new program.
  401.        * @param mode  the I/O mode to use when opening the pipe.
  402.        * @see   do_open(const std::string&, const argv_type&, pmode)
  403.        */
  404.       basic_ipstream( const std::string& file,
  405.                       const argv_type& argv,
  406.                       pmode mode = pstdout )
  407.       : istream_type(NULL), pbase_type(file, argv, readable(mode))
  408.       { }
  409.  
  410.       /**
  411.        * @brief Constructor that initialises the stream by starting a process.
  412.        *
  413.        * Initialises the stream buffer by calling
  414.        * @c do_open(argv[0],argv,mode|pstdout)
  415.        *
  416.        * @param argv  a vector of argument strings passed to the new program.
  417.        * @param mode  the I/O mode to use when opening the pipe.
  418.        * @see   do_open(const std::string&, const argv_type&, pmode)
  419.        */
  420.       explicit
  421.       basic_ipstream(const argv_type& argv, pmode mode = pstdout)
  422.       : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode))
  423.       { }
  424.  
  425. #if __cplusplus >= 201103L
  426.       template<typename T>
  427.         explicit
  428.         basic_ipstream(std::initializer_list<T> args, pmode mode = pstdout)
  429.         : basic_ipstream(argv_type(args.begin(), args.end()), mode)
  430.         { }
  431. #endif
  432.  
  433.       /**
  434.        * @brief Destructor.
  435.        *
  436.        * Closes the stream and waits for the child to exit.
  437.        */
  438.       ~basic_ipstream()
  439.       { }
  440.  
  441.       /**
  442.        * @brief Start a process.
  443.        *
  444.        * Calls do_open( @a cmd , @a mode|pstdout ).
  445.        *
  446.        * @param cmd   a string containing a shell command.
  447.        * @param mode  the I/O mode to use when opening the pipe.
  448.        * @see   do_open(const std::string&, pmode)
  449.        */
  450.       void
  451.       open(const std::string& cmd, pmode mode = pstdout)
  452.       {
  453.         this->do_open(cmd, readable(mode));
  454.       }
  455.  
  456.       /**
  457.        * @brief Start a process.
  458.        *
  459.        * Calls do_open( @a file , @a argv , @a mode|pstdout ).
  460.        *
  461.        * @param file  a string containing the pathname of a program to execute.
  462.        * @param argv  a vector of argument strings passed to the new program.
  463.        * @param mode  the I/O mode to use when opening the pipe.
  464.        * @see   do_open(const std::string&, const argv_type&, pmode)
  465.        */
  466.       void
  467.       open( const std::string& file,
  468.             const argv_type& argv,
  469.             pmode mode = pstdout )
  470.       {
  471.         this->do_open(file, argv, readable(mode));
  472.       }
  473.  
  474.       /**
  475.        * @brief Set streambuf to read from process' @c stdout.
  476.        * @return  @c *this
  477.        */
  478.       basic_ipstream&
  479.       out()
  480.       {
  481.         this->buf_.read_err(false);
  482.         return *this;
  483.       }
  484.  
  485.       /**
  486.        * @brief Set streambuf to read from process' @c stderr.
  487.        * @return  @c *this
  488.        */
  489.       basic_ipstream&
  490.       err()
  491.       {
  492.         this->buf_.read_err(true);
  493.         return *this;
  494.       }
  495.     };
  496.  
  497.  
  498.   /**
  499.    * @class basic_opstream
  500.    * @brief Class template for Output PStreams.
  501.    *
  502.    * Writing to an open opstream writes to the standard input of the command;
  503.    * the command's standard output is the same as that of the process that
  504.    * created the pstream object, unless altered by the command itself.
  505.    */
  506.  
  507.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  508.     class basic_opstream
  509.     : public std::basic_ostream<CharT, Traits>
  510.     , public pstream_common<CharT, Traits>
  511.     , virtual public pstreams
  512.     {
  513.       typedef std::basic_ostream<CharT, Traits>     ostream_type;
  514.       typedef pstream_common<CharT, Traits>         pbase_type;
  515.  
  516.       using pbase_type::buf_;  // declare name in this scope
  517.  
  518.     public:
  519.       /// Type used to specify how to connect to the process.
  520.       typedef typename pbase_type::pmode            pmode;
  521.  
  522.       /// Type used to hold the arguments for a command.
  523.       typedef typename pbase_type::argv_type        argv_type;
  524.  
  525.       /// Default constructor, creates an uninitialised stream.
  526.       basic_opstream()
  527.       : ostream_type(NULL), pbase_type()
  528.       { }
  529.  
  530.       /**
  531.        * @brief Constructor that initialises the stream by starting a process.
  532.        *
  533.        * Initialises the stream buffer by calling do_open() with the supplied
  534.        * arguments.
  535.        *
  536.        * @param cmd   a string containing a shell command.
  537.        * @param mode  the I/O mode to use when opening the pipe.
  538.        * @see   do_open(const std::string&, pmode)
  539.        */
  540.       explicit
  541.       basic_opstream(const std::string& cmd, pmode mode = pstdin)
  542.       : ostream_type(NULL), pbase_type(cmd, mode|pstdin)
  543.       { }
  544.  
  545.       /**
  546.        * @brief Constructor that initialises the stream by starting a process.
  547.        *
  548.        * Initialises the stream buffer by calling do_open() with the supplied
  549.        * arguments.
  550.        *
  551.        * @param file  a string containing the pathname of a program to execute.
  552.        * @param argv  a vector of argument strings passed to the new program.
  553.        * @param mode  the I/O mode to use when opening the pipe.
  554.        * @see   do_open(const std::string&, const argv_type&, pmode)
  555.        */
  556.       basic_opstream( const std::string& file,
  557.                       const argv_type& argv,
  558.                       pmode mode = pstdin )
  559.       : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
  560.       { }
  561.  
  562.       /**
  563.        * @brief Constructor that initialises the stream by starting a process.
  564.        *
  565.        * Initialises the stream buffer by calling
  566.        * @c do_open(argv[0],argv,mode|pstdin)
  567.        *
  568.        * @param argv  a vector of argument strings passed to the new program.
  569.        * @param mode  the I/O mode to use when opening the pipe.
  570.        * @see   do_open(const std::string&, const argv_type&, pmode)
  571.        */
  572.       explicit
  573.       basic_opstream(const argv_type& argv, pmode mode = pstdin)
  574.       : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin)
  575.       { }
  576.  
  577. #if __cplusplus >= 201103L
  578.       /**
  579.        * @brief Constructor that initialises the stream by starting a process.
  580.        *
  581.        * @param args  a list of argument strings passed to the new program.
  582.        * @param mode  the I/O mode to use when opening the pipe.
  583.        * @see   do_open(const std::string&, const argv_type&, pmode)
  584.        */
  585.       template<typename T>
  586.         explicit
  587.         basic_opstream(std::initializer_list<T> args, pmode mode = pstdin)
  588.         : basic_opstream(argv_type(args.begin(), args.end()), mode)
  589.         { }
  590. #endif
  591.  
  592.       /**
  593.        * @brief Destructor
  594.        *
  595.        * Closes the stream and waits for the child to exit.
  596.        */
  597.       ~basic_opstream() { }
  598.  
  599.       /**
  600.        * @brief Start a process.
  601.        *
  602.        * Calls do_open( @a cmd , @a mode|pstdin ).
  603.        *
  604.        * @param cmd   a string containing a shell command.
  605.        * @param mode  the I/O mode to use when opening the pipe.
  606.        * @see   do_open(const std::string&, pmode)
  607.        */
  608.       void
  609.       open(const std::string& cmd, pmode mode = pstdin)
  610.       {
  611.         this->do_open(cmd, mode|pstdin);
  612.       }
  613.  
  614.       /**
  615.        * @brief Start a process.
  616.        *
  617.        * Calls do_open( @a file , @a argv , @a mode|pstdin ).
  618.        *
  619.        * @param file  a string containing the pathname of a program to execute.
  620.        * @param argv  a vector of argument strings passed to the new program.
  621.        * @param mode  the I/O mode to use when opening the pipe.
  622.        * @see   do_open(const std::string&, const argv_type&, pmode)
  623.        */
  624.       void
  625.       open( const std::string& file,
  626.             const argv_type& argv,
  627.             pmode mode = pstdin)
  628.       {
  629.         this->do_open(file, argv, mode|pstdin);
  630.       }
  631.     };
  632.  
  633.  
  634.   /**
  635.    * @class basic_pstream
  636.    * @brief Class template for Bidirectional PStreams.
  637.    *
  638.    * Writing to a pstream opened with @c pmode @c pstdin writes to the
  639.    * standard input of the command.
  640.    * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr
  641.    * reads the command's standard output and/or standard error.
  642.    * Any of the process' @c stdin, @c stdout or @c stderr that is not
  643.    * connected to the pstream (as specified by the @c pmode)
  644.    * will be the same as the process that created the pstream object,
  645.    * unless altered by the command itself.
  646.    */
  647.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  648.     class basic_pstream
  649.     : public std::basic_iostream<CharT, Traits>
  650.     , public pstream_common<CharT, Traits>
  651.     , virtual public pstreams
  652.     {
  653.       typedef std::basic_iostream<CharT, Traits>    iostream_type;
  654.       typedef pstream_common<CharT, Traits>         pbase_type;
  655.  
  656.       using pbase_type::buf_;  // declare name in this scope
  657.  
  658.     public:
  659.       /// Type used to specify how to connect to the process.
  660.       typedef typename pbase_type::pmode            pmode;
  661.  
  662.       /// Type used to hold the arguments for a command.
  663.       typedef typename pbase_type::argv_type        argv_type;
  664.  
  665.       /// Default constructor, creates an uninitialised stream.
  666.       basic_pstream()
  667.       : iostream_type(NULL), pbase_type()
  668.       { }
  669.  
  670.       /**
  671.        * @brief Constructor that initialises the stream by starting a process.
  672.        *
  673.        * Initialises the stream buffer by calling do_open() with the supplied
  674.        * arguments.
  675.        *
  676.        * @param cmd   a string containing a shell command.
  677.        * @param mode  the I/O mode to use when opening the pipe.
  678.        * @see   do_open(const std::string&, pmode)
  679.        */
  680.       explicit
  681.       basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin)
  682.       : iostream_type(NULL), pbase_type(cmd, mode)
  683.       { }
  684.  
  685.       /**
  686.        * @brief Constructor that initialises the stream by starting a process.
  687.        *
  688.        * Initialises the stream buffer by calling do_open() with the supplied
  689.        * arguments.
  690.        *
  691.        * @param file  a string containing the pathname of a program to execute.
  692.        * @param argv  a vector of argument strings passed to the new program.
  693.        * @param mode  the I/O mode to use when opening the pipe.
  694.        * @see   do_open(const std::string&, const argv_type&, pmode)
  695.        */
  696.       basic_pstream( const std::string& file,
  697.                      const argv_type& argv,
  698.                      pmode mode = pstdout|pstdin )
  699.       : iostream_type(NULL), pbase_type(file, argv, mode)
  700.       { }
  701.  
  702.       /**
  703.        * @brief Constructor that initialises the stream by starting a process.
  704.        *
  705.        * Initialises the stream buffer by calling
  706.        * @c do_open(argv[0],argv,mode)
  707.        *
  708.        * @param argv  a vector of argument strings passed to the new program.
  709.        * @param mode  the I/O mode to use when opening the pipe.
  710.        * @see   do_open(const std::string&, const argv_type&, pmode)
  711.        */
  712.       explicit
  713.       basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin)
  714.       : iostream_type(NULL), pbase_type(argv.at(0), argv, mode)
  715.       { }
  716.  
  717. #if __cplusplus >= 201103L
  718.       /**
  719.        * @brief Constructor that initialises the stream by starting a process.
  720.        *
  721.        * @param l     a list of argument strings passed to the new program.
  722.        * @param mode  the I/O mode to use when opening the pipe.
  723.        * @see   do_open(const std::string&, const argv_type&, pmode)
  724.        */
  725.       template<typename T>
  726.         explicit
  727.         basic_pstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
  728.         : basic_pstream(argv_type(l.begin(), l.end()), mode)
  729.         { }
  730. #endif
  731.  
  732.       /**
  733.        * @brief Destructor
  734.        *
  735.        * Closes the stream and waits for the child to exit.
  736.        */
  737.       ~basic_pstream() { }
  738.  
  739.       /**
  740.        * @brief Start a process.
  741.        *
  742.        * Calls do_open( @a cnd , @a mode ).
  743.        *
  744.        * @param cmd   a string containing a shell command.
  745.        * @param mode  the I/O mode to use when opening the pipe.
  746.        * @see   do_open(const std::string&, pmode)
  747.        */
  748.       void
  749.       open(const std::string& cmd, pmode mode = pstdout|pstdin)
  750.       {
  751.         this->do_open(cmd, mode);
  752.       }
  753.  
  754.       /**
  755.        * @brief Start a process.
  756.        *
  757.        * Calls do_open( @a file , @a argv , @a mode ).
  758.        *
  759.        * @param file  a string containing the pathname of a program to execute.
  760.        * @param argv  a vector of argument strings passed to the new program.
  761.        * @param mode  the I/O mode to use when opening the pipe.
  762.        * @see   do_open(const std::string&, const argv_type&, pmode)
  763.        */
  764.       void
  765.       open( const std::string& file,
  766.             const argv_type& argv,
  767.             pmode mode = pstdout|pstdin )
  768.       {
  769.         this->do_open(file, argv, mode);
  770.       }
  771.  
  772.       /**
  773.        * @brief Set streambuf to read from process' @c stdout.
  774.        * @return  @c *this
  775.        */
  776.       basic_pstream&
  777.       out()
  778.       {
  779.         this->buf_.read_err(false);
  780.         return *this;
  781.       }
  782.  
  783.       /**
  784.        * @brief Set streambuf to read from process' @c stderr.
  785.        * @return  @c *this
  786.        */
  787.       basic_pstream&
  788.       err()
  789.       {
  790.         this->buf_.read_err(true);
  791.         return *this;
  792.       }
  793.     };
  794.  
  795.  
  796.   /**
  797.    * @class basic_rpstream
  798.    * @brief Class template for Restricted PStreams.
  799.    *
  800.    * Writing to an rpstream opened with @c pmode @c pstdin writes to the
  801.    * standard input of the command.
  802.    * It is not possible to read directly from an rpstream object, to use
  803.    * an rpstream as in istream you must call either basic_rpstream::out()
  804.    * or basic_rpstream::err(). This is to prevent accidental reads from
  805.    * the wrong input source. If the rpstream was not opened with @c pmode
  806.    * @c pstderr then the class cannot read the process' @c stderr, and
  807.    * basic_rpstream::err() will return an istream that reads from the
  808.    * process' @c stdout, and vice versa.
  809.    * Reading from an rpstream opened with @c pmode @c pstdout and/or
  810.    * @c pstderr reads the command's standard output and/or standard error.
  811.    * Any of the process' @c stdin, @c stdout or @c stderr that is not
  812.    * connected to the pstream (as specified by the @c pmode)
  813.    * will be the same as the process that created the pstream object,
  814.    * unless altered by the command itself.
  815.    */
  816.  
  817.   template <typename CharT, typename Traits = std::char_traits<CharT> >
  818.     class basic_rpstream
  819.     : public std::basic_ostream<CharT, Traits>
  820.     , private std::basic_istream<CharT, Traits>
  821.     , private pstream_common<CharT, Traits>
  822.     , virtual public pstreams
  823.     {
  824.       typedef std::basic_ostream<CharT, Traits>     ostream_type;
  825.       typedef std::basic_istream<CharT, Traits>     istream_type;
  826.       typedef pstream_common<CharT, Traits>         pbase_type;
  827.  
  828.       using pbase_type::buf_;  // declare name in this scope
  829.  
  830.     public:
  831.       /// Type used to specify how to connect to the process.
  832.       typedef typename pbase_type::pmode            pmode;
  833.  
  834.       /// Type used to hold the arguments for a command.
  835.       typedef typename pbase_type::argv_type        argv_type;
  836.  
  837.       /// Default constructor, creates an uninitialised stream.
  838.       basic_rpstream()
  839.       : ostream_type(NULL), istream_type(NULL), pbase_type()
  840.       { }
  841.  
  842.       /**
  843.        * @brief  Constructor that initialises the stream by starting a process.
  844.        *
  845.        * Initialises the stream buffer by calling do_open() with the supplied
  846.        * arguments.
  847.        *
  848.        * @param cmd   a string containing a shell command.
  849.        * @param mode  the I/O mode to use when opening the pipe.
  850.        * @see   do_open(const std::string&, pmode)
  851.        */
  852.       explicit
  853.       basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin)
  854.       : ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode)
  855.       { }
  856.  
  857.       /**
  858.        * @brief  Constructor that initialises the stream by starting a process.
  859.        *
  860.        * Initialises the stream buffer by calling do_open() with the supplied
  861.        * arguments.
  862.        *
  863.        * @param file a string containing the pathname of a program to execute.
  864.        * @param argv a vector of argument strings passed to the new program.
  865.        * @param mode the I/O mode to use when opening the pipe.
  866.        * @see   do_open(const std::string&, const argv_type&, pmode)
  867.        */
  868.       basic_rpstream( const std::string& file,
  869.                       const argv_type& argv,
  870.                       pmode mode = pstdout|pstdin )
  871.       : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
  872.       { }
  873.  
  874.       /**
  875.        * @brief Constructor that initialises the stream by starting a process.
  876.        *
  877.        * Initialises the stream buffer by calling
  878.        * @c do_open(argv[0],argv,mode)
  879.        *
  880.        * @param argv  a vector of argument strings passed to the new program.
  881.        * @param mode  the I/O mode to use when opening the pipe.
  882.        * @see   do_open(const std::string&, const argv_type&, pmode)
  883.        */
  884.       explicit
  885.       basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin)
  886.       : ostream_type(NULL), istream_type(NULL),
  887.         pbase_type(argv.at(0), argv, mode)
  888.       { }
  889.  
  890. #if __cplusplus >= 201103L
  891.       /**
  892.        * @brief Constructor that initialises the stream by starting a process.
  893.        *
  894.        * @param l     a list of argument strings passed to the new program.
  895.        * @param mode  the I/O mode to use when opening the pipe.
  896.        * @see   do_open(const std::string&, const argv_type&, pmode)
  897.        */
  898.       template<typename T>
  899.         explicit
  900.         basic_rpstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
  901.         : basic_rpstream(argv_type(l.begin(), l.end()), mode)
  902.         { }
  903. #endif
  904.  
  905.       /// Destructor
  906.       ~basic_rpstream() { }
  907.  
  908.       /**
  909.        * @brief  Start a process.
  910.        *
  911.        * Calls do_open( @a cmd , @a mode ).
  912.        *
  913.        * @param cmd   a string containing a shell command.
  914.        * @param mode  the I/O mode to use when opening the pipe.
  915.        * @see   do_open(const std::string&, pmode)
  916.        */
  917.       void
  918.       open(const std::string& cmd, pmode mode = pstdout|pstdin)
  919.       {
  920.         this->do_open(cmd, mode);
  921.       }
  922.  
  923.       /**
  924.        * @brief  Start a process.
  925.        *
  926.        * Calls do_open( @a file , @a argv , @a mode ).
  927.        *
  928.        * @param file a string containing the pathname of a program to execute.
  929.        * @param argv a vector of argument strings passed to the new program.
  930.        * @param mode the I/O mode to use when opening the pipe.
  931.        * @see   do_open(const std::string&, const argv_type&, pmode)
  932.        */
  933.       void
  934.       open( const std::string& file,
  935.             const argv_type& argv,
  936.             pmode mode = pstdout|pstdin )
  937.       {
  938.         this->do_open(file, argv, mode);
  939.       }
  940.  
  941.       /**
  942.        * @brief  Obtain a reference to the istream that reads
  943.        *         the process' @c stdout.
  944.        * @return @c *this
  945.        */
  946.       istream_type&
  947.       out()
  948.       {
  949.         this->buf_.read_err(false);
  950.         return *this;
  951.       }
  952.  
  953.       /**
  954.        * @brief  Obtain a reference to the istream that reads
  955.        *         the process' @c stderr.
  956.        * @return @c *this
  957.        */
  958.       istream_type&
  959.       err()
  960.       {
  961.         this->buf_.read_err(true);
  962.         return *this;
  963.       }
  964.     };
  965.  
  966.  
  967.   /// Type definition for common template specialisation.
  968.   typedef basic_pstreambuf<char> pstreambuf;
  969.   /// Type definition for common template specialisation.
  970.   typedef basic_ipstream<char> ipstream;
  971.   /// Type definition for common template specialisation.
  972.   typedef basic_opstream<char> opstream;
  973.   /// Type definition for common template specialisation.
  974.   typedef basic_pstream<char> pstream;
  975.   /// Type definition for common template specialisation.
  976.   typedef basic_rpstream<char> rpstream;
  977.  
  978.  
  979.   /**
  980.    * When inserted into an output pstream the manipulator calls
  981.    * basic_pstreambuf<C,T>::peof() to close the output pipe,
  982.    * causing the child process to receive the end-of-file indicator
  983.    * on subsequent reads from its @c stdin stream.
  984.    *
  985.    * @brief   Manipulator to close the pipe connected to the process' stdin.
  986.    * @param   s  An output PStream class.
  987.    * @return  The stream object the manipulator was invoked on.
  988.    * @see     basic_pstreambuf<C,T>::peof()
  989.    * @relates basic_opstream basic_pstream basic_rpstream
  990.    */
  991.   template <typename C, typename T>
  992.     inline std::basic_ostream<C,T>&
  993.     peof(std::basic_ostream<C,T>& s)
  994.     {
  995.       typedef basic_pstreambuf<C,T> pstreambuf_type;
  996.       if (pstreambuf_type* p = dynamic_cast<pstreambuf_type*>(s.rdbuf()))
  997.         p->peof();
  998.       return s;
  999.     }
  1000.  
  1001.  
  1002.   /*
  1003.    * member definitions for pstreambuf
  1004.    */
  1005.  
  1006.  
  1007.   /**
  1008.    * @class basic_pstreambuf
  1009.    * Provides underlying streambuf functionality for the PStreams classes.
  1010.    */
  1011.  
  1012.   /** Creates an uninitialised stream buffer. */
  1013.   template <typename C, typename T>
  1014.     inline
  1015.     basic_pstreambuf<C,T>::basic_pstreambuf()
  1016.     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
  1017.     , wpipe_(-1)
  1018.     , wbuffer_(NULL)
  1019.     , rsrc_(rsrc_out)
  1020.     , status_(-1)
  1021.     , error_(0)
  1022.     {
  1023.       init_rbuffers();
  1024.     }
  1025.  
  1026.   /**
  1027.    * Initialises the stream buffer by calling open() with the supplied
  1028.    * arguments.
  1029.    *
  1030.    * @param cmd   a string containing a shell command.
  1031.    * @param mode  the I/O mode to use when opening the pipe.
  1032.    * @see   open()
  1033.    */
  1034.   template <typename C, typename T>
  1035.     inline
  1036.     basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& cmd, pmode mode)
  1037.     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
  1038.     , wpipe_(-1)
  1039.     , wbuffer_(NULL)
  1040.     , rsrc_(rsrc_out)
  1041.     , status_(-1)
  1042.     , error_(0)
  1043.     {
  1044.       init_rbuffers();
  1045.       open(cmd, mode);
  1046.     }
  1047.  
  1048.   /**
  1049.    * Initialises the stream buffer by calling open() with the supplied
  1050.    * arguments.
  1051.    *
  1052.    * @param file  a string containing the name of a program to execute.
  1053.    * @param argv  a vector of argument strings passsed to the new program.
  1054.    * @param mode  the I/O mode to use when opening the pipe.
  1055.    * @see   open()
  1056.    */
  1057.   template <typename C, typename T>
  1058.     inline
  1059.     basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
  1060.                                              const argv_type& argv,
  1061.                                              pmode mode )
  1062.     : ppid_(-1)   // initialise to -1 to indicate no process run yet.
  1063.     , wpipe_(-1)
  1064.     , wbuffer_(NULL)
  1065.     , rsrc_(rsrc_out)
  1066.     , status_(-1)
  1067.     , error_(0)
  1068.     {
  1069.       init_rbuffers();
  1070.       open(file, argv, mode);
  1071.     }
  1072.  
  1073.   /**
  1074.    * Closes the stream by calling close().
  1075.    * @see close()
  1076.    */
  1077.   template <typename C, typename T>
  1078.     inline
  1079.     basic_pstreambuf<C,T>::~basic_pstreambuf()
  1080.     {
  1081.       close();
  1082.     }
  1083.  
  1084.   /**
  1085.    * Starts a new process by passing @a command to the shell (/bin/sh)
  1086.    * and opens pipes to the process with the specified @a mode.
  1087.    *
  1088.    * If @a mode contains @c pstdout the initial read source will be
  1089.    * the child process' stdout, otherwise if @a mode  contains @c pstderr
  1090.    * the initial read source will be the child's stderr.
  1091.    *
  1092.    * Will duplicate the actions of  the  shell  in searching for an
  1093.    * executable file if the specified file name does not contain a slash (/)
  1094.    * character.
  1095.    *
  1096.    * @warning
  1097.    * There is no way to tell whether the shell command succeeded, this
  1098.    * function will always succeed unless resource limits (such as
  1099.    * memory usage, or number of processes or open files) are exceeded.
  1100.    * This means is_open() will return true even if @a command cannot
  1101.    * be executed.
  1102.    * Use pstreambuf::open(const std::string&, const argv_type&, pmode)
  1103.    * if you need to know whether the command failed to execute.
  1104.    *
  1105.    * @param   command  a string containing a shell command.
  1106.    * @param   mode     a bitwise OR of one or more of @c out, @c in, @c err.
  1107.    * @return  NULL if the shell could not be started or the
  1108.    *          pipes could not be opened, @c this otherwise.
  1109.    * @see     <b>execl</b>(3)
  1110.    */
  1111.   template <typename C, typename T>
  1112.     basic_pstreambuf<C,T>*
  1113.     basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
  1114.     {
  1115.       const char * shell_path = "/bin/sh";
  1116. #if 0
  1117.       const std::string argv[] = { "sh", "-c", command };
  1118.       return this->open(shell_path, argv_type(argv, argv+3), mode);
  1119. #else
  1120.       basic_pstreambuf<C,T>* ret = NULL;
  1121.  
  1122.       if (!is_open())
  1123.       {
  1124.         switch(fork(mode))
  1125.         {
  1126.         case 0 :
  1127.           // this is the new process, exec command
  1128.           ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
  1129.  
  1130.           // can only reach this point if exec() failed
  1131.  
  1132.           // parent can get exit code from waitpid()
  1133.           ::_exit(errno);
  1134.           // using std::exit() would make static dtors run twice
  1135.  
  1136.         case -1 :
  1137.           // couldn't fork, error already handled in pstreambuf::fork()
  1138.           break;
  1139.  
  1140.         default :
  1141.           // this is the parent process
  1142.           // activate buffers
  1143.           create_buffers(mode);
  1144.           ret = this;
  1145.         }
  1146.       }
  1147.       return ret;
  1148. #endif
  1149.     }
  1150.  
  1151.   /**
  1152.    * @brief  Helper function to close a file descriptor.
  1153.    *
  1154.    * Inspects @a fd and calls <b>close</b>(3) if it has a non-negative value.
  1155.    *
  1156.    * @param   fd  a file descriptor.
  1157.    * @relates basic_pstreambuf
  1158.    */
  1159.   inline void
  1160.   close_fd(pstreams::fd_type& fd)
  1161.   {
  1162.     if (fd >= 0 && ::close(fd) == 0)
  1163.       fd = -1;
  1164.   }
  1165.  
  1166.   /**
  1167.    * @brief  Helper function to close an array of file descriptors.
  1168.    *
  1169.    * Calls @c close_fd() on each member of the array.
  1170.    * The length of the array is determined automatically by
  1171.    * template argument deduction to avoid errors.
  1172.    *
  1173.    * @param   fds  an array of file descriptors.
  1174.    * @relates basic_pstreambuf
  1175.    */
  1176.   template <int N>
  1177.     inline void
  1178.     close_fd_array(pstreams::fd_type (&fds)[N])
  1179.     {
  1180.       for (std::size_t i = 0; i < N; ++i)
  1181.         close_fd(fds[i]);
  1182.     }
  1183.  
  1184.   /**
  1185.    * Starts a new process by executing @a file with the arguments in
  1186.    * @a argv and opens pipes to the process with the specified @a mode.
  1187.    *
  1188.    * By convention @c argv[0] should be the file name of the file being
  1189.    * executed.
  1190.    *
  1191.    * If @a mode contains @c pstdout the initial read source will be
  1192.    * the child process' stdout, otherwise if @a mode  contains @c pstderr
  1193.    * the initial read source will be the child's stderr.
  1194.    *
  1195.    * Will duplicate the actions of  the  shell  in searching for an
  1196.    * executable file if the specified file name does not contain a slash (/)
  1197.    * character.
  1198.    *
  1199.    * Iff @a file is successfully executed then is_open() will return true.
  1200.    * Otherwise, pstreambuf::error() can be used to obtain the value of
  1201.    * @c errno that was set by <b>execvp</b>(3) in the child process.
  1202.    *
  1203.    * The exit status of the new process will be returned by
  1204.    * pstreambuf::status() after pstreambuf::exited() returns true.
  1205.    *
  1206.    * @param   file  a string containing the pathname of a program to execute.
  1207.    * @param   argv  a vector of argument strings passed to the new program.
  1208.    * @param   mode  a bitwise OR of one or more of @c out, @c in and @c err.
  1209.    * @return  NULL if a pipe could not be opened or if the program could
  1210.    *          not be executed, @c this otherwise.
  1211.    * @see     <b>execvp</b>(3)
  1212.    */
  1213.   template <typename C, typename T>
  1214.     basic_pstreambuf<C,T>*
  1215.     basic_pstreambuf<C,T>::open( const std::string& file,
  1216.                                  const argv_type& argv,
  1217.                                  pmode mode )
  1218.     {
  1219.       basic_pstreambuf<C,T>* ret = NULL;
  1220.  
  1221.       if (!is_open())
  1222.       {
  1223.         // constants for read/write ends of pipe
  1224.         enum { RD, WR };
  1225.  
  1226.         // open another pipe and set close-on-exec
  1227.         fd_type ck_exec[] = { -1, -1 };
  1228.         if (-1 == ::pipe(ck_exec)
  1229.             || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
  1230.             || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
  1231.         {
  1232.           error_ = errno;
  1233.           close_fd_array(ck_exec);
  1234.         }
  1235.         else
  1236.         {
  1237.           switch(fork(mode))
  1238.           {
  1239.           case 0 :
  1240.             // this is the new process, exec command
  1241.             {
  1242.               char** arg_v = new char*[argv.size()+1];
  1243.               for (std::size_t i = 0; i < argv.size(); ++i)
  1244.               {
  1245.                 const std::string& src = argv[i];
  1246.                 char*& dest = arg_v[i];
  1247.                 dest = new char[src.size()+1];
  1248.                 dest[ src.copy(dest, src.size()) ] = '\0';
  1249.               }
  1250.               arg_v[argv.size()] = NULL;
  1251.  
  1252.               ::execvp(file.c_str(), arg_v);
  1253.  
  1254.               // can only reach this point if exec() failed
  1255.  
  1256.               // parent can get error code from ck_exec pipe
  1257.               error_ = errno;
  1258.  
  1259.               while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1
  1260.                   && errno == EINTR)
  1261.               { }
  1262.  
  1263.               ::close(ck_exec[WR]);
  1264.               ::close(ck_exec[RD]);
  1265.  
  1266.               ::_exit(error_);
  1267.               // using std::exit() would make static dtors run twice
  1268.             }
  1269.  
  1270.           case -1 :
  1271.             // couldn't fork, error already handled in pstreambuf::fork()
  1272.             close_fd_array(ck_exec);
  1273.             break;
  1274.  
  1275.           default :
  1276.             // this is the parent process
  1277.  
  1278.             // check child called exec() successfully
  1279.             ::close(ck_exec[WR]);
  1280.             switch (::read(ck_exec[RD], &error_, sizeof(error_)))
  1281.             {
  1282.             case 0:
  1283.               // activate buffers
  1284.               create_buffers(mode);
  1285.               ret = this;
  1286.               break;
  1287.             case -1:
  1288.               error_ = errno;
  1289.               break;
  1290.             default:
  1291.               // error_ contains error code from child
  1292.               // call wait() to clean up and set ppid_ to 0
  1293.               this->wait();
  1294.               break;
  1295.             }
  1296.             ::close(ck_exec[RD]);
  1297.           }
  1298.         }
  1299.       }
  1300.       return ret;
  1301.     }
  1302.  
  1303.   /**
  1304.    * Creates pipes as specified by @a mode and calls @c fork() to create
  1305.    * a new process. If the fork is successful the parent process stores
  1306.    * the child's PID and the opened pipes and the child process replaces
  1307.    * its standard streams with the opened pipes.
  1308.    *
  1309.    * If an error occurs the error code will be set to one of the possible
  1310.    * errors for @c pipe() or @c fork().
  1311.    * See your system's documentation for these error codes.
  1312.    *
  1313.    * @param   mode  an OR of pmodes specifying which of the child's
  1314.    *                standard streams to connect to.
  1315.    * @return  On success the PID of the child is returned in the parent's
  1316.    *          context and zero is returned in the child's context.
  1317.    *          On error -1 is returned and the error code is set appropriately.
  1318.    */
  1319.   template <typename C, typename T>
  1320.     pid_t
  1321.     basic_pstreambuf<C,T>::fork(pmode mode)
  1322.     {
  1323.       pid_t pid = -1;
  1324.  
  1325.       // Three pairs of file descriptors, for pipes connected to the
  1326.       // process' stdin, stdout and stderr
  1327.       // (stored in a single array so close_fd_array() can close all at once)
  1328.       fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
  1329.       fd_type* const pin = fd;
  1330.       fd_type* const pout = fd+2;
  1331.       fd_type* const perr = fd+4;
  1332.  
  1333.       // constants for read/write ends of pipe
  1334.       enum { RD, WR };
  1335.  
  1336.       // N.B.
  1337.       // For the pstreambuf pin is an output stream and
  1338.       // pout and perr are input streams.
  1339.  
  1340.       if (!error_ && mode&pstdin && ::pipe(pin))
  1341.         error_ = errno;
  1342.  
  1343.       if (!error_ && mode&pstdout && ::pipe(pout))
  1344.         error_ = errno;
  1345.  
  1346.       if (!error_ && mode&pstderr && ::pipe(perr))
  1347.         error_ = errno;
  1348.  
  1349.       if (!error_)
  1350.       {
  1351.         pid = ::fork();
  1352.         switch (pid)
  1353.         {
  1354.           case 0 :
  1355.           {
  1356.             // this is the new process
  1357.  
  1358.             // for each open pipe close one end and redirect the
  1359.             // respective standard stream to the other end
  1360.  
  1361.             if (*pin >= 0)
  1362.             {
  1363.               ::close(pin[WR]);
  1364.               ::dup2(pin[RD], STDIN_FILENO);
  1365.               ::close(pin[RD]);
  1366.             }
  1367.             if (*pout >= 0)
  1368.             {
  1369.               ::close(pout[RD]);
  1370.               ::dup2(pout[WR], STDOUT_FILENO);
  1371.               ::close(pout[WR]);
  1372.             }
  1373.             if (*perr >= 0)
  1374.             {
  1375.               ::close(perr[RD]);
  1376.               ::dup2(perr[WR], STDERR_FILENO);
  1377.               ::close(perr[WR]);
  1378.             }
  1379.  
  1380. #ifdef _POSIX_JOB_CONTROL
  1381.             if (mode&newpg)
  1382.               ::setpgid(0, 0); // Change to a new process group
  1383. #endif
  1384.  
  1385.             break;
  1386.           }
  1387.           case -1 :
  1388.           {
  1389.             // couldn't fork for some reason
  1390.             error_ = errno;
  1391.             // close any open pipes
  1392.             close_fd_array(fd);
  1393.             break;
  1394.           }
  1395.           default :
  1396.           {
  1397.             // this is the parent process, store process' pid
  1398.             ppid_ = pid;
  1399.  
  1400.             // store one end of open pipes and close other end
  1401.             if (*pin >= 0)
  1402.             {
  1403.               wpipe_ = pin[WR];
  1404.               ::close(pin[RD]);
  1405.             }
  1406.             if (*pout >= 0)
  1407.             {
  1408.               rpipe_[rsrc_out] = pout[RD];
  1409.               ::close(pout[WR]);
  1410.             }
  1411.             if (*perr >= 0)
  1412.             {
  1413.               rpipe_[rsrc_err] = perr[RD];
  1414.               ::close(perr[WR]);
  1415.             }
  1416.           }
  1417.         }
  1418.       }
  1419.       else
  1420.       {
  1421.         // close any pipes we opened before failure
  1422.         close_fd_array(fd);
  1423.       }
  1424.       return pid;
  1425.     }
  1426.  
  1427.   /**
  1428.    * Closes all pipes and calls wait() to wait for the process to finish.
  1429.    * If an error occurs the error code will be set to one of the possible
  1430.    * errors for @c waitpid().
  1431.    * See your system's documentation for these errors.
  1432.    *
  1433.    * @return  @c this on successful close or @c NULL if there is no
  1434.    *          process to close or if an error occurs.
  1435.    */
  1436.   template <typename C, typename T>
  1437.     basic_pstreambuf<C,T>*
  1438.     basic_pstreambuf<C,T>::close()
  1439.     {
  1440.       const bool running = is_open();
  1441.  
  1442.       sync(); // this might call wait() and reap the child process
  1443.  
  1444.       // rather than trying to work out whether or not we need to clean up
  1445.       // just do it anyway, all cleanup functions are safe to call twice.
  1446.  
  1447.       destroy_buffers(pstdin|pstdout|pstderr);
  1448.  
  1449.       // close pipes before wait() so child gets EOF/SIGPIPE
  1450.       close_fd(wpipe_);
  1451.       close_fd_array(rpipe_);
  1452.  
  1453.       do
  1454.       {
  1455.         error_ = 0;
  1456.       } while (wait() == -1 && error() == EINTR);
  1457.  
  1458.       return running ? this : NULL;
  1459.     }
  1460.  
  1461.   /**
  1462.    *  Called on construction to initialise the arrays used for reading.
  1463.    */
  1464.   template <typename C, typename T>
  1465.     inline void
  1466.     basic_pstreambuf<C,T>::init_rbuffers()
  1467.     {
  1468.       rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
  1469.       rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
  1470.       rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
  1471.     }
  1472.  
  1473.   template <typename C, typename T>
  1474.     void
  1475.     basic_pstreambuf<C,T>::create_buffers(pmode mode)
  1476.     {
  1477.       if (mode & pstdin)
  1478.       {
  1479.         delete[] wbuffer_;
  1480.         wbuffer_ = new char_type[bufsz];
  1481.         this->setp(wbuffer_, wbuffer_ + bufsz);
  1482.       }
  1483.       if (mode & pstdout)
  1484.       {
  1485.         delete[] rbuffer_[rsrc_out];
  1486.         rbuffer_[rsrc_out] = new char_type[bufsz];
  1487.         rsrc_ = rsrc_out;
  1488.         this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
  1489.             rbuffer_[rsrc_out] + pbsz);
  1490.       }
  1491.       if (mode & pstderr)
  1492.       {
  1493.         delete[] rbuffer_[rsrc_err];
  1494.         rbuffer_[rsrc_err] = new char_type[bufsz];
  1495.         if (!(mode & pstdout))
  1496.         {
  1497.           rsrc_ = rsrc_err;
  1498.           this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
  1499.               rbuffer_[rsrc_err] + pbsz);
  1500.         }
  1501.       }
  1502.     }
  1503.  
  1504.   template <typename C, typename T>
  1505.     void
  1506.     basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
  1507.     {
  1508.       if (mode & pstdin)
  1509.       {
  1510.         this->setp(NULL, NULL);
  1511.         delete[] wbuffer_;
  1512.         wbuffer_ = NULL;
  1513.       }
  1514.       if (mode & pstdout)
  1515.       {
  1516.         if (rsrc_ == rsrc_out)
  1517.           this->setg(NULL, NULL, NULL);
  1518.         delete[] rbuffer_[rsrc_out];
  1519.         rbuffer_[rsrc_out] = NULL;
  1520.       }
  1521.       if (mode & pstderr)
  1522.       {
  1523.         if (rsrc_ == rsrc_err)
  1524.           this->setg(NULL, NULL, NULL);
  1525.         delete[] rbuffer_[rsrc_err];
  1526.         rbuffer_[rsrc_err] = NULL;
  1527.       }
  1528.     }
  1529.  
  1530.   template <typename C, typename T>
  1531.     typename basic_pstreambuf<C,T>::buf_read_src
  1532.     basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
  1533.     {
  1534.       if (rsrc_ != src)
  1535.       {
  1536.         char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
  1537.         this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
  1538.         for (std::size_t i = 0; i < 3; ++i)
  1539.           rbufstate_[i] = tmpbufstate[i];
  1540.         rsrc_ = src;
  1541.       }
  1542.       return rsrc_;
  1543.     }
  1544.  
  1545.   /**
  1546.    * Suspends execution and waits for the associated process to exit, or
  1547.    * until a signal is delivered whose action is to terminate the current
  1548.    * process or to call a signal handling function. If the process has
  1549.    * already exited (i.e. it is a "zombie" process) then wait() returns
  1550.    * immediately.  Waiting for the child process causes all its system
  1551.    * resources to be freed.
  1552.    *
  1553.    * error() will return EINTR if wait() is interrupted by a signal.
  1554.    *
  1555.    * @param   nohang  true to return immediately if the process has not exited.
  1556.    * @return  1 if the process has exited and wait() has not yet been called.
  1557.    *          0 if @a nohang is true and the process has not exited yet.
  1558.    *          -1 if no process has been started or if an error occurs,
  1559.    *          in which case the error can be found using error().
  1560.    */
  1561.   template <typename C, typename T>
  1562.     int
  1563.     basic_pstreambuf<C,T>::wait(bool nohang)
  1564.     {
  1565.       int child_exited = -1;
  1566.       if (is_open())
  1567.       {
  1568.         int exit_status;
  1569.         switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0))
  1570.         {
  1571.           case 0 :
  1572.             // nohang was true and process has not exited
  1573.             child_exited = 0;
  1574.             break;
  1575.           case -1 :
  1576.             error_ = errno;
  1577.             break;
  1578.           default :
  1579.             // process has exited
  1580.             ppid_ = 0;
  1581.             status_ = exit_status;
  1582.             child_exited = 1;
  1583.             // Close wpipe, would get SIGPIPE if we used it.
  1584.             destroy_buffers(pstdin);
  1585.             close_fd(wpipe_);
  1586.             // Must free read buffers and pipes on destruction
  1587.             // or next call to open()/close()
  1588.             break;
  1589.         }
  1590.       }
  1591.       return child_exited;
  1592.     }
  1593.  
  1594.   /**
  1595.    * Sends the specified signal to the process.  A signal can be used to
  1596.    * terminate a child process that would not exit otherwise.
  1597.    *
  1598.    * If an error occurs the error code will be set to one of the possible
  1599.    * errors for @c kill().  See your system's documentation for these errors.
  1600.    *
  1601.    * @param   signal  A signal to send to the child process.
  1602.    * @return  @c this or @c NULL if @c kill() fails.
  1603.    */
  1604.   template <typename C, typename T>
  1605.     inline basic_pstreambuf<C,T>*
  1606.     basic_pstreambuf<C,T>::kill(int signal)
  1607.     {
  1608.       basic_pstreambuf<C,T>* ret = NULL;
  1609.       if (is_open())
  1610.       {
  1611.         if (::kill(ppid_, signal))
  1612.           error_ = errno;
  1613.         else
  1614.         {
  1615. #if 0
  1616.           // TODO call exited() to check for exit and clean up? leave to user?
  1617.           if (signal==SIGTERM || signal==SIGKILL)
  1618.             this->exited();
  1619. #endif
  1620.           ret = this;
  1621.         }
  1622.       }
  1623.       return ret;
  1624.     }
  1625.  
  1626.   /**
  1627.    * Sends the specified signal to the process group of the child process.
  1628.    * A signal can be used to terminate a child process that would not exit
  1629.    * otherwise, or to kill the process and its own children.
  1630.    *
  1631.    * If an error occurs the error code will be set to one of the possible
  1632.    * errors for @c getpgid() or @c kill().  See your system's documentation
  1633.    * for these errors. If the child is in the current process group then
  1634.    * NULL will be returned and the error code set to EPERM.
  1635.    *
  1636.    * @param   signal  A signal to send to the child process.
  1637.    * @return  @c this on success or @c NULL on failure.
  1638.    */
  1639.   template <typename C, typename T>
  1640.     inline basic_pstreambuf<C,T>*
  1641.     basic_pstreambuf<C,T>::killpg(int signal)
  1642.     {
  1643.       basic_pstreambuf<C,T>* ret = NULL;
  1644. #ifdef _POSIX_JOB_CONTROL
  1645.       if (is_open())
  1646.       {
  1647.         pid_t pgid = ::getpgid(ppid_);
  1648.         if (pgid == -1)
  1649.           error_ = errno;
  1650.         else if (pgid == ::getpgrp())
  1651.           error_ = EPERM;  // Don't commit suicide
  1652.         else if (::killpg(pgid, signal))
  1653.           error_ = errno;
  1654.         else
  1655.           ret = this;
  1656.       }
  1657. #else
  1658.       error_ = ENOTSUP;
  1659. #endif
  1660.       return ret;
  1661.     }
  1662.  
  1663.   /**
  1664.    *  This function can call pstreambuf::wait() and so may change the
  1665.    *  object's state if the child process has already exited.
  1666.    *
  1667.    *  @return  True if the associated process has exited, false otherwise.
  1668.    *  @see     basic_pstreambuf<C,T>::wait()
  1669.    */
  1670.   template <typename C, typename T>
  1671.     inline bool
  1672.     basic_pstreambuf<C,T>::exited()
  1673.     {
  1674.       return ppid_ == 0 || wait(true)==1;
  1675.     }
  1676.  
  1677.  
  1678.   /**
  1679.    *  @return  The exit status of the child process, or -1 if wait()
  1680.    *           has not yet been called to wait for the child to exit.
  1681.    *  @see     basic_pstreambuf<C,T>::wait()
  1682.    */
  1683.   template <typename C, typename T>
  1684.     inline int
  1685.     basic_pstreambuf<C,T>::status() const
  1686.     {
  1687.       return status_;
  1688.     }
  1689.  
  1690.   /**
  1691.    *  @return  The error code of the most recently failed operation, or zero.
  1692.    */
  1693.   template <typename C, typename T>
  1694.     inline int
  1695.     basic_pstreambuf<C,T>::error() const
  1696.     {
  1697.       return error_;
  1698.     }
  1699.  
  1700.   /**
  1701.    *  Closes the output pipe, causing the child process to receive the
  1702.    *  end-of-file indicator on subsequent reads from its @c stdin stream.
  1703.    */
  1704.   template <typename C, typename T>
  1705.     inline void
  1706.     basic_pstreambuf<C,T>::peof()
  1707.     {
  1708.       sync();
  1709.       destroy_buffers(pstdin);
  1710.       close_fd(wpipe_);
  1711.     }
  1712.  
  1713.   /**
  1714.    * Unlike pstreambuf::exited(), this function will not call wait() and
  1715.    * so will not change the object's state.  This means that once a child
  1716.    * process is executed successfully this function will continue to
  1717.    * return true even after the process exits (until wait() is called.)
  1718.    *
  1719.    * @return  true if a previous call to open() succeeded and wait() has
  1720.    *          not been called and determined that the process has exited,
  1721.    *          false otherwise.
  1722.    */
  1723.   template <typename C, typename T>
  1724.     inline bool
  1725.     basic_pstreambuf<C,T>::is_open() const
  1726.     {
  1727.       return ppid_ > 0;
  1728.     }
  1729.  
  1730.   /**
  1731.    * Toggle the stream used for reading. If @a readerr is @c true then the
  1732.    * process' @c stderr output will be used for subsequent extractions, if
  1733.    * @a readerr is false the the process' stdout will be used.
  1734.    * @param   readerr  @c true to read @c stderr, @c false to read @c stdout.
  1735.    * @return  @c true if the requested stream is open and will be used for
  1736.    *          subsequent extractions, @c false otherwise.
  1737.    */
  1738.   template <typename C, typename T>
  1739.     inline bool
  1740.     basic_pstreambuf<C,T>::read_err(bool readerr)
  1741.     {
  1742.       buf_read_src src = readerr ? rsrc_err : rsrc_out;
  1743.       if (rpipe_[src]>=0)
  1744.       {
  1745.         switch_read_buffer(src);
  1746.         return true;
  1747.       }
  1748.       return false;
  1749.     }
  1750.  
  1751.   /**
  1752.    * Called when the internal character buffer is not present or is full,
  1753.    * to transfer the buffer contents to the pipe.
  1754.    *
  1755.    * @param   c  a character to be written to the pipe.
  1756.    * @return  @c traits_type::eof() if an error occurs, otherwise if @a c
  1757.    *          is not equal to @c traits_type::eof() it will be buffered and
  1758.    *          a value other than @c traits_type::eof() returned to indicate
  1759.    *          success.
  1760.    */
  1761.   template <typename C, typename T>
  1762.     typename basic_pstreambuf<C,T>::int_type
  1763.     basic_pstreambuf<C,T>::overflow(int_type c)
  1764.     {
  1765.       if (!empty_buffer())
  1766.         return traits_type::eof();
  1767.       else if (!traits_type::eq_int_type(c, traits_type::eof()))
  1768.         return this->sputc(c);
  1769.       else
  1770.         return traits_type::not_eof(c);
  1771.     }
  1772.  
  1773.  
  1774.   template <typename C, typename T>
  1775.     int
  1776.     basic_pstreambuf<C,T>::sync()
  1777.     {
  1778.       return !exited() && empty_buffer() ? 0 : -1;
  1779.     }
  1780.  
  1781.   /**
  1782.    * @param   s  character buffer.
  1783.    * @param   n  buffer length.
  1784.    * @return  the number of characters written.
  1785.    */
  1786.   template <typename C, typename T>
  1787.     std::streamsize
  1788.     basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
  1789.     {
  1790.       std::streamsize done = 0;
  1791.       while (done < n)
  1792.       {
  1793.         if (std::streamsize nbuf = this->epptr() - this->pptr())
  1794.         {
  1795.           nbuf = std::min(nbuf, n - done);
  1796.           traits_type::copy(this->pptr(), s + done, nbuf);
  1797.           this->pbump(nbuf);
  1798.           done += nbuf;
  1799.         }
  1800.         else if (!empty_buffer())
  1801.           break;
  1802.       }
  1803.       return done;
  1804.     }
  1805.  
  1806.   /**
  1807.    * @return  true if the buffer was emptied, false otherwise.
  1808.    */
  1809.   template <typename C, typename T>
  1810.     bool
  1811.     basic_pstreambuf<C,T>::empty_buffer()
  1812.     {
  1813.       const std::streamsize count = this->pptr() - this->pbase();
  1814.       if (count > 0)
  1815.       {
  1816.         const std::streamsize written = this->write(this->wbuffer_, count);
  1817.         if (written > 0)
  1818.         {
  1819.           if (const std::streamsize unwritten = count - written)
  1820.             traits_type::move(this->pbase(), this->pbase()+written, unwritten);
  1821.           this->pbump(-written);
  1822.           return true;
  1823.         }
  1824.       }
  1825.       return false;
  1826.     }
  1827.  
  1828.   /**
  1829.    * Called when the internal character buffer is is empty, to re-fill it
  1830.    * from the pipe.
  1831.    *
  1832.    * @return The first available character in the buffer,
  1833.    * or @c traits_type::eof() in case of failure.
  1834.    */
  1835.   template <typename C, typename T>
  1836.     typename basic_pstreambuf<C,T>::int_type
  1837.     basic_pstreambuf<C,T>::underflow()
  1838.     {
  1839.       if (this->gptr() < this->egptr() || fill_buffer())
  1840.         return traits_type::to_int_type(*this->gptr());
  1841.       else
  1842.         return traits_type::eof();
  1843.     }
  1844.  
  1845.   /**
  1846.    * Attempts to make @a c available as the next character to be read by
  1847.    * @c sgetc().
  1848.    *
  1849.    * @param   c   a character to make available for extraction.
  1850.    * @return  @a c if the character can be made available,
  1851.    *          @c traits_type::eof() otherwise.
  1852.    */
  1853.   template <typename C, typename T>
  1854.     typename basic_pstreambuf<C,T>::int_type
  1855.     basic_pstreambuf<C,T>::pbackfail(int_type c)
  1856.     {
  1857.       if (this->gptr() != this->eback())
  1858.       {
  1859.         this->gbump(-1);
  1860.         if (!traits_type::eq_int_type(c, traits_type::eof()))
  1861.           *this->gptr() = traits_type::to_char_type(c);
  1862.         return traits_type::not_eof(c);
  1863.       }
  1864.       else
  1865.          return traits_type::eof();
  1866.     }
  1867.  
  1868.   template <typename C, typename T>
  1869.     std::streamsize
  1870.     basic_pstreambuf<C,T>::showmanyc()
  1871.     {
  1872.       int avail = 0;
  1873.       if (sizeof(char_type) == 1)
  1874.         avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
  1875. #ifdef FIONREAD
  1876.       else
  1877.       {
  1878.         if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
  1879.           avail = -1;
  1880.         else if (avail)
  1881.           avail /= sizeof(char_type);
  1882.       }
  1883. #endif
  1884.       return std::streamsize(avail);
  1885.     }
  1886.  
  1887.   /**
  1888.    * @return  true if the buffer was filled, false otherwise.
  1889.    */
  1890.   template <typename C, typename T>
  1891.     bool
  1892.     basic_pstreambuf<C,T>::fill_buffer(bool non_blocking)
  1893.     {
  1894.       const std::streamsize pb1 = this->gptr() - this->eback();
  1895.       const std::streamsize pb2 = pbsz;
  1896.       const std::streamsize npb = std::min(pb1, pb2);
  1897.  
  1898.       char_type* const rbuf = rbuffer();
  1899.  
  1900.       if (npb)
  1901.         traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
  1902.  
  1903.       std::streamsize rc = -1;
  1904.  
  1905.       if (non_blocking)
  1906.       {
  1907.         const int flags = ::fcntl(rpipe(), F_GETFL);
  1908.         if (flags != -1)
  1909.         {
  1910.           const bool blocking = !(flags & O_NONBLOCK);
  1911.           if (blocking)
  1912.             ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK);  // set non-blocking
  1913.  
  1914.           error_ = 0;
  1915.           rc = read(rbuf + pbsz, bufsz - pbsz);
  1916.  
  1917.           if (rc == -1 && error_ == EAGAIN)  // nothing available
  1918.             rc = 0;
  1919.           else if (rc == 0)  // EOF
  1920.             rc = -1;
  1921.  
  1922.           if (blocking)
  1923.             ::fcntl(rpipe(), F_SETFL, flags); // restore
  1924.         }
  1925.       }
  1926.       else
  1927.         rc = read(rbuf + pbsz, bufsz - pbsz);
  1928.  
  1929.       if (rc > 0 || (rc == 0 && non_blocking))
  1930.       {
  1931.         this->setg( rbuf + pbsz - npb,
  1932.                     rbuf + pbsz,
  1933.                     rbuf + pbsz + rc );
  1934.         return true;
  1935.       }
  1936.       else
  1937.       {
  1938.         this->setg(NULL, NULL, NULL);
  1939.         return false;
  1940.       }
  1941.     }
  1942.  
  1943.   /**
  1944.    * Writes up to @a n characters to the pipe from the buffer @a s.
  1945.    *
  1946.    * @param   s  character buffer.
  1947.    * @param   n  buffer length.
  1948.    * @return  the number of characters written.
  1949.    */
  1950.   template <typename C, typename T>
  1951.     inline std::streamsize
  1952.     basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
  1953.     {
  1954.       std::streamsize nwritten = 0;
  1955.       if (wpipe() >= 0)
  1956.       {
  1957.         nwritten = ::write(wpipe(), s, n * sizeof(char_type));
  1958.         if (nwritten == -1)
  1959.           error_ = errno;
  1960.         else
  1961.           nwritten /= sizeof(char_type);
  1962.       }
  1963.       return nwritten;
  1964.     }
  1965.  
  1966.   /**
  1967.    * Reads up to @a n characters from the pipe to the buffer @a s.
  1968.    *
  1969.    * @param   s  character buffer.
  1970.    * @param   n  buffer length.
  1971.    * @return  the number of characters read.
  1972.    */
  1973.   template <typename C, typename T>
  1974.     inline std::streamsize
  1975.     basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
  1976.     {
  1977.       std::streamsize nread = 0;
  1978.       if (rpipe() >= 0)
  1979.       {
  1980.         nread = ::read(rpipe(), s, n * sizeof(char_type));
  1981.         if (nread == -1)
  1982.           error_ = errno;
  1983.         else
  1984.           nread /= sizeof(char_type);
  1985.       }
  1986.       return nread;
  1987.     }
  1988.  
  1989.   /** @return a reference to the output file descriptor */
  1990.   template <typename C, typename T>
  1991.     inline pstreams::fd_type&
  1992.     basic_pstreambuf<C,T>::wpipe()
  1993.     {
  1994.       return wpipe_;
  1995.     }
  1996.  
  1997.   /** @return a reference to the active input file descriptor */
  1998.   template <typename C, typename T>
  1999.     inline pstreams::fd_type&
  2000.     basic_pstreambuf<C,T>::rpipe()
  2001.     {
  2002.       return rpipe_[rsrc_];
  2003.     }
  2004.  
  2005.   /** @return a reference to the specified input file descriptor */
  2006.   template <typename C, typename T>
  2007.     inline pstreams::fd_type&
  2008.     basic_pstreambuf<C,T>::rpipe(buf_read_src which)
  2009.     {
  2010.       return rpipe_[which];
  2011.     }
  2012.  
  2013.   /** @return a pointer to the start of the active input buffer area. */
  2014.   template <typename C, typename T>
  2015.     inline typename basic_pstreambuf<C,T>::char_type*
  2016.     basic_pstreambuf<C,T>::rbuffer()
  2017.     {
  2018.       return rbuffer_[rsrc_];
  2019.     }
  2020.  
  2021.  
  2022.   /*
  2023.    * member definitions for pstream_common
  2024.    */
  2025.  
  2026.   /**
  2027.    * @class pstream_common
  2028.    * Abstract Base Class providing common functionality for basic_ipstream,
  2029.    * basic_opstream and basic_pstream.
  2030.    * pstream_common manages the basic_pstreambuf stream buffer that is used
  2031.    * by the derived classes to initialise an iostream class.
  2032.    */
  2033.  
  2034.   /** Creates an uninitialised stream. */
  2035.   template <typename C, typename T>
  2036.     inline
  2037.     pstream_common<C,T>::pstream_common()
  2038.     : std::basic_ios<C,T>(NULL)
  2039.     , command_()
  2040.     , buf_()
  2041.     {
  2042.       this->std::basic_ios<C,T>::rdbuf(&buf_);
  2043.     }
  2044.  
  2045.   /**
  2046.    * Initialises the stream buffer by calling
  2047.    * do_open( @a command , @a mode )
  2048.    *
  2049.    * @param cmd   a string containing a shell command.
  2050.    * @param mode  the I/O mode to use when opening the pipe.
  2051.    * @see   do_open(const std::string&, pmode)
  2052.    */
  2053.   template <typename C, typename T>
  2054.     inline
  2055.     pstream_common<C,T>::pstream_common(const std::string& cmd, pmode mode)
  2056.     : std::basic_ios<C,T>(NULL)
  2057.     , command_(cmd)
  2058.     , buf_()
  2059.     {
  2060.       this->std::basic_ios<C,T>::rdbuf(&buf_);
  2061.       do_open(cmd, mode);
  2062.     }
  2063.  
  2064.   /**
  2065.    * Initialises the stream buffer by calling
  2066.    * do_open( @a file , @a argv , @a mode )
  2067.    *
  2068.    * @param file  a string containing the pathname of a program to execute.
  2069.    * @param argv  a vector of argument strings passed to the new program.
  2070.    * @param mode  the I/O mode to use when opening the pipe.
  2071.    * @see do_open(const std::string&, const argv_type&, pmode)
  2072.    */
  2073.   template <typename C, typename T>
  2074.     inline
  2075.     pstream_common<C,T>::pstream_common( const std::string& file,
  2076.                                          const argv_type& argv,
  2077.                                          pmode mode )
  2078.     : std::basic_ios<C,T>(NULL)
  2079.     , command_(file)
  2080.     , buf_()
  2081.     {
  2082.       this->std::basic_ios<C,T>::rdbuf(&buf_);
  2083.       do_open(file, argv, mode);
  2084.     }
  2085.  
  2086.   /**
  2087.    * This is a pure virtual function to make @c pstream_common abstract.
  2088.    * Because it is the destructor it will be called by derived classes
  2089.    * and so must be defined.  It is also protected, to discourage use of
  2090.    * the PStreams classes through pointers or references to the base class.
  2091.    *
  2092.    * @sa If defining a pure virtual seems odd you should read
  2093.    * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!)
  2094.    */
  2095.   template <typename C, typename T>
  2096.     inline
  2097.     pstream_common<C,T>::~pstream_common()
  2098.     {
  2099.     }
  2100.  
  2101.   /**
  2102.    * Calls rdbuf()->open( @a command , @a mode )
  2103.    * and sets @c failbit on error.
  2104.    *
  2105.    * @param cmd   a string containing a shell command.
  2106.    * @param mode  the I/O mode to use when opening the pipe.
  2107.    * @see   basic_pstreambuf::open(const std::string&, pmode)
  2108.    */
  2109.   template <typename C, typename T>
  2110.     inline void
  2111.     pstream_common<C,T>::do_open(const std::string& cmd, pmode mode)
  2112.     {
  2113.       if (!buf_.open((command_=cmd), mode))
  2114.         this->setstate(std::ios_base::failbit);
  2115.     }
  2116.  
  2117.   /**
  2118.    * Calls rdbuf()->open( @a file, @a  argv, @a mode )
  2119.    * and sets @c failbit on error.
  2120.    *
  2121.    * @param file  a string containing the pathname of a program to execute.
  2122.    * @param argv  a vector of argument strings passed to the new program.
  2123.    * @param mode  the I/O mode to use when opening the pipe.
  2124.    * @see   basic_pstreambuf::open(const std::string&, const argv_type&, pmode)
  2125.    */
  2126.   template <typename C, typename T>
  2127.     inline void
  2128.     pstream_common<C,T>::do_open( const std::string& file,
  2129.                                   const argv_type& argv,
  2130.                                   pmode mode )
  2131.     {
  2132.       if (!buf_.open((command_=file), argv, mode))
  2133.         this->setstate(std::ios_base::failbit);
  2134.     }
  2135.  
  2136.   /** Calls rdbuf->close() and sets @c failbit on error. */
  2137.   template <typename C, typename T>
  2138.     inline void
  2139.     pstream_common<C,T>::close()
  2140.     {
  2141.       if (!buf_.close())
  2142.         this->setstate(std::ios_base::failbit);
  2143.     }
  2144.  
  2145.   /**
  2146.    * @return  rdbuf()->is_open().
  2147.    * @see     basic_pstreambuf::is_open()
  2148.    */
  2149.   template <typename C, typename T>
  2150.     inline bool
  2151.     pstream_common<C,T>::is_open() const
  2152.     {
  2153.       return buf_.is_open();
  2154.     }
  2155.  
  2156.   /** @return a string containing the command used to initialise the stream. */
  2157.   template <typename C, typename T>
  2158.     inline const std::string&
  2159.     pstream_common<C,T>::command() const
  2160.     {
  2161.       return command_;
  2162.     }
  2163.  
  2164.   /** @return a pointer to the private stream buffer member. */
  2165.   // TODO  document behaviour if buffer replaced.
  2166.   template <typename C, typename T>
  2167.     inline typename pstream_common<C,T>::streambuf_type*
  2168.     pstream_common<C,T>::rdbuf() const
  2169.     {
  2170.       return const_cast<streambuf_type*>(&buf_);
  2171.     }
  2172.  
  2173.  
  2174. #if REDI_EVISCERATE_PSTREAMS
  2175.   /**
  2176.    * @def REDI_EVISCERATE_PSTREAMS
  2177.    * If this macro has a non-zero value then certain internals of the
  2178.    * @c basic_pstreambuf template class are exposed. In general this is
  2179.    * a Bad Thing, as the internal implementation is largely undocumented
  2180.    * and may be subject to change at any time, so this feature is only
  2181.    * provided because it might make PStreams useful in situations where
  2182.    * it is necessary to do Bad Things.
  2183.    */
  2184.  
  2185.   /**
  2186.    * @warning  This function exposes the internals of the stream buffer and
  2187.    *           should be used with caution. It is the caller's responsibility
  2188.    *           to flush streams etc. in order to clear any buffered data.
  2189.    *           The POSIX.1 function <b>fdopen</b>(3) is used to obtain the
  2190.    *           @c FILE pointers from the streambuf's private file descriptor
  2191.    *           members so consult your system's documentation for
  2192.    *           <b>fdopen</b>(3).
  2193.    *
  2194.    * @param   in    A FILE* that will refer to the process' stdin.
  2195.    * @param   out   A FILE* that will refer to the process' stdout.
  2196.    * @param   err   A FILE* that will refer to the process' stderr.
  2197.    * @return  An OR of zero or more of @c pstdin, @c pstdout, @c pstderr.
  2198.    *
  2199.    * For each open stream shared with the child process a @c FILE* is
  2200.    * obtained and assigned to the corresponding parameter. For closed
  2201.    * streams @c NULL is assigned to the parameter.
  2202.    * The return value can be tested to see which parameters should be
  2203.    * @c !NULL by masking with the corresponding @c pmode value.
  2204.    *
  2205.    * @see <b>fdopen</b>(3)
  2206.    */
  2207.   template <typename C, typename T>
  2208.     std::size_t
  2209.     basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
  2210.     {
  2211.       in = out = err = NULL;
  2212.       std::size_t open_files = 0;
  2213.       if (wpipe() > -1)
  2214.       {
  2215.         if ((in = ::fdopen(wpipe(), "w")))
  2216.         {
  2217.             open_files |= pstdin;
  2218.         }
  2219.       }
  2220.       if (rpipe(rsrc_out) > -1)
  2221.       {
  2222.         if ((out = ::fdopen(rpipe(rsrc_out), "r")))
  2223.         {
  2224.             open_files |= pstdout;
  2225.         }
  2226.       }
  2227.       if (rpipe(rsrc_err) > -1)
  2228.       {
  2229.         if ((err = ::fdopen(rpipe(rsrc_err), "r")))
  2230.         {
  2231.             open_files |= pstderr;
  2232.         }
  2233.       }
  2234.       return open_files;
  2235.     }
  2236.  
  2237.   /**
  2238.    *  @warning This function exposes the internals of the stream buffer and
  2239.    *  should be used with caution.
  2240.    *
  2241.    *  @param  in   A FILE* that will refer to the process' stdin.
  2242.    *  @param  out  A FILE* that will refer to the process' stdout.
  2243.    *  @param  err  A FILE* that will refer to the process' stderr.
  2244.    *  @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr.
  2245.    *  @see    basic_pstreambuf::fopen()
  2246.    */
  2247.   template <typename C, typename T>
  2248.     inline std::size_t
  2249.     pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
  2250.     {
  2251.       return buf_.fopen(fin, fout, ferr);
  2252.     }
  2253.  
  2254. #endif // REDI_EVISCERATE_PSTREAMS
  2255.  
  2256.  
  2257. } // namespace redi
  2258.  
  2259. #endif  // REDI_PSTREAM_H_SEEN
  2260. // vim: ts=2 sw=2 expandtab
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement