source: trunk/GDE/SINA/builddir/include/pstream.h

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