PStreams
pstream.h
Go to the documentation of this file.
1 /* $Id: pstream.h,v 1.112 2010/03/20 14:50:47 redi Exp $
2 PStreams - POSIX Process I/O for C++
3 Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008 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 
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
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 
58 #define PSTREAMS_VERSION 0x0070 // 0.7.0
59 
73 namespace redi
74 {
76  struct pstreams
77  {
79  typedef std::ios_base::openmode pmode;
80 
82  typedef std::vector<std::string> argv_type;
83 
85  typedef int fd_type;
86 
87  static const pmode pstdin = std::ios_base::out;
88  static const pmode pstdout = std::ios_base::in;
89  static const pmode pstderr = std::ios_base::app;
90 
91  protected:
92  enum { bufsz = 32 };
93  enum { pbsz = 2 };
94  };
95 
97  template <typename CharT, typename Traits = std::char_traits<CharT> >
99  : public std::basic_streambuf<CharT, Traits>
100  , public pstreams
101  {
102  public:
103  // Type definitions for dependent types
104  typedef CharT char_type;
105  typedef Traits traits_type;
106  typedef typename traits_type::int_type int_type;
107  typedef typename traits_type::off_type off_type;
108  typedef typename traits_type::pos_type pos_type;
110  typedef fd_type fd_t;
111 
114 
116  basic_pstreambuf(const std::string& command, pmode mode);
117 
119  basic_pstreambuf( const std::string& file,
120  const argv_type& argv,
121  pmode mode );
122 
125 
128  open(const std::string& command, pmode mode);
129 
132  open(const std::string& file, const argv_type& argv, pmode mode);
133 
136  close();
137 
140  kill(int signal = SIGTERM);
141 
143  void
144  peof();
145 
147  bool
148  read_err(bool readerr = true);
149 
151  bool
152  is_open() const;
153 
155  bool
156  exited();
157 
158 #if REDI_EVISCERATE_PSTREAMS
159  std::size_t
161  fopen(FILE*& in, FILE*& out, FILE*& err);
162 #endif
163 
165  int
166  status() const;
167 
169  int
170  error() const;
171 
172  protected:
174  int_type
175  overflow(int_type c);
176 
178  int_type
179  underflow();
180 
182  int_type
183  pbackfail(int_type c = traits_type::eof());
184 
186  int
187  sync();
188 
190  std::streamsize
191  xsputn(const char_type* s, std::streamsize n);
192 
194  std::streamsize
195  write(const char_type* s, std::streamsize n);
196 
198  std::streamsize
199  read(char_type* s, std::streamsize n);
200 
202  std::streamsize
203  showmanyc();
204 
205  protected:
207  enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
208 
210  pid_t
211  fork(pmode mode);
212 
214  int
215  wait(bool nohang = false);
216 
218  fd_type&
219  wpipe();
220 
222  fd_type&
223  rpipe();
224 
226  fd_type&
227  rpipe(buf_read_src which);
228 
229  void
230  create_buffers(pmode mode);
231 
232  void
233  destroy_buffers(pmode mode);
234 
236  bool
237  empty_buffer();
238 
239  bool
240  fill_buffer(bool non_blocking = false);
241 
243  char_type*
244  rbuffer();
245 
247  switch_read_buffer(buf_read_src);
248 
249  private:
251  basic_pstreambuf& operator=(const basic_pstreambuf&);
252 
253  void
254  init_rbuffers();
255 
256  pid_t ppid_; // pid of process
257  fd_type wpipe_; // pipe used to write to process' stdin
258  fd_type rpipe_[2]; // two pipes to read from, stdout and stderr
259  char_type* wbuffer_;
260  char_type* rbuffer_[2];
261  char_type* rbufstate_[3];
263  buf_read_src rsrc_;
264  int status_; // hold exit status of child process
265  int error_; // hold errno if fork() or exec() fails
266  };
267 
269  template <typename CharT, typename Traits = std::char_traits<CharT> >
271  : virtual public std::basic_ios<CharT, Traits>
272  , virtual public pstreams
273  {
274  protected:
276 
277  typedef pstreams::pmode pmode;
279 
281  pstream_common();
282 
284  pstream_common(const std::string& command, pmode mode);
285 
287  pstream_common(const std::string& file, const argv_type& argv, pmode mode);
288 
290  virtual
291  ~pstream_common() = 0;
292 
294  void
295  do_open(const std::string& command, pmode mode);
296 
298  void
299  do_open(const std::string& file, const argv_type& argv, pmode mode);
300 
301  public:
303  void
304  close();
305 
307  bool
308  is_open() const;
309 
311  const std::string&
312  command() const;
313 
316  rdbuf() const;
317 
318 #if REDI_EVISCERATE_PSTREAMS
319  std::size_t
321  fopen(FILE*& in, FILE*& out, FILE*& err);
322 #endif
323 
324  protected:
325  std::string command_;
327  };
328 
329 
340  template <typename CharT, typename Traits = std::char_traits<CharT> >
342  : public std::basic_istream<CharT, Traits>
343  , public pstream_common<CharT, Traits>
344  , virtual public pstreams
345  {
346  typedef std::basic_istream<CharT, Traits> istream_type;
348 
349  using pbase_type::buf_; // declare name in this scope
350 
351  pmode readable(pmode mode)
352  {
353  if (!(mode & (pstdout|pstderr)))
354  mode |= pstdout;
355  return mode;
356  }
357 
358  public:
360  typedef typename pbase_type::pmode pmode;
361 
363  typedef typename pbase_type::argv_type argv_type;
364 
367  : istream_type(NULL), pbase_type()
368  { }
369 
380  basic_ipstream(const std::string& command, pmode mode = pstdout)
381  : istream_type(NULL), pbase_type(command, readable(mode))
382  { }
383 
395  basic_ipstream( const std::string& file,
396  const argv_type& argv,
397  pmode mode = pstdout )
398  : istream_type(NULL), pbase_type(file, argv, readable(mode))
399  { }
400 
407  { }
408 
418  void
419  open(const std::string& command, pmode mode = pstdout)
420  {
421  this->do_open(command, readable(mode));
422  }
423 
434  void
435  open( const std::string& file,
436  const argv_type& argv,
437  pmode mode = pstdout )
438  {
439  this->do_open(file, argv, readable(mode));
440  }
441 
447  out()
448  {
449  this->buf_.read_err(false);
450  return *this;
451  }
452 
458  err()
459  {
460  this->buf_.read_err(true);
461  return *this;
462  }
463  };
464 
465 
475  template <typename CharT, typename Traits = std::char_traits<CharT> >
477  : public std::basic_ostream<CharT, Traits>
478  , public pstream_common<CharT, Traits>
479  , virtual public pstreams
480  {
481  typedef std::basic_ostream<CharT, Traits> ostream_type;
483 
484  using pbase_type::buf_; // declare name in this scope
485 
486  public:
488  typedef typename pbase_type::pmode pmode;
489 
491  typedef typename pbase_type::argv_type argv_type;
492 
495  : ostream_type(NULL), pbase_type()
496  { }
497 
508  basic_opstream(const std::string& command, pmode mode = pstdin)
509  : ostream_type(NULL), pbase_type(command, mode|pstdin)
510  { }
511 
523  basic_opstream( const std::string& file,
524  const argv_type& argv,
525  pmode mode = pstdin )
526  : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
527  { }
528 
535 
545  void
546  open(const std::string& command, pmode mode = pstdin)
547  {
548  this->do_open(command, mode|pstdin);
549  }
550 
561  void
562  open( const std::string& file,
563  const argv_type& argv,
564  pmode mode = pstdin)
565  {
566  this->do_open(file, argv, mode|pstdin);
567  }
568  };
569 
570 
584  template <typename CharT, typename Traits = std::char_traits<CharT> >
586  : public std::basic_iostream<CharT, Traits>
587  , public pstream_common<CharT, Traits>
588  , virtual public pstreams
589  {
590  typedef std::basic_iostream<CharT, Traits> iostream_type;
592 
593  using pbase_type::buf_; // declare name in this scope
594 
595  public:
597  typedef typename pbase_type::pmode pmode;
598 
600  typedef typename pbase_type::argv_type argv_type;
601 
604  : iostream_type(NULL), pbase_type()
605  { }
606 
617  basic_pstream(const std::string& command, pmode mode = pstdout|pstdin)
618  : iostream_type(NULL), pbase_type(command, mode)
619  { }
620 
632  basic_pstream( const std::string& file,
633  const argv_type& argv,
634  pmode mode = pstdout|pstdin )
635  : iostream_type(NULL), pbase_type(file, argv, mode)
636  { }
637 
644 
654  void
655  open(const std::string& command, pmode mode = pstdout|pstdin)
656  {
657  this->do_open(command, mode);
658  }
659 
670  void
671  open( const std::string& file,
672  const argv_type& argv,
673  pmode mode = pstdout|pstdin )
674  {
675  this->do_open(file, argv, mode);
676  }
677 
683  out()
684  {
685  this->buf_.read_err(false);
686  return *this;
687  }
688 
694  err()
695  {
696  this->buf_.read_err(true);
697  return *this;
698  }
699  };
700 
701 
723  template <typename CharT, typename Traits = std::char_traits<CharT> >
725  : public std::basic_ostream<CharT, Traits>
726  , private std::basic_istream<CharT, Traits>
727  , private pstream_common<CharT, Traits>
728  , virtual public pstreams
729  {
730  typedef std::basic_ostream<CharT, Traits> ostream_type;
731  typedef std::basic_istream<CharT, Traits> istream_type;
733 
734  using pbase_type::buf_; // declare name in this scope
735 
736  public:
738  typedef typename pbase_type::pmode pmode;
739 
741  typedef typename pbase_type::argv_type argv_type;
742 
745  : ostream_type(NULL), istream_type(NULL), pbase_type()
746  { }
747 
758  basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
759  : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
760  { }
761 
773  basic_rpstream( const std::string& file,
774  const argv_type& argv,
775  pmode mode = pstdout|pstdin )
776  : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
777  { }
778 
781 
791  void
792  open(const std::string& command, pmode mode = pstdout|pstdin)
793  {
794  this->do_open(command, mode);
795  }
796 
807  void
808  open( const std::string& file,
809  const argv_type& argv,
810  pmode mode = pstdout|pstdin )
811  {
812  this->do_open(file, argv, mode);
813  }
814 
820  istream_type&
821  out()
822  {
823  this->buf_.read_err(false);
824  return *this;
825  }
826 
832  istream_type&
833  err()
834  {
835  this->buf_.read_err(true);
836  return *this;
837  }
838  };
839 
840 
851 
852 
865  template <typename C, typename T>
866  inline std::basic_ostream<C,T>&
867  peof(std::basic_ostream<C,T>& s)
868  {
870  if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
871  p->peof();
872  return s;
873  }
874 
875 
876  /*
877  * member definitions for pstreambuf
878  */
879 
880 
887  template <typename C, typename T>
888  inline
890  : ppid_(-1) // initialise to -1 to indicate no process run yet.
891  , wpipe_(-1)
892  , wbuffer_(NULL)
893  , rsrc_(rsrc_out)
894  , status_(-1)
895  , error_(0)
896  {
897  init_rbuffers();
898  }
899 
908  template <typename C, typename T>
909  inline
910  basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
911  : ppid_(-1) // initialise to -1 to indicate no process run yet.
912  , wpipe_(-1)
913  , wbuffer_(NULL)
914  , rsrc_(rsrc_out)
915  , status_(-1)
916  , error_(0)
917  {
918  init_rbuffers();
919  open(command, mode);
920  }
921 
931  template <typename C, typename T>
932  inline
933  basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
934  const argv_type& argv,
935  pmode mode )
936  : ppid_(-1) // initialise to -1 to indicate no process run yet.
937  , wpipe_(-1)
938  , wbuffer_(NULL)
939  , rsrc_(rsrc_out)
940  , status_(-1)
941  , error_(0)
942  {
943  init_rbuffers();
944  open(file, argv, mode);
945  }
946 
951  template <typename C, typename T>
952  inline
954  {
955  close();
956  }
957 
985  template <typename C, typename T>
987  basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
988  {
989  const char * shell_path = "/bin/sh";
990 #if 0
991  const std::string argv[] = { "sh", "-c", command };
992  return this->open(shell_path, argv_type(argv, argv+3), mode);
993 #else
994  basic_pstreambuf<C,T>* ret = NULL;
995 
996  if (!is_open())
997  {
998  switch(fork(mode))
999  {
1000  case 0 :
1001  // this is the new process, exec command
1002  ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
1003 
1004  // can only reach this point if exec() failed
1005 
1006  // parent can get exit code from waitpid()
1007  ::_exit(errno);
1008  // using std::exit() would make static dtors run twice
1009 
1010  case -1 :
1011  // couldn't fork, error already handled in pstreambuf::fork()
1012  break;
1013 
1014  default :
1015  // this is the parent process
1016  // activate buffers
1017  create_buffers(mode);
1018  ret = this;
1019  }
1020  }
1021  return ret;
1022 #endif
1023  }
1024 
1033  inline void
1035  {
1036  if (fd >= 0 && ::close(fd) == 0)
1037  fd = -1;
1038  }
1039 
1050  template <int N>
1051  inline void
1053  {
1054  for (std::size_t i = 0; i < N; ++i)
1055  close_fd(fds[i]);
1056  }
1057 
1087  template <typename C, typename T>
1089  basic_pstreambuf<C,T>::open( const std::string& file,
1090  const argv_type& argv,
1091  pmode mode )
1092  {
1093  basic_pstreambuf<C,T>* ret = NULL;
1094 
1095  if (!is_open())
1096  {
1097  // constants for read/write ends of pipe
1098  enum { RD, WR };
1099 
1100  // open another pipe and set close-on-exec
1101  fd_type ck_exec[] = { -1, -1 };
1102  if (-1 == ::pipe(ck_exec)
1103  || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
1104  || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
1105  {
1106  error_ = errno;
1107  close_fd_array(ck_exec);
1108  }
1109  else
1110  {
1111  switch(fork(mode))
1112  {
1113  case 0 :
1114  // this is the new process, exec command
1115  {
1116  char** arg_v = new char*[argv.size()+1];
1117  for (std::size_t i = 0; i < argv.size(); ++i)
1118  {
1119  const std::string& src = argv[i];
1120  char*& dest = arg_v[i];
1121  dest = new char[src.size()+1];
1122  dest[ src.copy(dest, src.size()) ] = '\0';
1123  }
1124  arg_v[argv.size()] = NULL;
1125 
1126  ::execvp(file.c_str(), arg_v);
1127 
1128  // can only reach this point if exec() failed
1129 
1130  // parent can get error code from ck_exec pipe
1131  error_ = errno;
1132 
1133  ::write(ck_exec[WR], &error_, sizeof(error_));
1134  ::close(ck_exec[WR]);
1135  ::close(ck_exec[RD]);
1136 
1137  ::_exit(error_);
1138  // using std::exit() would make static dtors run twice
1139  }
1140 
1141  case -1 :
1142  // couldn't fork, error already handled in pstreambuf::fork()
1143  close_fd_array(ck_exec);
1144  break;
1145 
1146  default :
1147  // this is the parent process
1148 
1149  // check child called exec() successfully
1150  ::close(ck_exec[WR]);
1151  switch (::read(ck_exec[RD], &error_, sizeof(error_)))
1152  {
1153  case 0:
1154  // activate buffers
1155  create_buffers(mode);
1156  ret = this;
1157  break;
1158  case -1:
1159  error_ = errno;
1160  break;
1161  default:
1162  // error_ contains error code from child
1163  // call wait() to clean up and set ppid_ to 0
1164  this->wait();
1165  break;
1166  }
1167  ::close(ck_exec[RD]);
1168  }
1169  }
1170  }
1171  return ret;
1172  }
1173 
1190  template <typename C, typename T>
1191  pid_t
1193  {
1194  pid_t pid = -1;
1195 
1196  // Three pairs of file descriptors, for pipes connected to the
1197  // process' stdin, stdout and stderr
1198  // (stored in a single array so close_fd_array() can close all at once)
1199  fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
1200  fd_type* const pin = fd;
1201  fd_type* const pout = fd+2;
1202  fd_type* const perr = fd+4;
1203 
1204  // constants for read/write ends of pipe
1205  enum { RD, WR };
1206 
1207  // N.B.
1208  // For the pstreambuf pin is an output stream and
1209  // pout and perr are input streams.
1210 
1211  if (!error_ && mode&pstdin && ::pipe(pin))
1212  error_ = errno;
1213 
1214  if (!error_ && mode&pstdout && ::pipe(pout))
1215  error_ = errno;
1216 
1217  if (!error_ && mode&pstderr && ::pipe(perr))
1218  error_ = errno;
1219 
1220  if (!error_)
1221  {
1222  pid = ::fork();
1223  switch (pid)
1224  {
1225  case 0 :
1226  {
1227  // this is the new process
1228 
1229  // for each open pipe close one end and redirect the
1230  // respective standard stream to the other end
1231 
1232  if (*pin >= 0)
1233  {
1234  ::close(pin[WR]);
1235  ::dup2(pin[RD], STDIN_FILENO);
1236  ::close(pin[RD]);
1237  }
1238  if (*pout >= 0)
1239  {
1240  ::close(pout[RD]);
1241  ::dup2(pout[WR], STDOUT_FILENO);
1242  ::close(pout[WR]);
1243  }
1244  if (*perr >= 0)
1245  {
1246  ::close(perr[RD]);
1247  ::dup2(perr[WR], STDERR_FILENO);
1248  ::close(perr[WR]);
1249  }
1250  break;
1251  }
1252  case -1 :
1253  {
1254  // couldn't fork for some reason
1255  error_ = errno;
1256  // close any open pipes
1257  close_fd_array(fd);
1258  break;
1259  }
1260  default :
1261  {
1262  // this is the parent process, store process' pid
1263  ppid_ = pid;
1264 
1265  // store one end of open pipes and close other end
1266  if (*pin >= 0)
1267  {
1268  wpipe_ = pin[WR];
1269  ::close(pin[RD]);
1270  }
1271  if (*pout >= 0)
1272  {
1273  rpipe_[rsrc_out] = pout[RD];
1274  ::close(pout[WR]);
1275  }
1276  if (*perr >= 0)
1277  {
1278  rpipe_[rsrc_err] = perr[RD];
1279  ::close(perr[WR]);
1280  }
1281  }
1282  }
1283  }
1284  else
1285  {
1286  // close any pipes we opened before failure
1287  close_fd_array(fd);
1288  }
1289  return pid;
1290  }
1291 
1301  template <typename C, typename T>
1304  {
1305  const bool running = is_open();
1306 
1307  sync(); // this might call wait() and reap the child process
1308 
1309  // rather than trying to work out whether or not we need to clean up
1310  // just do it anyway, all cleanup functions are safe to call twice.
1311 
1312  destroy_buffers(pstdin|pstdout|pstderr);
1313 
1314  // close pipes before wait() so child gets EOF/SIGPIPE
1315  close_fd(wpipe_);
1316  close_fd_array(rpipe_);
1317 
1318  do
1319  {
1320  error_ = 0;
1321  } while (wait() == -1 && error() == EINTR);
1322 
1323  return running ? this : NULL;
1324  }
1325 
1329  template <typename C, typename T>
1330  inline void
1332  {
1333  rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1334  rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
1335  rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
1336  }
1337 
1338  template <typename C, typename T>
1339  void
1340  basic_pstreambuf<C,T>::create_buffers(pmode mode)
1341  {
1342  if (mode & pstdin)
1343  {
1344  delete[] wbuffer_;
1345  wbuffer_ = new char_type[bufsz];
1346  this->setp(wbuffer_, wbuffer_ + bufsz);
1347  }
1348  if (mode & pstdout)
1349  {
1350  delete[] rbuffer_[rsrc_out];
1351  rbuffer_[rsrc_out] = new char_type[bufsz];
1352  rsrc_ = rsrc_out;
1353  this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
1354  rbuffer_[rsrc_out] + pbsz);
1355  }
1356  if (mode & pstderr)
1357  {
1358  delete[] rbuffer_[rsrc_err];
1359  rbuffer_[rsrc_err] = new char_type[bufsz];
1360  if (!(mode & pstdout))
1361  {
1362  rsrc_ = rsrc_err;
1363  this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
1364  rbuffer_[rsrc_err] + pbsz);
1365  }
1366  }
1367  }
1368 
1369  template <typename C, typename T>
1370  void
1371  basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
1372  {
1373  if (mode & pstdin)
1374  {
1375  this->setp(NULL, NULL);
1376  delete[] wbuffer_;
1377  wbuffer_ = NULL;
1378  }
1379  if (mode & pstdout)
1380  {
1381  if (rsrc_ == rsrc_out)
1382  this->setg(NULL, NULL, NULL);
1383  delete[] rbuffer_[rsrc_out];
1384  rbuffer_[rsrc_out] = NULL;
1385  }
1386  if (mode & pstderr)
1387  {
1388  if (rsrc_ == rsrc_err)
1389  this->setg(NULL, NULL, NULL);
1390  delete[] rbuffer_[rsrc_err];
1391  rbuffer_[rsrc_err] = NULL;
1392  }
1393  }
1394 
1395  template <typename C, typename T>
1396  typename basic_pstreambuf<C,T>::buf_read_src
1397  basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
1398  {
1399  if (rsrc_ != src)
1400  {
1401  char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
1402  this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
1403  for (std::size_t i = 0; i < 3; ++i)
1404  rbufstate_[i] = tmpbufstate[i];
1405  rsrc_ = src;
1406  }
1407  return rsrc_;
1408  }
1409 
1426  template <typename C, typename T>
1427  int
1429  {
1430  int exited = -1;
1431  if (is_open())
1432  {
1433  int status;
1434  switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
1435  {
1436  case 0 :
1437  // nohang was true and process has not exited
1438  exited = 0;
1439  break;
1440  case -1 :
1441  error_ = errno;
1442  break;
1443  default :
1444  // process has exited
1445  ppid_ = 0;
1446  status_ = status;
1447  exited = 1;
1448  // Close wpipe, would get SIGPIPE if we used it.
1449  destroy_buffers(pstdin);
1450  close_fd(wpipe_);
1451  // Must free read buffers and pipes on destruction
1452  // or next call to open()/close()
1453  break;
1454  }
1455  }
1456  return exited;
1457  }
1458 
1469  template <typename C, typename T>
1470  inline basic_pstreambuf<C,T>*
1472  {
1473  basic_pstreambuf<C,T>* ret = NULL;
1474  if (is_open())
1475  {
1476  if (::kill(ppid_, signal))
1477  error_ = errno;
1478  else
1479  {
1480 #if 0
1481  // TODO call exited() to check for exit and clean up? leave to user?
1482  if (signal==SIGTERM || signal==SIGKILL)
1483  this->exited();
1484 #endif
1485  ret = this;
1486  }
1487  }
1488  return ret;
1489  }
1490 
1498  template <typename C, typename T>
1499  inline bool
1501  {
1502  return ppid_ == 0 || wait(true)==1;
1503  }
1504 
1505 
1511  template <typename C, typename T>
1512  inline int
1514  {
1515  return status_;
1516  }
1517 
1521  template <typename C, typename T>
1522  inline int
1524  {
1525  return error_;
1526  }
1527 
1532  template <typename C, typename T>
1533  inline void
1535  {
1536  sync();
1537  destroy_buffers(pstdin);
1538  close_fd(wpipe_);
1539  }
1540 
1551  template <typename C, typename T>
1552  inline bool
1554  {
1555  return ppid_ > 0;
1556  }
1557 
1566  template <typename C, typename T>
1567  inline bool
1569  {
1570  buf_read_src src = readerr ? rsrc_err : rsrc_out;
1571  if (rpipe_[src]>=0)
1572  {
1573  switch_read_buffer(src);
1574  return true;
1575  }
1576  return false;
1577  }
1578 
1589  template <typename C, typename T>
1590  typename basic_pstreambuf<C,T>::int_type
1592  {
1593  if (!empty_buffer())
1594  return traits_type::eof();
1595  else if (!traits_type::eq_int_type(c, traits_type::eof()))
1596  return this->sputc(c);
1597  else
1598  return traits_type::not_eof(c);
1599  }
1600 
1601 
1602  template <typename C, typename T>
1603  int
1605  {
1606  return !exited() && empty_buffer() ? 0 : -1;
1607  }
1608 
1614  template <typename C, typename T>
1615  std::streamsize
1616  basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
1617  {
1618  if (n < this->epptr() - this->pptr())
1619  {
1620  traits_type::copy(this->pptr(), s, n);
1621  this->pbump(n);
1622  return n;
1623  }
1624  else
1625  {
1626  for (std::streamsize i = 0; i < n; ++i)
1627  {
1628  if (traits_type::eq_int_type(this->sputc(s[i]), traits_type::eof()))
1629  return i;
1630  }
1631  return n;
1632  }
1633  }
1634 
1638  template <typename C, typename T>
1639  bool
1641  {
1642  const std::streamsize count = this->pptr() - this->pbase();
1643  if (count > 0)
1644  {
1645  const std::streamsize written = this->write(this->wbuffer_, count);
1646  if (written > 0)
1647  {
1648  if (const std::streamsize unwritten = count - written)
1649  traits_type::move(this->pbase(), this->pbase()+written, unwritten);
1650  this->pbump(-written);
1651  return true;
1652  }
1653  }
1654  return false;
1655  }
1656 
1664  template <typename C, typename T>
1665  typename basic_pstreambuf<C,T>::int_type
1667  {
1668  if (this->gptr() < this->egptr() || fill_buffer())
1669  return traits_type::to_int_type(*this->gptr());
1670  else
1671  return traits_type::eof();
1672  }
1673 
1682  template <typename C, typename T>
1683  typename basic_pstreambuf<C,T>::int_type
1685  {
1686  if (this->gptr() != this->eback())
1687  {
1688  this->gbump(-1);
1689  if (!traits_type::eq_int_type(c, traits_type::eof()))
1690  *this->gptr() = traits_type::to_char_type(c);
1691  return traits_type::not_eof(c);
1692  }
1693  else
1694  return traits_type::eof();
1695  }
1696 
1697  template <typename C, typename T>
1698  std::streamsize
1700  {
1701  int avail = 0;
1702  if (sizeof(char_type) == 1)
1703  avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
1704 #ifdef FIONREAD
1705  else
1706  {
1707  if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
1708  avail = -1;
1709  else if (avail)
1710  avail /= sizeof(char_type);
1711  }
1712 #endif
1713  return std::streamsize(avail);
1714  }
1715 
1719  template <typename C, typename T>
1720  bool
1722  {
1723  const std::streamsize pb1 = this->gptr() - this->eback();
1724  const std::streamsize pb2 = pbsz;
1725  const std::streamsize npb = std::min(pb1, pb2);
1726 
1727  char_type* const rbuf = rbuffer();
1728 
1729  traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
1730 
1731  std::streamsize rc = -1;
1732 
1733  if (non_blocking)
1734  {
1735  const int flags = ::fcntl(rpipe(), F_GETFL);
1736  if (flags != -1)
1737  {
1738  const bool blocking = !(flags & O_NONBLOCK);
1739  if (blocking)
1740  ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking
1741 
1742  error_ = 0;
1743  rc = read(rbuf + pbsz, bufsz - pbsz);
1744 
1745  if (rc == -1 && error_ == EAGAIN) // nothing available
1746  rc = 0;
1747  else if (rc == 0) // EOF
1748  rc = -1;
1749 
1750  if (blocking)
1751  ::fcntl(rpipe(), F_SETFL, flags); // restore
1752  }
1753  }
1754  else
1755  rc = read(rbuf + pbsz, bufsz - pbsz);
1756 
1757  if (rc > 0 || (rc == 0 && non_blocking))
1758  {
1759  this->setg( rbuf + pbsz - npb,
1760  rbuf + pbsz,
1761  rbuf + pbsz + rc );
1762  return true;
1763  }
1764  else
1765  {
1766  this->setg(NULL, NULL, NULL);
1767  return false;
1768  }
1769  }
1770 
1778  template <typename C, typename T>
1779  inline std::streamsize
1780  basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
1781  {
1782  std::streamsize nwritten = 0;
1783  if (wpipe() >= 0)
1784  {
1785  nwritten = ::write(wpipe(), s, n * sizeof(char_type));
1786  if (nwritten == -1)
1787  error_ = errno;
1788  else
1789  nwritten /= sizeof(char_type);
1790  }
1791  return nwritten;
1792  }
1793 
1801  template <typename C, typename T>
1802  inline std::streamsize
1803  basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
1804  {
1805  std::streamsize nread = 0;
1806  if (rpipe() >= 0)
1807  {
1808  nread = ::read(rpipe(), s, n * sizeof(char_type));
1809  if (nread == -1)
1810  error_ = errno;
1811  else
1812  nread /= sizeof(char_type);
1813  }
1814  return nread;
1815  }
1816 
1818  template <typename C, typename T>
1819  inline typename basic_pstreambuf<C,T>::fd_type&
1821  {
1822  return wpipe_;
1823  }
1824 
1826  template <typename C, typename T>
1827  inline typename basic_pstreambuf<C,T>::fd_type&
1829  {
1830  return rpipe_[rsrc_];
1831  }
1832 
1834  template <typename C, typename T>
1835  inline typename basic_pstreambuf<C,T>::fd_type&
1837  {
1838  return rpipe_[which];
1839  }
1840 
1842  template <typename C, typename T>
1843  inline typename basic_pstreambuf<C,T>::char_type*
1845  {
1846  return rbuffer_[rsrc_];
1847  }
1848 
1849 
1850  /*
1851  * member definitions for pstream_common
1852  */
1853 
1863  template <typename C, typename T>
1864  inline
1866  : std::basic_ios<C,T>(NULL)
1867  , command_()
1868  , buf_()
1869  {
1870  this->init(&buf_);
1871  }
1872 
1881  template <typename C, typename T>
1882  inline
1883  pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
1884  : std::basic_ios<C,T>(NULL)
1885  , command_(command)
1886  , buf_()
1887  {
1888  this->init(&buf_);
1889  do_open(command, mode);
1890  }
1891 
1901  template <typename C, typename T>
1902  inline
1903  pstream_common<C,T>::pstream_common( const std::string& file,
1904  const argv_type& argv,
1905  pmode mode )
1906  : std::basic_ios<C,T>(NULL)
1907  , command_(file)
1908  , buf_()
1909  {
1910  this->init(&buf_);
1911  do_open(file, argv, mode);
1912  }
1913 
1923  template <typename C, typename T>
1924  inline
1926  {
1927  }
1928 
1937  template <typename C, typename T>
1938  inline void
1939  pstream_common<C,T>::do_open(const std::string& command, pmode mode)
1940  {
1941  if (!buf_.open((command_=command), mode))
1942  this->setstate(std::ios_base::failbit);
1943  }
1944 
1954  template <typename C, typename T>
1955  inline void
1956  pstream_common<C,T>::do_open( const std::string& file,
1957  const argv_type& argv,
1958  pmode mode )
1959  {
1960  if (!buf_.open((command_=file), argv, mode))
1961  this->setstate(std::ios_base::failbit);
1962  }
1963 
1965  template <typename C, typename T>
1966  inline void
1968  {
1969  if (!buf_.close())
1970  this->setstate(std::ios_base::failbit);
1971  }
1972 
1977  template <typename C, typename T>
1978  inline bool
1980  {
1981  return buf_.is_open();
1982  }
1983 
1985  template <typename C, typename T>
1986  inline const std::string&
1988  {
1989  return command_;
1990  }
1991 
1993  // TODO document behaviour if buffer replaced.
1994  template <typename C, typename T>
1995  inline typename pstream_common<C,T>::streambuf_type*
1997  {
1998  return const_cast<streambuf_type*>(&buf_);
1999  }
2000 
2001 
2002 #if REDI_EVISCERATE_PSTREAMS
2003 
2035  template <typename C, typename T>
2036  std::size_t
2037  basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
2038  {
2039  in = out = err = NULL;
2040  std::size_t open_files = 0;
2041  if (wpipe() > -1)
2042  {
2043  if ((in = ::fdopen(wpipe(), "w")))
2044  {
2045  open_files |= pstdin;
2046  }
2047  }
2048  if (rpipe(rsrc_out) > -1)
2049  {
2050  if ((out = ::fdopen(rpipe(rsrc_out), "r")))
2051  {
2052  open_files |= pstdout;
2053  }
2054  }
2055  if (rpipe(rsrc_err) > -1)
2056  {
2057  if ((err = ::fdopen(rpipe(rsrc_err), "r")))
2058  {
2059  open_files |= pstderr;
2060  }
2061  }
2062  return open_files;
2063  }
2064 
2075  template <typename C, typename T>
2076  inline std::size_t
2077  pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
2078  {
2079  return buf_.fopen(fin, fout, ferr);
2080  }
2081 
2082 #endif // REDI_EVISCERATE_PSTREAMS
2083 
2084 
2085 } // namespace redi
2086 
2092 #endif // REDI_PSTREAM_H_SEEN
2093 
2094 // vim: ts=2 sw=2 expandtab
2095 
void close_fd(pstreams::fd_type &fd)
Helper function to close a file descriptor.
Definition: pstream.h:1034
basic_pstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:617
int_type overflow(int_type c)
Transfer characters to the pipe when character buffer overflows.
Definition: pstream.h:1591
std::streamsize write(const char_type *s, std::streamsize n)
Insert a sequence of characters into the pipe.
Definition: pstream.h:1780
int error() const
Return the error number (errno) for the most recent failed operation.
Definition: pstream.h:1523
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:741
fd_type fd_t
Definition: pstream.h:110
~basic_pstream()
Destructor.
Definition: pstream.h:643
Class template for Bidirectional PStreams.
Definition: pstream.h:585
char_type * rbuffer()
Return the active input buffer.
Definition: pstream.h:1844
Class template for stream buffer.
Definition: pstream.h:98
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:360
std::streamsize read(char_type *s, std::streamsize n)
Extract a sequence of characters from the pipe.
Definition: pstream.h:1803
basic_rpstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:744
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:792
basic_pstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:603
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:488
bool read_err(bool readerr=true)
Change active input source.
Definition: pstream.h:1568
basic_rpstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:758
virtual ~pstream_common()=0
Pure virtual destructor.
Definition: pstream.h:1925
void close_fd_array(pstreams::fd_type(&fds)[N])
Helper function to close an array of file descriptors.
Definition: pstream.h:1052
std::vector< std::string > argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:82
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:363
pstream_common()
Default constructor.
Definition: pstream.h:1865
int_type underflow()
Transfer characters from the pipe when the character buffer is empty.
Definition: pstream.h:1666
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:808
Class template for common base class.
Definition: pstream.h:270
basic_pstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:632
basic_opstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:494
basic_pstreambuf< char > pstreambuf
Type definition for common template specialisation.
Definition: pstream.h:842
static const pmode pstderr
Read from stderr.
Definition: pstream.h:89
streambuf_type * rdbuf() const
Return a pointer to the stream buffer.
Definition: pstream.h:1996
int_type pbackfail(int_type c=traits_type::eof())
Make a character available to be returned by the next extraction.
Definition: pstream.h:1684
Common base class providing constants and typenames.
Definition: pstream.h:76
bool fill_buffer(bool non_blocking=false)
Definition: pstream.h:1721
static const pmode pstdout
Read from stdout.
Definition: pstream.h:88
fd_type & wpipe()
Return the file descriptor for the output pipe.
Definition: pstream.h:1820
int sync()
Write any buffered characters to the stream.
Definition: pstream.h:1604
basic_rpstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:773
basic_pstreambuf()
Default constructor.
Definition: pstream.h:889
basic_ipstream(const std::string &command, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:380
std::string command_
The command used to start the process.
Definition: pstream.h:325
bool exited()
Report whether the process has exited.
Definition: pstream.h:1500
streambuf_type buf_
The stream buffer.
Definition: pstream.h:326
buf_read_src
Enumerated type to indicate whether stdout or stderr is to be read.
Definition: pstream.h:207
basic_pstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:683
bool is_open() const
Report whether the stream's buffer has been initialised.
Definition: pstream.h:1979
basic_ipstream(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:395
Class template for Input PStreams.
Definition: pstream.h:341
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:600
std::streamsize xsputn(const char_type *s, std::streamsize n)
Insert multiple characters into the pipe.
Definition: pstream.h:1616
void open(const std::string &command, pmode mode=pstdin)
Start a process.
Definition: pstream.h:546
pid_t fork(pmode mode)
Initialise pipes and fork process.
Definition: pstream.h:1192
basic_ipstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:458
basic_pstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:694
fd_type & rpipe()
Return the file descriptor for the active input pipe.
Definition: pstream.h:1828
basic_rpstream< char > rpstream
Type definition for common template specialisation.
Definition: pstream.h:850
basic_ipstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:447
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:655
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:491
int fd_type
Type used for file descriptors.
Definition: pstream.h:85
~basic_pstreambuf()
Destructor.
Definition: pstream.h:953
std::ios_base::openmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:79
template for Restricted PStreams.
Definition: pstream.h:724
basic_pstreambuf * close()
Close the stream buffer and wait for the process to exit.
Definition: pstream.h:1303
bool is_open() const
Report whether the stream buffer has been initialised.
Definition: pstream.h:1553
bool empty_buffer()
Writes buffered characters to the process' stdin pipe.
Definition: pstream.h:1640
void do_open(const std::string &command, pmode mode)
Start a process.
Definition: pstream.h:1939
~basic_ipstream()
Destructor.
Definition: pstream.h:406
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:738
std::basic_ostream< C, T > & peof(std::basic_ostream< C, T > &s)
Manipulator to close the pipe connected to the process' stdin.
Definition: pstream.h:867
basic_ipstream< char > ipstream
Type definition for common template specialisation.
Definition: pstream.h:844
void open(const std::string &command, pmode mode=pstdout)
Start a process.
Definition: pstream.h:419
int wait(bool nohang=false)
Wait for the child process to exit.
Definition: pstream.h:1428
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Start a process.
Definition: pstream.h:435
Class template for Output PStreams.
Definition: pstream.h:476
const std::string & command() const
Return the command used to initialise the stream.
Definition: pstream.h:1987
basic_pstreambuf * open(const std::string &command, pmode mode)
Initialise the stream buffer with command.
Definition: pstream.h:987
istream_type & err()
Obtain a reference to the istream that reads the process' stderr.
Definition: pstream.h:833
basic_ipstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:366
~basic_rpstream()
Destructor.
Definition: pstream.h:780
void close()
Close the pipe.
Definition: pstream.h:1967
void peof()
Close the pipe connected to the process' stdin.
Definition: pstream.h:1534
basic_opstream< char > opstream
Type definition for common template specialisation.
Definition: pstream.h:846
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:597
void open(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Start a process.
Definition: pstream.h:562
int status() const
Return the exit status of the process.
Definition: pstream.h:1513
basic_pstream< char > pstream
Type definition for common template specialisation.
Definition: pstream.h:848
static const pmode pstdin
Write to stdin.
Definition: pstream.h:87
std::streamsize showmanyc()
Report how many characters can be read from active input without blocking.
Definition: pstream.h:1699
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:671
basic_opstream(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:523
basic_opstream(const std::string &command, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:508
basic_pstreambuf * kill(int signal=SIGTERM)
Send a signal to the process.
Definition: pstream.h:1471
istream_type & out()
Obtain a reference to the istream that reads the process' stdout.
Definition: pstream.h:821
~basic_opstream()
Destructor.
Definition: pstream.h:534