PStreams
pstream.h
Go to the documentation of this file.
1/*
2PStreams - POSIX Process I/O for C++
3Copyright (C) 2001-2014 Jonathan Wakely
4
5This file is part of PStreams.
6
7PStreams is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
11
12PStreams is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along 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, NULL
42#include <cstdlib> // for exit()
43#include <sys/types.h> // for pid_t
44#include <sys/wait.h> // for waitpid()
45#include <sys/ioctl.h> // for ioctl() and FIONREAD
46#if defined(__sun)
47# include <sys/filio.h> // for FIONREAD on Solaris 2.5
48#endif
49#include <unistd.h> // for pipe() fork() exec() and filedes functions
50#include <signal.h> // for kill()
51#include <fcntl.h> // for fcntl()
52#if REDI_EVISCERATE_PSTREAMS
53# include <stdio.h> // for FILE, fdopen()
54#endif
55
56
58#define PSTREAMS_VERSION 0x0081 // 0.8.1
59
73namespace 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
92 static const pmode newpg = std::ios_base::trunc;
93
94 protected:
95 enum { bufsz = 32 };
96 enum { pbsz = 2 };
97 };
98
100 template <typename CharT, typename Traits = std::char_traits<CharT> >
102 : public std::basic_streambuf<CharT, Traits>
103 , public pstreams
104 {
105 public:
106 // Type definitions for dependent types
107 typedef CharT char_type;
108 typedef Traits traits_type;
109 typedef typename traits_type::int_type int_type;
110 typedef typename traits_type::off_type off_type;
111 typedef typename traits_type::pos_type pos_type;
113 typedef fd_type fd_t;
114
117
119 basic_pstreambuf(const std::string& command, pmode mode);
120
122 basic_pstreambuf( const std::string& file,
123 const argv_type& argv,
124 pmode mode );
125
128
131 open(const std::string& command, pmode mode);
132
135 open(const std::string& file, const argv_type& argv, pmode mode);
136
140
143 kill(int signal = SIGTERM);
144
147 killpg(int signal = SIGTERM);
148
150 void
152
154 bool
155 read_err(bool readerr = true);
156
158 bool
159 is_open() const;
160
162 bool
164
165#if REDI_EVISCERATE_PSTREAMS
167 std::size_t
168 fopen(FILE*& in, FILE*& out, FILE*& err);
169#endif
170
172 int
173 status() const;
174
176 int
177 error() const;
178
179 protected:
181 int_type
182 overflow(int_type c);
183
185 int_type
187
189 int_type
190 pbackfail(int_type c = traits_type::eof());
191
193 int
195
197 std::streamsize
198 xsputn(const char_type* s, std::streamsize n);
199
201 std::streamsize
202 write(const char_type* s, std::streamsize n);
203
205 std::streamsize
206 read(char_type* s, std::streamsize n);
207
209 std::streamsize
211
212 protected:
214 enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
215
217 pid_t
218 fork(pmode mode);
219
221 int
222 wait(bool nohang = false);
223
225 fd_type&
227
229 fd_type&
231
233 fd_type&
235
236 void
237 create_buffers(pmode mode);
238
239 void
240 destroy_buffers(pmode mode);
241
243 bool
245
246 bool
247 fill_buffer(bool non_blocking = false);
248
250 char_type*
252
254 switch_read_buffer(buf_read_src);
255
256 private:
258 basic_pstreambuf& operator=(const basic_pstreambuf&);
259
260 void
261 init_rbuffers();
262
263 pid_t ppid_; // pid of process
264 fd_type wpipe_; // pipe used to write to process' stdin
265 fd_type rpipe_[2]; // two pipes to read from, stdout and stderr
266 char_type* wbuffer_;
267 char_type* rbuffer_[2];
268 char_type* rbufstate_[3];
270 buf_read_src rsrc_;
271 int status_; // hold exit status of child process
272 int error_; // hold errno if fork() or exec() fails
273 };
274
276 template <typename CharT, typename Traits = std::char_traits<CharT> >
278 : virtual public std::basic_ios<CharT, Traits>
279 , virtual public pstreams
280 {
281 protected:
283
284 typedef pstreams::pmode pmode;
285 typedef pstreams::argv_type argv_type;
286
289
291 pstream_common(const std::string& command, pmode mode);
292
294 pstream_common(const std::string& file, const argv_type& argv, pmode mode);
295
297 virtual
299
301 void
302 do_open(const std::string& command, pmode mode);
303
305 void
306 do_open(const std::string& file, const argv_type& argv, pmode mode);
307
308 public:
310 void
312
314 bool
315 is_open() const;
316
318 const std::string&
319 command() const;
320
323 rdbuf() const;
324
325#if REDI_EVISCERATE_PSTREAMS
327 std::size_t
328 fopen(FILE*& in, FILE*& out, FILE*& err);
329#endif
330
331 protected:
332 std::string command_;
334 };
335
336
347 template <typename CharT, typename Traits = std::char_traits<CharT> >
349 : public std::basic_istream<CharT, Traits>
350 , public pstream_common<CharT, Traits>
351 , virtual public pstreams
352 {
353 typedef std::basic_istream<CharT, Traits> istream_type;
355
356 using pbase_type::buf_; // declare name in this scope
357
358 // Ensure a basic_ipstream will read from at least one pipe
359 pmode readable(pmode mode)
360 {
361 if (!(mode & (pstdout|pstderr)))
362 mode |= pstdout;
363 return mode;
364 }
365
366 public:
368 typedef typename pbase_type::pmode pmode;
369
371 typedef typename pbase_type::argv_type argv_type;
372
375 : istream_type(NULL), pbase_type()
376 { }
377
388 explicit
389 basic_ipstream(const std::string& command, pmode mode = pstdout)
390 : istream_type(NULL), pbase_type(command, readable(mode))
391 { }
392
404 basic_ipstream( const std::string& file,
405 const argv_type& argv,
406 pmode mode = pstdout )
407 : istream_type(NULL), pbase_type(file, argv, readable(mode))
408 { }
409
420 explicit
422 : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode))
423 { }
424
425#if __cplusplus >= 201103L
426 template<typename T>
427 explicit
428 basic_ipstream(std::initializer_list<T> args, pmode mode = pstdout)
429 : basic_ipstream(argv_type(args.begin(), args.end()), mode)
430 { }
431#endif
432
439 { }
440
450 void
451 open(const std::string& command, pmode mode = pstdout)
452 {
453 this->do_open(command, readable(mode));
454 }
455
466 void
467 open( const std::string& file,
468 const argv_type& argv,
469 pmode mode = pstdout )
470 {
471 this->do_open(file, argv, readable(mode));
472 }
473
480 {
481 this->buf_.read_err(false);
482 return *this;
483 }
484
491 {
492 this->buf_.read_err(true);
493 return *this;
494 }
495 };
496
497
507 template <typename CharT, typename Traits = std::char_traits<CharT> >
509 : public std::basic_ostream<CharT, Traits>
510 , public pstream_common<CharT, Traits>
511 , virtual public pstreams
512 {
513 typedef std::basic_ostream<CharT, Traits> ostream_type;
515
516 using pbase_type::buf_; // declare name in this scope
517
518 public:
520 typedef typename pbase_type::pmode pmode;
521
523 typedef typename pbase_type::argv_type argv_type;
524
527 : ostream_type(NULL), pbase_type()
528 { }
529
540 explicit
541 basic_opstream(const std::string& command, pmode mode = pstdin)
542 : ostream_type(NULL), pbase_type(command, mode|pstdin)
543 { }
544
556 basic_opstream( const std::string& file,
557 const argv_type& argv,
558 pmode mode = pstdin )
559 : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
560 { }
561
572 explicit
574 : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin)
575 { }
576
577#if __cplusplus >= 201103L
585 template<typename T>
586 explicit
587 basic_opstream(std::initializer_list<T> args, pmode mode = pstdin)
588 : basic_opstream(argv_type(args.begin(), args.end()), mode)
589 { }
590#endif
591
598
608 void
609 open(const std::string& command, pmode mode = pstdin)
610 {
611 this->do_open(command, mode|pstdin);
612 }
613
624 void
625 open( const std::string& file,
626 const argv_type& argv,
627 pmode mode = pstdin)
628 {
629 this->do_open(file, argv, mode|pstdin);
630 }
631 };
632
633
647 template <typename CharT, typename Traits = std::char_traits<CharT> >
649 : public std::basic_iostream<CharT, Traits>
650 , public pstream_common<CharT, Traits>
651 , virtual public pstreams
652 {
653 typedef std::basic_iostream<CharT, Traits> iostream_type;
655
656 using pbase_type::buf_; // declare name in this scope
657
658 public:
660 typedef typename pbase_type::pmode pmode;
661
663 typedef typename pbase_type::argv_type argv_type;
664
667 : iostream_type(NULL), pbase_type()
668 { }
669
680 explicit
681 basic_pstream(const std::string& command, pmode mode = pstdout|pstdin)
682 : iostream_type(NULL), pbase_type(command, mode)
683 { }
684
696 basic_pstream( const std::string& file,
697 const argv_type& argv,
698 pmode mode = pstdout|pstdin )
699 : iostream_type(NULL), pbase_type(file, argv, mode)
700 { }
701
712 explicit
714 : iostream_type(NULL), pbase_type(argv.at(0), argv, mode)
715 { }
716
717#if __cplusplus >= 201103L
725 template<typename T>
726 explicit
727 basic_pstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
728 : basic_pstream(argv_type(l.begin(), l.end()), mode)
729 { }
730#endif
731
738
748 void
749 open(const std::string& command, pmode mode = pstdout|pstdin)
750 {
751 this->do_open(command, mode);
752 }
753
764 void
765 open( const std::string& file,
766 const argv_type& argv,
767 pmode mode = pstdout|pstdin )
768 {
769 this->do_open(file, argv, mode);
770 }
771
778 {
779 this->buf_.read_err(false);
780 return *this;
781 }
782
789 {
790 this->buf_.read_err(true);
791 return *this;
792 }
793 };
794
795
817 template <typename CharT, typename Traits = std::char_traits<CharT> >
819 : public std::basic_ostream<CharT, Traits>
820 , private std::basic_istream<CharT, Traits>
821 , private pstream_common<CharT, Traits>
822 , virtual public pstreams
823 {
824 typedef std::basic_ostream<CharT, Traits> ostream_type;
825 typedef std::basic_istream<CharT, Traits> istream_type;
827
828 using pbase_type::buf_; // declare name in this scope
829
830 public:
832 typedef typename pbase_type::pmode pmode;
833
835 typedef typename pbase_type::argv_type argv_type;
836
839 : ostream_type(NULL), istream_type(NULL), pbase_type()
840 { }
841
852 explicit
853 basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
854 : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
855 { }
856
868 basic_rpstream( const std::string& file,
869 const argv_type& argv,
870 pmode mode = pstdout|pstdin )
871 : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
872 { }
873
884 explicit
886 : ostream_type(NULL), istream_type(NULL),
887 pbase_type(argv.at(0), argv, mode)
888 { }
889
890#if __cplusplus >= 201103L
898 template<typename T>
899 explicit
900 basic_rpstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
901 : basic_rpstream(argv_type(l.begin(), l.end()), mode)
902 { }
903#endif
904
907
917 void
918 open(const std::string& command, pmode mode = pstdout|pstdin)
919 {
920 this->do_open(command, mode);
921 }
922
933 void
934 open( const std::string& file,
935 const argv_type& argv,
936 pmode mode = pstdout|pstdin )
937 {
938 this->do_open(file, argv, mode);
939 }
940
946 istream_type&
948 {
949 this->buf_.read_err(false);
950 return *this;
951 }
952
958 istream_type&
960 {
961 this->buf_.read_err(true);
962 return *this;
963 }
964 };
965
966
977
978
991 template <typename C, typename T>
992 inline std::basic_ostream<C,T>&
993 peof(std::basic_ostream<C,T>& s)
994 {
996 if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
997 p->peof();
998 return s;
999 }
1000
1001
1002 /*
1003 * member definitions for pstreambuf
1004 */
1005
1006
1013 template <typename C, typename T>
1014 inline
1016 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1017 , wpipe_(-1)
1018 , wbuffer_(NULL)
1019 , rsrc_(rsrc_out)
1020 , status_(-1)
1021 , error_(0)
1022 {
1023 init_rbuffers();
1024 }
1025
1034 template <typename C, typename T>
1035 inline
1036 basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
1037 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1038 , wpipe_(-1)
1039 , wbuffer_(NULL)
1040 , rsrc_(rsrc_out)
1041 , status_(-1)
1042 , error_(0)
1043 {
1044 init_rbuffers();
1045 open(command, mode);
1046 }
1047
1057 template <typename C, typename T>
1058 inline
1060 const argv_type& argv,
1061 pmode mode )
1062 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1063 , wpipe_(-1)
1064 , wbuffer_(NULL)
1065 , rsrc_(rsrc_out)
1066 , status_(-1)
1067 , error_(0)
1068 {
1069 init_rbuffers();
1070 open(file, argv, mode);
1071 }
1072
1077 template <typename C, typename T>
1078 inline
1080 {
1081 close();
1082 }
1083
1111 template <typename C, typename T>
1113 basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
1114 {
1115 const char * shell_path = "/bin/sh";
1116#if 0
1117 const std::string argv[] = { "sh", "-c", command };
1118 return this->open(shell_path, argv_type(argv, argv+3), mode);
1119#else
1120 basic_pstreambuf<C,T>* ret = NULL;
1121
1122 if (!is_open())
1123 {
1124 switch(fork(mode))
1125 {
1126 case 0 :
1127 // this is the new process, exec command
1128 ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
1129
1130 // can only reach this point if exec() failed
1131
1132 // parent can get exit code from waitpid()
1133 ::_exit(errno);
1134 // using std::exit() would make static dtors run twice
1135
1136 case -1 :
1137 // couldn't fork, error already handled in pstreambuf::fork()
1138 break;
1139
1140 default :
1141 // this is the parent process
1142 // activate buffers
1143 create_buffers(mode);
1144 ret = this;
1145 }
1146 }
1147 return ret;
1148#endif
1149 }
1150
1159 inline void
1161 {
1162 if (fd >= 0 && ::close(fd) == 0)
1163 fd = -1;
1164 }
1165
1176 template <int N>
1177 inline void
1179 {
1180 for (std::size_t i = 0; i < N; ++i)
1181 close_fd(fds[i]);
1182 }
1183
1213 template <typename C, typename T>
1215 basic_pstreambuf<C,T>::open( const std::string& file,
1216 const argv_type& argv,
1217 pmode mode )
1218 {
1219 basic_pstreambuf<C,T>* ret = NULL;
1220
1221 if (!is_open())
1222 {
1223 // constants for read/write ends of pipe
1224 enum { RD, WR };
1225
1226 // open another pipe and set close-on-exec
1227 fd_type ck_exec[] = { -1, -1 };
1228 if (-1 == ::pipe(ck_exec)
1229 || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
1230 || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
1231 {
1232 error_ = errno;
1233 close_fd_array(ck_exec);
1234 }
1235 else
1236 {
1237 switch(fork(mode))
1238 {
1239 case 0 :
1240 // this is the new process, exec command
1241 {
1242 char** arg_v = new char*[argv.size()+1];
1243 for (std::size_t i = 0; i < argv.size(); ++i)
1244 {
1245 const std::string& src = argv[i];
1246 char*& dest = arg_v[i];
1247 dest = new char[src.size()+1];
1248 dest[ src.copy(dest, src.size()) ] = '\0';
1249 }
1250 arg_v[argv.size()] = NULL;
1251
1252 ::execvp(file.c_str(), arg_v);
1253
1254 // can only reach this point if exec() failed
1255
1256 // parent can get error code from ck_exec pipe
1257 error_ = errno;
1258
1259 while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1
1260 && errno == EINTR)
1261 { }
1262
1263 ::close(ck_exec[WR]);
1264 ::close(ck_exec[RD]);
1265
1266 ::_exit(error_);
1267 // using std::exit() would make static dtors run twice
1268 }
1269
1270 case -1 :
1271 // couldn't fork, error already handled in pstreambuf::fork()
1272 close_fd_array(ck_exec);
1273 break;
1274
1275 default :
1276 // this is the parent process
1277
1278 // check child called exec() successfully
1279 ::close(ck_exec[WR]);
1280 switch (::read(ck_exec[RD], &error_, sizeof(error_)))
1281 {
1282 case 0:
1283 // activate buffers
1284 create_buffers(mode);
1285 ret = this;
1286 break;
1287 case -1:
1288 error_ = errno;
1289 break;
1290 default:
1291 // error_ contains error code from child
1292 // call wait() to clean up and set ppid_ to 0
1293 this->wait();
1294 break;
1295 }
1296 ::close(ck_exec[RD]);
1297 }
1298 }
1299 }
1300 return ret;
1301 }
1302
1319 template <typename C, typename T>
1320 pid_t
1322 {
1323 pid_t pid = -1;
1324
1325 // Three pairs of file descriptors, for pipes connected to the
1326 // process' stdin, stdout and stderr
1327 // (stored in a single array so close_fd_array() can close all at once)
1328 fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
1329 fd_type* const pin = fd;
1330 fd_type* const pout = fd+2;
1331 fd_type* const perr = fd+4;
1332
1333 // constants for read/write ends of pipe
1334 enum { RD, WR };
1335
1336 // N.B.
1337 // For the pstreambuf pin is an output stream and
1338 // pout and perr are input streams.
1339
1340 if (!error_ && mode&pstdin && ::pipe(pin))
1341 error_ = errno;
1342
1343 if (!error_ && mode&pstdout && ::pipe(pout))
1344 error_ = errno;
1345
1346 if (!error_ && mode&pstderr && ::pipe(perr))
1347 error_ = errno;
1348
1349 if (!error_)
1350 {
1351 pid = ::fork();
1352 switch (pid)
1353 {
1354 case 0 :
1355 {
1356 // this is the new process
1357
1358 // for each open pipe close one end and redirect the
1359 // respective standard stream to the other end
1360
1361 if (*pin >= 0)
1362 {
1363 ::close(pin[WR]);
1364 ::dup2(pin[RD], STDIN_FILENO);
1365 ::close(pin[RD]);
1366 }
1367 if (*pout >= 0)
1368 {
1369 ::close(pout[RD]);
1370 ::dup2(pout[WR], STDOUT_FILENO);
1371 ::close(pout[WR]);
1372 }
1373 if (*perr >= 0)
1374 {
1375 ::close(perr[RD]);
1376 ::dup2(perr[WR], STDERR_FILENO);
1377 ::close(perr[WR]);
1378 }
1379
1380#ifdef _POSIX_JOB_CONTROL
1381 if (mode&newpg)
1382 ::setpgid(0, 0); // Change to a new process group
1383#endif
1384
1385 break;
1386 }
1387 case -1 :
1388 {
1389 // couldn't fork for some reason
1390 error_ = errno;
1391 // close any open pipes
1392 close_fd_array(fd);
1393 break;
1394 }
1395 default :
1396 {
1397 // this is the parent process, store process' pid
1398 ppid_ = pid;
1399
1400 // store one end of open pipes and close other end
1401 if (*pin >= 0)
1402 {
1403 wpipe_ = pin[WR];
1404 ::close(pin[RD]);
1405 }
1406 if (*pout >= 0)
1407 {
1408 rpipe_[rsrc_out] = pout[RD];
1409 ::close(pout[WR]);
1410 }
1411 if (*perr >= 0)
1412 {
1413 rpipe_[rsrc_err] = perr[RD];
1414 ::close(perr[WR]);
1415 }
1416 }
1417 }
1418 }
1419 else
1420 {
1421 // close any pipes we opened before failure
1422 close_fd_array(fd);
1423 }
1424 return pid;
1425 }
1426
1436 template <typename C, typename T>
1439 {
1440 const bool running = is_open();
1441
1442 sync(); // this might call wait() and reap the child process
1443
1444 // rather than trying to work out whether or not we need to clean up
1445 // just do it anyway, all cleanup functions are safe to call twice.
1446
1447 destroy_buffers(pstdin|pstdout|pstderr);
1448
1449 // close pipes before wait() so child gets EOF/SIGPIPE
1450 close_fd(wpipe_);
1451 close_fd_array(rpipe_);
1452
1453 do
1454 {
1455 error_ = 0;
1456 } while (wait() == -1 && error() == EINTR);
1457
1458 return running ? this : NULL;
1459 }
1460
1464 template <typename C, typename T>
1465 inline void
1467 {
1468 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1469 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
1470 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
1471 }
1472
1473 template <typename C, typename T>
1474 void
1475 basic_pstreambuf<C,T>::create_buffers(pmode mode)
1476 {
1477 if (mode & pstdin)
1478 {
1479 delete[] wbuffer_;
1480 wbuffer_ = new char_type[bufsz];
1481 this->setp(wbuffer_, wbuffer_ + bufsz);
1482 }
1483 if (mode & pstdout)
1484 {
1485 delete[] rbuffer_[rsrc_out];
1486 rbuffer_[rsrc_out] = new char_type[bufsz];
1487 rsrc_ = rsrc_out;
1488 this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
1489 rbuffer_[rsrc_out] + pbsz);
1490 }
1491 if (mode & pstderr)
1492 {
1493 delete[] rbuffer_[rsrc_err];
1494 rbuffer_[rsrc_err] = new char_type[bufsz];
1495 if (!(mode & pstdout))
1496 {
1497 rsrc_ = rsrc_err;
1498 this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
1499 rbuffer_[rsrc_err] + pbsz);
1500 }
1501 }
1502 }
1503
1504 template <typename C, typename T>
1505 void
1506 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
1507 {
1508 if (mode & pstdin)
1509 {
1510 this->setp(NULL, NULL);
1511 delete[] wbuffer_;
1512 wbuffer_ = NULL;
1513 }
1514 if (mode & pstdout)
1515 {
1516 if (rsrc_ == rsrc_out)
1517 this->setg(NULL, NULL, NULL);
1518 delete[] rbuffer_[rsrc_out];
1519 rbuffer_[rsrc_out] = NULL;
1520 }
1521 if (mode & pstderr)
1522 {
1523 if (rsrc_ == rsrc_err)
1524 this->setg(NULL, NULL, NULL);
1525 delete[] rbuffer_[rsrc_err];
1526 rbuffer_[rsrc_err] = NULL;
1527 }
1528 }
1529
1530 template <typename C, typename T>
1532 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
1533 {
1534 if (rsrc_ != src)
1535 {
1536 char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
1537 this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
1538 for (std::size_t i = 0; i < 3; ++i)
1539 rbufstate_[i] = tmpbufstate[i];
1540 rsrc_ = src;
1541 }
1542 return rsrc_;
1543 }
1544
1561 template <typename C, typename T>
1562 int
1564 {
1565 int exited = -1;
1566 if (is_open())
1567 {
1568 int status;
1569 switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
1570 {
1571 case 0 :
1572 // nohang was true and process has not exited
1573 exited = 0;
1574 break;
1575 case -1 :
1576 error_ = errno;
1577 break;
1578 default :
1579 // process has exited
1580 ppid_ = 0;
1581 status_ = status;
1582 exited = 1;
1583 // Close wpipe, would get SIGPIPE if we used it.
1584 destroy_buffers(pstdin);
1585 close_fd(wpipe_);
1586 // Must free read buffers and pipes on destruction
1587 // or next call to open()/close()
1588 break;
1589 }
1590 }
1591 return exited;
1592 }
1593
1604 template <typename C, typename T>
1605 inline basic_pstreambuf<C,T>*
1607 {
1608 basic_pstreambuf<C,T>* ret = NULL;
1609 if (is_open())
1610 {
1611 if (::kill(ppid_, signal))
1612 error_ = errno;
1613 else
1614 {
1615#if 0
1616 // TODO call exited() to check for exit and clean up? leave to user?
1617 if (signal==SIGTERM || signal==SIGKILL)
1618 this->exited();
1619#endif
1620 ret = this;
1621 }
1622 }
1623 return ret;
1624 }
1625
1639 template <typename C, typename T>
1640 inline basic_pstreambuf<C,T>*
1642 {
1643 basic_pstreambuf<C,T>* ret = NULL;
1644#ifdef _POSIX_JOB_CONTROL
1645 if (is_open())
1646 {
1647 pid_t pgid = ::getpgid(ppid_);
1648 if (pgid == -1)
1649 error_ = errno;
1650 else if (pgid == ::getpgrp())
1651 error_ = EPERM; // Don't commit suicide
1652 else if (::killpg(pgid, signal))
1653 error_ = errno;
1654 else
1655 ret = this;
1656 }
1657#else
1658 error_ = ENOTSUP;
1659#endif
1660 return ret;
1661 }
1662
1670 template <typename C, typename T>
1671 inline bool
1673 {
1674 return ppid_ == 0 || wait(true)==1;
1675 }
1676
1677
1683 template <typename C, typename T>
1684 inline int
1686 {
1687 return status_;
1688 }
1689
1693 template <typename C, typename T>
1694 inline int
1696 {
1697 return error_;
1698 }
1699
1704 template <typename C, typename T>
1705 inline void
1707 {
1708 sync();
1709 destroy_buffers(pstdin);
1710 close_fd(wpipe_);
1711 }
1712
1723 template <typename C, typename T>
1724 inline bool
1726 {
1727 return ppid_ > 0;
1728 }
1729
1738 template <typename C, typename T>
1739 inline bool
1741 {
1742 buf_read_src src = readerr ? rsrc_err : rsrc_out;
1743 if (rpipe_[src]>=0)
1744 {
1745 switch_read_buffer(src);
1746 return true;
1747 }
1748 return false;
1749 }
1750
1761 template <typename C, typename T>
1762 typename basic_pstreambuf<C,T>::int_type
1764 {
1765 if (!empty_buffer())
1766 return traits_type::eof();
1767 else if (!traits_type::eq_int_type(c, traits_type::eof()))
1768 return this->sputc(c);
1769 else
1770 return traits_type::not_eof(c);
1771 }
1772
1773
1774 template <typename C, typename T>
1775 int
1777 {
1778 return !exited() && empty_buffer() ? 0 : -1;
1779 }
1780
1786 template <typename C, typename T>
1787 std::streamsize
1788 basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
1789 {
1790 std::streamsize done = 0;
1791 while (done < n)
1792 {
1793 if (std::streamsize nbuf = this->epptr() - this->pptr())
1794 {
1795 nbuf = std::min(nbuf, n - done);
1796 traits_type::copy(this->pptr(), s + done, nbuf);
1797 this->pbump(nbuf);
1798 done += nbuf;
1799 }
1800 else if (!empty_buffer())
1801 break;
1802 }
1803 return done;
1804 }
1805
1809 template <typename C, typename T>
1810 bool
1812 {
1813 const std::streamsize count = this->pptr() - this->pbase();
1814 if (count > 0)
1815 {
1816 const std::streamsize written = this->write(this->wbuffer_, count);
1817 if (written > 0)
1818 {
1819 if (const std::streamsize unwritten = count - written)
1820 traits_type::move(this->pbase(), this->pbase()+written, unwritten);
1821 this->pbump(-written);
1822 return true;
1823 }
1824 }
1825 return false;
1826 }
1827
1835 template <typename C, typename T>
1836 typename basic_pstreambuf<C,T>::int_type
1838 {
1839 if (this->gptr() < this->egptr() || fill_buffer())
1840 return traits_type::to_int_type(*this->gptr());
1841 else
1842 return traits_type::eof();
1843 }
1844
1853 template <typename C, typename T>
1854 typename basic_pstreambuf<C,T>::int_type
1856 {
1857 if (this->gptr() != this->eback())
1858 {
1859 this->gbump(-1);
1860 if (!traits_type::eq_int_type(c, traits_type::eof()))
1861 *this->gptr() = traits_type::to_char_type(c);
1862 return traits_type::not_eof(c);
1863 }
1864 else
1865 return traits_type::eof();
1866 }
1867
1868 template <typename C, typename T>
1869 std::streamsize
1871 {
1872 int avail = 0;
1873 if (sizeof(char_type) == 1)
1874 avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
1875#ifdef FIONREAD
1876 else
1877 {
1878 if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
1879 avail = -1;
1880 else if (avail)
1881 avail /= sizeof(char_type);
1882 }
1883#endif
1884 return std::streamsize(avail);
1885 }
1886
1890 template <typename C, typename T>
1891 bool
1893 {
1894 const std::streamsize pb1 = this->gptr() - this->eback();
1895 const std::streamsize pb2 = pbsz;
1896 const std::streamsize npb = std::min(pb1, pb2);
1897
1898 char_type* const rbuf = rbuffer();
1899
1900 traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
1901
1902 std::streamsize rc = -1;
1903
1904 if (non_blocking)
1905 {
1906 const int flags = ::fcntl(rpipe(), F_GETFL);
1907 if (flags != -1)
1908 {
1909 const bool blocking = !(flags & O_NONBLOCK);
1910 if (blocking)
1911 ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking
1912
1913 error_ = 0;
1914 rc = read(rbuf + pbsz, bufsz - pbsz);
1915
1916 if (rc == -1 && error_ == EAGAIN) // nothing available
1917 rc = 0;
1918 else if (rc == 0) // EOF
1919 rc = -1;
1920
1921 if (blocking)
1922 ::fcntl(rpipe(), F_SETFL, flags); // restore
1923 }
1924 }
1925 else
1926 rc = read(rbuf + pbsz, bufsz - pbsz);
1927
1928 if (rc > 0 || (rc == 0 && non_blocking))
1929 {
1930 this->setg( rbuf + pbsz - npb,
1931 rbuf + pbsz,
1932 rbuf + pbsz + rc );
1933 return true;
1934 }
1935 else
1936 {
1937 this->setg(NULL, NULL, NULL);
1938 return false;
1939 }
1940 }
1941
1949 template <typename C, typename T>
1950 inline std::streamsize
1951 basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
1952 {
1953 std::streamsize nwritten = 0;
1954 if (wpipe() >= 0)
1955 {
1956 nwritten = ::write(wpipe(), s, n * sizeof(char_type));
1957 if (nwritten == -1)
1958 error_ = errno;
1959 else
1960 nwritten /= sizeof(char_type);
1961 }
1962 return nwritten;
1963 }
1964
1972 template <typename C, typename T>
1973 inline std::streamsize
1974 basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
1975 {
1976 std::streamsize nread = 0;
1977 if (rpipe() >= 0)
1978 {
1979 nread = ::read(rpipe(), s, n * sizeof(char_type));
1980 if (nread == -1)
1981 error_ = errno;
1982 else
1983 nread /= sizeof(char_type);
1984 }
1985 return nread;
1986 }
1987
1989 template <typename C, typename T>
1990 inline pstreams::fd_type&
1992 {
1993 return wpipe_;
1994 }
1995
1997 template <typename C, typename T>
1998 inline pstreams::fd_type&
2000 {
2001 return rpipe_[rsrc_];
2002 }
2003
2005 template <typename C, typename T>
2006 inline pstreams::fd_type&
2008 {
2009 return rpipe_[which];
2010 }
2011
2013 template <typename C, typename T>
2014 inline typename basic_pstreambuf<C,T>::char_type*
2016 {
2017 return rbuffer_[rsrc_];
2018 }
2019
2020
2021 /*
2022 * member definitions for pstream_common
2023 */
2024
2034 template <typename C, typename T>
2035 inline
2037 : std::basic_ios<C,T>(NULL)
2038 , command_()
2039 , buf_()
2040 {
2041 this->std::basic_ios<C,T>::rdbuf(&buf_);
2042 }
2043
2052 template <typename C, typename T>
2053 inline
2054 pstream_common<C,T>::pstream_common(const std::string& command, pmode mode)
2055 : std::basic_ios<C,T>(NULL)
2056 , command_(command)
2057 , buf_()
2058 {
2059 this->std::basic_ios<C,T>::rdbuf(&buf_);
2060 do_open(command, mode);
2061 }
2062
2072 template <typename C, typename T>
2073 inline
2074 pstream_common<C,T>::pstream_common( const std::string& file,
2075 const argv_type& argv,
2076 pmode mode )
2077 : std::basic_ios<C,T>(NULL)
2078 , command_(file)
2079 , buf_()
2080 {
2081 this->std::basic_ios<C,T>::rdbuf(&buf_);
2082 do_open(file, argv, mode);
2083 }
2084
2094 template <typename C, typename T>
2095 inline
2097 {
2098 }
2099
2108 template <typename C, typename T>
2109 inline void
2110 pstream_common<C,T>::do_open(const std::string& command, pmode mode)
2111 {
2112 if (!buf_.open((command_=command), mode))
2113 this->setstate(std::ios_base::failbit);
2114 }
2115
2125 template <typename C, typename T>
2126 inline void
2127 pstream_common<C,T>::do_open( const std::string& file,
2128 const argv_type& argv,
2129 pmode mode )
2130 {
2131 if (!buf_.open((command_=file), argv, mode))
2132 this->setstate(std::ios_base::failbit);
2133 }
2134
2136 template <typename C, typename T>
2137 inline void
2139 {
2140 if (!buf_.close())
2141 this->setstate(std::ios_base::failbit);
2142 }
2143
2148 template <typename C, typename T>
2149 inline bool
2151 {
2152 return buf_.is_open();
2153 }
2154
2156 template <typename C, typename T>
2157 inline const std::string&
2159 {
2160 return command_;
2161 }
2162
2164 // TODO document behaviour if buffer replaced.
2165 template <typename C, typename T>
2168 {
2169 return const_cast<streambuf_type*>(&buf_);
2170 }
2171
2172
2173#if REDI_EVISCERATE_PSTREAMS
2206 template <typename C, typename T>
2207 std::size_t
2208 basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
2209 {
2210 in = out = err = NULL;
2211 std::size_t open_files = 0;
2212 if (wpipe() > -1)
2213 {
2214 if ((in = ::fdopen(wpipe(), "w")))
2215 {
2216 open_files |= pstdin;
2217 }
2218 }
2219 if (rpipe(rsrc_out) > -1)
2220 {
2221 if ((out = ::fdopen(rpipe(rsrc_out), "r")))
2222 {
2223 open_files |= pstdout;
2224 }
2225 }
2226 if (rpipe(rsrc_err) > -1)
2227 {
2228 if ((err = ::fdopen(rpipe(rsrc_err), "r")))
2229 {
2230 open_files |= pstderr;
2231 }
2232 }
2233 return open_files;
2234 }
2235
2246 template <typename C, typename T>
2247 inline std::size_t
2248 pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
2249 {
2250 return buf_.fopen(fin, fout, ferr);
2251 }
2252
2253#endif // REDI_EVISCERATE_PSTREAMS
2254
2255
2256} // namespace redi
2257
2263#endif // REDI_PSTREAM_H_SEEN
2264
2265// vim: ts=2 sw=2 expandtab
2266
Class template for Input PStreams.
Definition: pstream.h:352
void open(const std::string &command, pmode mode=pstdout)
Start a process.
Definition: pstream.h:451
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:404
basic_ipstream(const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:421
basic_ipstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:374
basic_ipstream(const std::string &command, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:389
~basic_ipstream()
Destructor.
Definition: pstream.h:438
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Start a process.
Definition: pstream.h:467
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:371
basic_ipstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:490
basic_ipstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:479
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:368
Class template for Output PStreams.
Definition: pstream.h:512
void open(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Start a process.
Definition: pstream.h:625
basic_opstream(const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:573
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:556
basic_opstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:526
void open(const std::string &command, pmode mode=pstdin)
Start a process.
Definition: pstream.h:609
basic_opstream(const std::string &command, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:541
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:520
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:523
~basic_opstream()
Destructor.
Definition: pstream.h:597
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:993
Class template for Bidirectional PStreams.
Definition: pstream.h:652
basic_pstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:666
~basic_pstream()
Destructor.
Definition: pstream.h:737
basic_pstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:681
basic_pstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:713
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:765
basic_pstream & out()
Set streambuf to read from process' stdout.
Definition: pstream.h:777
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:696
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:663
basic_pstream & err()
Set streambuf to read from process' stderr.
Definition: pstream.h:788
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:749
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:660
Class template for stream buffer.
Definition: pstream.h:104
fd_type & rpipe(buf_read_src which)
Return the file descriptor for the specified input pipe.
Definition: pstream.h:2007
basic_pstreambuf * killpg(int signal=SIGTERM)
Send a signal to the process' process group.
Definition: pstream.h:1641
basic_pstreambuf * open(const std::string &command, pmode mode)
Initialise the stream buffer with command.
Definition: pstream.h:1113
void close_fd(pstreams::fd_type &fd)
Helper function to close a file descriptor.
Definition: pstream.h:1160
int status() const
Return the exit status of the process.
Definition: pstream.h:1685
basic_pstreambuf * open(const std::string &file, const argv_type &argv, pmode mode)
Initialise the stream buffer with file and argv.
Definition: pstream.h:1215
std::streamsize xsputn(const char_type *s, std::streamsize n)
Insert multiple characters into the pipe.
Definition: pstream.h:1788
std::streamsize read(char_type *s, std::streamsize n)
Extract a sequence of characters from the pipe.
Definition: pstream.h:1974
std::streamsize write(const char_type *s, std::streamsize n)
Insert a sequence of characters into the pipe.
Definition: pstream.h:1951
~basic_pstreambuf()
Destructor.
Definition: pstream.h:1079
int_type overflow(int_type c)
Transfer characters to the pipe when character buffer overflows.
Definition: pstream.h:1763
int sync()
Write any buffered characters to the stream.
Definition: pstream.h:1776
basic_pstreambuf * kill(int signal=SIGTERM)
Send a signal to the process.
Definition: pstream.h:1606
void peof()
Close the pipe connected to the process' stdin.
Definition: pstream.h:1706
pid_t fork(pmode mode)
Initialise pipes and fork process.
Definition: pstream.h:1321
basic_pstreambuf * close()
Close the stream buffer and wait for the process to exit.
Definition: pstream.h:1438
basic_pstreambuf(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the buffer with file and argv.
Definition: pstream.h:1059
int error() const
Return the error number (errno) for the most recent failed operation.
Definition: pstream.h:1695
buf_read_src
Enumerated type to indicate whether stdout or stderr is to be read.
Definition: pstream.h:214
void close_fd_array(pstreams::fd_type(&fds)[N])
Helper function to close an array of file descriptors.
Definition: pstream.h:1178
fd_type & wpipe()
Return the file descriptor for the output pipe.
Definition: pstream.h:1991
bool exited()
Report whether the process has exited.
Definition: pstream.h:1672
bool empty_buffer()
Writes buffered characters to the process' stdin pipe.
Definition: pstream.h:1811
fd_type fd_t
Definition: pstream.h:113
basic_pstreambuf(const std::string &command, pmode mode)
Constructor that initialises the buffer with command.
Definition: pstream.h:1036
char_type * rbuffer()
Return the active input buffer.
Definition: pstream.h:2015
std::streamsize showmanyc()
Report how many characters can be read from active input without blocking.
Definition: pstream.h:1870
bool read_err(bool readerr=true)
Change active input source.
Definition: pstream.h:1740
bool fill_buffer(bool non_blocking=false)
Definition: pstream.h:1892
int_type pbackfail(int_type c=traits_type::eof())
Make a character available to be returned by the next extraction.
Definition: pstream.h:1855
fd_type & rpipe()
Return the file descriptor for the active input pipe.
Definition: pstream.h:1999
basic_pstreambuf()
Default constructor.
Definition: pstream.h:1015
bool is_open() const
Report whether the stream buffer has been initialised.
Definition: pstream.h:1725
int_type underflow()
Transfer characters from the pipe when the character buffer is empty.
Definition: pstream.h:1837
int wait(bool nohang=false)
Wait for the child process to exit.
Definition: pstream.h:1563
Class template for Restricted PStreams.
Definition: pstream.h:823
istream_type & err()
Obtain a reference to the istream that reads the process' stderr.
Definition: pstream.h:959
~basic_rpstream()
Destructor.
Definition: pstream.h:906
basic_rpstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:838
basic_rpstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:853
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:934
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:918
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:835
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:832
basic_rpstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:885
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:868
istream_type & out()
Obtain a reference to the istream that reads the process' stdout.
Definition: pstream.h:947
Class template for common base class.
Definition: pstream.h:280
pstream_common()
Default constructor.
Definition: pstream.h:2036
void do_open(const std::string &file, const argv_type &argv, pmode mode)
Start a process.
Definition: pstream.h:2127
void do_open(const std::string &command, pmode mode)
Start a process.
Definition: pstream.h:2110
pstream_common(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:2074
streambuf_type * rdbuf() const
Return a pointer to the stream buffer.
Definition: pstream.h:2167
streambuf_type buf_
The stream buffer.
Definition: pstream.h:333
virtual ~pstream_common()=0
Pure virtual destructor.
Definition: pstream.h:2096
bool is_open() const
Report whether the stream's buffer has been initialised.
Definition: pstream.h:2150
pstream_common(const std::string &command, pmode mode)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:2054
std::string command_
The command used to start the process.
Definition: pstream.h:332
void close()
Close the pipe.
Definition: pstream.h:2138
const std::string & command() const
Return the command used to initialise the stream.
Definition: pstream.h:2158
All PStreams classes are declared in namespace redi.
basic_pstreambuf< char > pstreambuf
Type definition for common template specialisation.
Definition: pstream.h:968
basic_ipstream< char > ipstream
Type definition for common template specialisation.
Definition: pstream.h:970
basic_rpstream< char > rpstream
Type definition for common template specialisation.
Definition: pstream.h:976
basic_opstream< char > opstream
Type definition for common template specialisation.
Definition: pstream.h:972
basic_pstream< char > pstream
Type definition for common template specialisation.
Definition: pstream.h:974
Common base class providing constants and typenames.
Definition: pstream.h:77
std::ios_base::openmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:79
static const pmode pstderr
Read from stderr.
Definition: pstream.h:89
static const pmode pstdin
Write to stdin.
Definition: pstream.h:87
static const pmode newpg
Create a new process group for the child process.
Definition: pstream.h:92
static const pmode pstdout
Read from stdout.
Definition: pstream.h:88
int fd_type
Type used for file descriptors.
Definition: pstream.h:85
std::vector< std::string > argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:82