PStreams
pstream.h
Go to the documentation of this file.
1// PStreams - POSIX Process I/O for C++
2
3// Copyright (C) 2001 - 2020 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// SPDX-License-Identifier: BSL-1.0
9
19#ifndef REDI_PSTREAM_H_SEEN
20#define REDI_PSTREAM_H_SEEN
21
22#include <ios>
23#include <streambuf>
24#include <istream>
25#include <ostream>
26#include <string>
27#include <vector>
28#include <algorithm> // for min()
29#include <cerrno> // for errno
30#include <cstddef> // for size_t, NULL
31#include <cstdlib> // for exit()
32#include <sys/types.h> // for pid_t
33#include <sys/wait.h> // for waitpid()
34#include <sys/ioctl.h> // for ioctl() and FIONREAD
35#if defined(__sun)
36# include <sys/filio.h> // for FIONREAD on Solaris 2.5
37#endif
38#include <unistd.h> // for pipe() fork() exec() and filedes functions
39#include <signal.h> // for kill()
40#include <fcntl.h> // for fcntl()
41#if REDI_EVISCERATE_PSTREAMS
42# include <stdio.h> // for FILE, fdopen()
43#endif
44
45
47#define PSTREAMS_VERSION 0x0103 // 1.0.3
48
62namespace redi
63{
65 struct pstreams
66 {
68 typedef std::ios_base::openmode pmode;
69
71 typedef std::vector<std::string> argv_type;
72
74 typedef int fd_type;
75
76 static const pmode pstdin = std::ios_base::out;
77 static const pmode pstdout = std::ios_base::in;
78 static const pmode pstderr = std::ios_base::app;
79
81 static const pmode newpg = std::ios_base::trunc;
82
83 protected:
84 enum { bufsz = 32 };
85 enum { pbsz = 2 };
86
87#if __cplusplus >= 201103L
88 template<typename T>
89 using stringable = decltype((void)std::string(std::declval<const T&>()));
90#endif
91 };
92
94 template <typename CharT, typename Traits = std::char_traits<CharT> >
96 : public std::basic_streambuf<CharT, Traits>
97 , public pstreams
98 {
99 public:
100 // Type definitions for dependent types
101 typedef CharT char_type;
102 typedef Traits traits_type;
103 typedef typename traits_type::int_type int_type;
104 typedef typename traits_type::off_type off_type;
105 typedef typename traits_type::pos_type pos_type;
107 typedef fd_type fd_t;
108
111
113 basic_pstreambuf(const std::string& cmd, pmode mode);
114
116 basic_pstreambuf( const std::string& file,
117 const argv_type& argv,
118 pmode mode );
119
120#if __cplusplus >= 201103L
122 basic_pstreambuf& operator=(basic_pstreambuf&&) noexcept;
123 void swap(basic_pstreambuf&) noexcept;
124#endif
125
128
131 open(const std::string& cmd, 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:
257#if __cplusplus >= 201103L
258 using basic_streambuf = std::basic_streambuf<char_type, traits_type>;
259#else
261 basic_pstreambuf& operator=(const basic_pstreambuf&);
262#endif
263
264 void
265 init_rbuffers();
266
267 pid_t ppid_; // pid of process
268 fd_type wpipe_; // pipe used to write to process' stdin
269 fd_type rpipe_[2]; // two pipes to read from, stdout and stderr
270 char_type* wbuffer_;
271 char_type* rbuffer_[2];
272 char_type* rbufstate_[3];
274 buf_read_src rsrc_;
275 int status_; // hold exit status of child process
276 int error_; // hold errno if fork() or exec() fails
277 };
278
280 template <typename CharT, typename Traits = std::char_traits<CharT> >
282 : virtual public std::basic_ios<CharT, Traits>
283 , virtual public pstreams
284 {
285 protected:
287 typedef std::basic_ios<CharT, Traits> ios_type;
288
289 typedef pstreams::pmode pmode;
290 typedef pstreams::argv_type argv_type;
291
294
296 pstream_common(const std::string& cmd, pmode mode);
297
299 pstream_common(const std::string& file, const argv_type& argv, pmode mode);
300
302 virtual
304
305#if __cplusplus >= 201103L
306 pstream_common(pstream_common&& rhs) noexcept
307 : command_(std::move(rhs.command_))
308 , buf_(std::move(rhs.buf_))
309 {
310 /* derived class is responsible for ios_type::move(rhs) happening */
311 }
312
314 operator=(pstream_common&& rhs) noexcept
315 {
316 command_ = std::move(rhs.command_);
317 buf_ = std::move(rhs.buf_);
318 return *this;
319 }
320
321 void
322 swap(pstream_common& rhs) noexcept
323 {
324 /* derived class is responsible for ios_type::swap(rhs) happening */
325 command_.swap(rhs.command_);
326 buf_.swap(rhs.buf_);
327 }
328#endif // C++11
329
331 void
332 do_open(const std::string& cmd, pmode mode);
333
335 void
336 do_open(const std::string& file, const argv_type& argv, pmode mode);
337
338 public:
341 int
343
345 bool
346 is_open() const;
347
349 const std::string&
350 command() const;
351
354 rdbuf() const;
355
356#if REDI_EVISCERATE_PSTREAMS
358 std::size_t
359 fopen(FILE*& in, FILE*& out, FILE*& err);
360#endif
361
362 protected:
363 std::string command_;
365 };
366
367
378 template <typename CharT, typename Traits = std::char_traits<CharT> >
380 : public std::basic_istream<CharT, Traits>
381 , public pstream_common<CharT, Traits>
382 , virtual public pstreams
383 {
384 typedef std::basic_istream<CharT, Traits> istream_type;
386
387 using pbase_type::buf_; // declare name in this scope
388
389 // Ensure a basic_ipstream will read from at least one pipe
390 pmode readable(pmode mode)
391 {
392 if (!(mode & (pstdout|pstderr)))
393 mode |= pstdout;
394 return mode;
395 }
396
397 public:
399 typedef typename pbase_type::pmode pmode;
400
402 typedef typename pbase_type::argv_type argv_type;
403
406 : istream_type(NULL), pbase_type()
407 { }
408
419 explicit
420 basic_ipstream(const std::string& cmd, pmode mode = pstdout)
421 : istream_type(NULL), pbase_type(cmd, readable(mode))
422 { }
423
435 basic_ipstream( const std::string& file,
436 const argv_type& argv,
437 pmode mode = pstdout )
438 : istream_type(NULL), pbase_type(file, argv, readable(mode))
439 { }
440
451 explicit
453 : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode))
454 { }
455
456#if __cplusplus >= 201103L
457 template<typename T, typename = stringable<T>>
458 explicit
459 basic_ipstream(std::initializer_list<T> args, pmode mode = pstdout)
460 : basic_ipstream(argv_type(args.begin(), args.end()), mode)
461 { }
462
464 : istream_type(std::move(rhs))
465 , pbase_type(std::move(rhs))
466 { istream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
467
469 operator=(basic_ipstream&& rhs)
470 {
471 istream_type::operator=(std::move(rhs));
472 pbase_type::operator=(std::move(rhs));
473 return *this;
474 }
475
476 void
477 swap(basic_ipstream& rhs)
478 {
479 istream_type::swap(rhs);
480 pbase_type::swap(rhs);
481 }
482#endif // C++11
483
490 { }
491
501 void
502 open(const std::string& cmd, pmode mode = pstdout)
503 {
504 this->do_open(cmd, readable(mode));
505 }
506
517 void
518 open( const std::string& file,
519 const argv_type& argv,
520 pmode mode = pstdout )
521 {
522 this->do_open(file, argv, readable(mode));
523 }
524
531 {
532 this->buf_.read_err(false);
533 return *this;
534 }
535
542 {
543 this->buf_.read_err(true);
544 return *this;
545 }
546 };
547
548
558 template <typename CharT, typename Traits = std::char_traits<CharT> >
560 : public std::basic_ostream<CharT, Traits>
561 , public pstream_common<CharT, Traits>
562 , virtual public pstreams
563 {
564 typedef std::basic_ostream<CharT, Traits> ostream_type;
566
567 using pbase_type::buf_; // declare name in this scope
568
569 public:
571 typedef typename pbase_type::pmode pmode;
572
574 typedef typename pbase_type::argv_type argv_type;
575
578 : ostream_type(NULL), pbase_type()
579 { }
580
591 explicit
592 basic_opstream(const std::string& cmd, pmode mode = pstdin)
593 : ostream_type(NULL), pbase_type(cmd, mode|pstdin)
594 { }
595
607 basic_opstream( const std::string& file,
608 const argv_type& argv,
609 pmode mode = pstdin )
610 : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
611 { }
612
623 explicit
625 : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin)
626 { }
627
628#if __cplusplus >= 201103L
636 template<typename T, typename = stringable<T>>
637 explicit
638 basic_opstream(std::initializer_list<T> args, pmode mode = pstdin)
639 : basic_opstream(argv_type(args.begin(), args.end()), mode)
640 { }
641
643 : ostream_type(std::move(rhs))
644 , pbase_type(std::move(rhs))
645 { ostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
646
648 operator=(basic_opstream&& rhs)
649 {
650 ostream_type::operator=(std::move(rhs));
651 pbase_type::operator=(std::move(rhs));
652 return *this;
653 }
654
655 void
656 swap(basic_opstream& rhs)
657 {
658 ostream_type::swap(rhs);
659 pbase_type::swap(rhs);
660 }
661#endif // C++11
662
669
679 void
680 open(const std::string& cmd, pmode mode = pstdin)
681 {
682 this->do_open(cmd, mode|pstdin);
683 }
684
695 void
696 open( const std::string& file,
697 const argv_type& argv,
698 pmode mode = pstdin)
699 {
700 this->do_open(file, argv, mode|pstdin);
701 }
702 };
703
704
718 template <typename CharT, typename Traits = std::char_traits<CharT> >
720 : public std::basic_iostream<CharT, Traits>
721 , public pstream_common<CharT, Traits>
722 , virtual public pstreams
723 {
724 typedef std::basic_iostream<CharT, Traits> iostream_type;
726
727 using pbase_type::buf_; // declare name in this scope
728
729 public:
731 typedef typename pbase_type::pmode pmode;
732
734 typedef typename pbase_type::argv_type argv_type;
735
738 : iostream_type(NULL), pbase_type()
739 { }
740
751 explicit
752 basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin)
753 : iostream_type(NULL), pbase_type(cmd, mode)
754 { }
755
767 basic_pstream( const std::string& file,
768 const argv_type& argv,
769 pmode mode = pstdout|pstdin )
770 : iostream_type(NULL), pbase_type(file, argv, mode)
771 { }
772
783 explicit
785 : iostream_type(NULL), pbase_type(argv.at(0), argv, mode)
786 { }
787
788#if __cplusplus >= 201103L
796 template<typename T, typename = stringable<T>>
797 explicit
798 basic_pstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
799 : basic_pstream(argv_type(l.begin(), l.end()), mode)
800 { }
801
803 : iostream_type(std::move(rhs))
804 , pbase_type(std::move(rhs))
805 { iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
806
808 operator=(basic_pstream&& rhs)
809 {
810 iostream_type::operator=(std::move(rhs));
811 pbase_type::operator=(std::move(rhs));
812 return *this;
813 }
814
815 void
816 swap(basic_pstream& rhs)
817 {
818 iostream_type::swap(rhs);
819 pbase_type::swap(rhs);
820 }
821#endif // C++11
822
829
839 void
840 open(const std::string& cmd, pmode mode = pstdout|pstdin)
841 {
842 this->do_open(cmd, mode);
843 }
844
855 void
856 open( const std::string& file,
857 const argv_type& argv,
858 pmode mode = pstdout|pstdin )
859 {
860 this->do_open(file, argv, mode);
861 }
862
869 {
870 this->buf_.read_err(false);
871 return *this;
872 }
873
880 {
881 this->buf_.read_err(true);
882 return *this;
883 }
884 };
885
886
908 template <typename CharT, typename Traits = std::char_traits<CharT> >
910 : public std::basic_ostream<CharT, Traits>
911 , private std::basic_istream<CharT, Traits>
912 , private pstream_common<CharT, Traits>
913 , virtual public pstreams
914 {
915 typedef std::basic_ostream<CharT, Traits> ostream_type;
916 typedef std::basic_istream<CharT, Traits> istream_type;
918
919 using pbase_type::buf_; // declare name in this scope
920
921 public:
923 typedef typename pbase_type::pmode pmode;
924
926 typedef typename pbase_type::argv_type argv_type;
927
930 : ostream_type(NULL), istream_type(NULL), pbase_type()
931 { }
932
943 explicit
944 basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin)
945 : ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode)
946 { }
947
959 basic_rpstream( const std::string& file,
960 const argv_type& argv,
961 pmode mode = pstdout|pstdin )
962 : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
963 { }
964
975 explicit
977 : ostream_type(NULL), istream_type(NULL)
978 , pbase_type(argv.at(0), argv, mode)
979 { }
980
981#if __cplusplus >= 201103L
989 template<typename T, typename = stringable<T>>
990 explicit
991 basic_rpstream(std::initializer_list<T> l, pmode mode = pstdout|pstdin)
992 : basic_rpstream(argv_type(l.begin(), l.end()), mode)
993 { }
994
995 // TODO: figure out how to move istream and ostream bases separately,
996 // but so the virtual basic_ios base is only modified once.
997#if 0
999 : iostream_type(std::move(rhs))
1000 , pbase_type(std::move(rhs))
1001 { iostream_type::set_rdbuf(std::addressof(pbase_type::buf_)); }
1002
1004 operator=(basic_rpstream&& rhs)
1005 {
1006 iostream_type::operator=(std::move(rhs));
1007 pbase_type::operator=(std::move(rhs));
1008 return *this;
1009 }
1010
1011 void
1012 swap(basic_rpstream& rhs)
1013 {
1014 iostream_type::swap(rhs);
1015 pbase_type::swap(rhs);
1016 }
1017#endif
1018#endif // C++11
1019
1022
1032 void
1033 open(const std::string& cmd, pmode mode = pstdout|pstdin)
1034 {
1035 this->do_open(cmd, mode);
1036 }
1037
1048 void
1049 open( const std::string& file,
1050 const argv_type& argv,
1051 pmode mode = pstdout|pstdin )
1052 {
1053 this->do_open(file, argv, mode);
1054 }
1055
1061 istream_type&
1063 {
1064 this->buf_.read_err(false);
1065 return *this;
1066 }
1067
1073 istream_type&
1075 {
1076 this->buf_.read_err(true);
1077 return *this;
1078 }
1079 };
1080
1081
1092
1093
1106 template <typename C, typename T>
1107 inline std::basic_ostream<C,T>&
1108 peof(std::basic_ostream<C,T>& s)
1109 {
1110 typedef basic_pstreambuf<C,T> pstreambuf_type;
1111 if (pstreambuf_type* p = dynamic_cast<pstreambuf_type*>(s.rdbuf()))
1112 p->peof();
1113 return s;
1114 }
1115
1116
1117 /*
1118 * member definitions for pstreambuf
1119 */
1120
1121
1128 template <typename C, typename T>
1129 inline
1131 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1132 , wpipe_(-1)
1133 , wbuffer_()
1134 , rbuffer_()
1135 , rbufstate_()
1136 , rsrc_(rsrc_out)
1137 , status_(-1)
1138 , error_(0)
1139 {
1140 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1141 }
1142
1151 template <typename C, typename T>
1152 inline
1154 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1155 , wpipe_(-1)
1156 , wbuffer_()
1157 , rbuffer_()
1158 , rbufstate_()
1159 , rsrc_(rsrc_out)
1160 , status_(-1)
1161 , error_(0)
1162 {
1163 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1164 open(cmd, mode);
1165 }
1166
1176 template <typename C, typename T>
1177 inline
1179 const argv_type& argv,
1180 pmode mode )
1181 : ppid_(-1) // initialise to -1 to indicate no process run yet.
1182 , wpipe_(-1)
1183 , wbuffer_()
1184 , rbuffer_()
1185 , rbufstate_()
1186 , rsrc_(rsrc_out)
1187 , status_(-1)
1188 , error_(0)
1189 {
1190 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1191 open(file, argv, mode);
1192 }
1193
1198 template <typename C, typename T>
1199 inline
1201 {
1202 close();
1203 }
1204
1205#if __cplusplus >= 201103L
1209 template <typename C, typename T>
1210 inline
1212 : basic_streambuf(static_cast<const basic_streambuf&>(rhs))
1213 , ppid_(rhs.ppid_)
1214 , wpipe_(rhs.wpipe_)
1215 , rpipe_{rhs.rpipe_[0], rhs.rpipe_[1]}
1216 , wbuffer_(rhs.wbuffer_)
1217 , rbuffer_{rhs.rbuffer_[0], rhs.rbuffer_[1]}
1218 , rbufstate_{rhs.rbufstate_[0], rhs.rbufstate_[1], rhs.rbufstate_[2]}
1219 , rsrc_(rhs.rsrc_)
1220 , status_(rhs.status_)
1221 , error_(rhs.error_)
1222 {
1223 rhs.ppid_ = -1;
1224 rhs.wpipe_ = -1;
1225 rhs.rpipe_[0] = rhs.rpipe_[1] = -1;
1226 rhs.wbuffer_ = nullptr;
1227 rhs.rbuffer_[0] = rhs.rbuffer_[1] = nullptr;
1228 rhs.rbufstate_[0] = rhs.rbufstate_[1] = rhs.rbufstate_[2] = nullptr;
1229 rhs.rsrc_ = rsrc_out;
1230 rhs.status_ = -1;
1231 rhs.error_ = 0;
1232 rhs.setg(nullptr, nullptr, nullptr);
1233 rhs.setp(nullptr, nullptr);
1234 }
1235
1236 template <typename C, typename T>
1237 inline basic_pstreambuf<C,T>&
1238 basic_pstreambuf<C,T>::operator=( basic_pstreambuf&& rhs ) noexcept
1239 {
1240 close();
1241 basic_streambuf::operator=(static_cast<const basic_streambuf&>(rhs));
1242 swap(rhs);
1243 return *this;
1244 }
1245
1246 template <typename C, typename T>
1247 inline void
1248 basic_pstreambuf<C,T>::swap( basic_pstreambuf& rhs ) noexcept
1249 {
1250 basic_streambuf::swap(static_cast<basic_streambuf&>(rhs));
1251 std::swap(ppid_, rhs.ppid_);
1252 std::swap(wpipe_, rhs.wpipe_);
1253 std::swap(rpipe_, rhs.rpipe_);
1254 std::swap(wbuffer_, rhs.wbuffer_);
1255 std::swap(rbuffer_, rhs.rbuffer_);
1256 std::swap(rbufstate_, rhs.rbufstate_);
1257 std::swap(rsrc_, rhs.rsrc_);
1258 std::swap(status_, rhs.status_);
1259 std::swap(error_, rhs.error_);
1260 }
1261#endif // C++11
1262
1290 template <typename C, typename T>
1291 basic_pstreambuf<C,T>*
1292 basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
1293 {
1294 const char * shell_path = "/bin/sh";
1295#if 0
1296 const std::string argv[] = { "sh", "-c", command };
1297 return this->open(shell_path, argv_type(argv, argv+3), mode);
1298#else
1299 basic_pstreambuf<C,T>* ret = NULL;
1300
1301 if (!is_open())
1302 {
1303 switch(fork(mode))
1304 {
1305 case 0 :
1306 // this is the new process, exec command
1307 ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
1308
1309 // can only reach this point if exec() failed
1310
1311 // parent can get exit code from waitpid()
1312 ::_exit(errno);
1313 // using std::exit() would make static dtors run twice
1314
1315 case -1 :
1316 // couldn't fork, error already handled in pstreambuf::fork()
1317 break;
1318
1319 default :
1320 // this is the parent process
1321 // activate buffers
1322 create_buffers(mode);
1323 ret = this;
1324 }
1325 }
1326 return ret;
1327#endif
1328 }
1329
1338 inline void
1340 {
1341 if (fd >= 0 && ::close(fd) == 0)
1342 fd = -1;
1343 }
1344
1355 template <int N>
1356 inline void
1358 {
1359 for (std::size_t i = 0; i < N; ++i)
1360 close_fd(fds[i]);
1361 }
1362
1392 template <typename C, typename T>
1394 basic_pstreambuf<C,T>::open( const std::string& file,
1395 const argv_type& argv,
1396 pmode mode )
1397 {
1398 basic_pstreambuf<C,T>* ret = NULL;
1399
1400 if (!is_open())
1401 {
1402 // constants for read/write ends of pipe
1403 enum { RD, WR };
1404
1405 // open another pipe and set close-on-exec
1406 fd_type ck_exec[] = { -1, -1 };
1407 if (-1 == ::pipe(ck_exec)
1408 || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
1409 || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
1410 {
1411 error_ = errno;
1412 close_fd_array(ck_exec);
1413 }
1414 else
1415 {
1416 switch(fork(mode))
1417 {
1418 case 0 :
1419 // this is the new process, exec command
1420 {
1421 char** arg_v = new char*[argv.size()+1];
1422 for (std::size_t i = 0; i < argv.size(); ++i)
1423 {
1424 const std::string& src = argv[i];
1425 char*& dest = arg_v[i];
1426 dest = new char[src.size()+1];
1427 dest[ src.copy(dest, src.size()) ] = '\0';
1428 }
1429 arg_v[argv.size()] = NULL;
1430
1431 ::execvp(file.c_str(), arg_v);
1432
1433 // can only reach this point if exec() failed
1434
1435 // parent can get error code from ck_exec pipe
1436 error_ = errno;
1437
1438 while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1
1439 && errno == EINTR)
1440 { }
1441
1442 ::close(ck_exec[WR]);
1443 ::close(ck_exec[RD]);
1444
1445 ::_exit(error_);
1446 // using std::exit() would make static dtors run twice
1447 }
1448
1449 case -1 :
1450 // couldn't fork, error already handled in pstreambuf::fork()
1451 close_fd_array(ck_exec);
1452 break;
1453
1454 default :
1455 // this is the parent process
1456
1457 // check child called exec() successfully
1458 ::close(ck_exec[WR]);
1459 switch (::read(ck_exec[RD], &error_, sizeof(error_)))
1460 {
1461 case 0:
1462 // activate buffers
1463 create_buffers(mode);
1464 ret = this;
1465 break;
1466 case -1:
1467 error_ = errno;
1468 break;
1469 default:
1470 // error_ contains error code from child
1471 // call wait() to clean up and set ppid_ to 0
1472 this->wait();
1473 break;
1474 }
1475 ::close(ck_exec[RD]);
1476 }
1477 }
1478 }
1479 return ret;
1480 }
1481
1498 template <typename C, typename T>
1499 pid_t
1501 {
1502 pid_t pid = -1;
1503
1504 // Three pairs of file descriptors, for pipes connected to the
1505 // process' stdin, stdout and stderr
1506 // (stored in a single array so close_fd_array() can close all at once)
1507 fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
1508 fd_type* const pin = fd;
1509 fd_type* const pout = fd+2;
1510 fd_type* const perr = fd+4;
1511
1512 // constants for read/write ends of pipe
1513 enum { RD, WR };
1514
1515 // N.B.
1516 // For the pstreambuf pin is an output stream and
1517 // pout and perr are input streams.
1518
1519 if (!error_ && mode&pstdin && ::pipe(pin))
1520 error_ = errno;
1521
1522 if (!error_ && mode&pstdout && ::pipe(pout))
1523 error_ = errno;
1524
1525 if (!error_ && mode&pstderr && ::pipe(perr))
1526 error_ = errno;
1527
1528 if (!error_)
1529 {
1530 pid = ::fork();
1531 switch (pid)
1532 {
1533 case 0 :
1534 {
1535 // this is the new process
1536
1537 // for each open pipe close one end and redirect the
1538 // respective standard stream to the other end
1539
1540 if (*pin >= 0)
1541 {
1542 ::close(pin[WR]);
1543 ::dup2(pin[RD], STDIN_FILENO);
1544 ::close(pin[RD]);
1545 }
1546 if (*pout >= 0)
1547 {
1548 ::close(pout[RD]);
1549 ::dup2(pout[WR], STDOUT_FILENO);
1550 ::close(pout[WR]);
1551 }
1552 if (*perr >= 0)
1553 {
1554 ::close(perr[RD]);
1555 ::dup2(perr[WR], STDERR_FILENO);
1556 ::close(perr[WR]);
1557 }
1558
1559#ifdef _POSIX_JOB_CONTROL
1560 if (mode&newpg)
1561 ::setpgid(0, 0); // Change to a new process group
1562#endif
1563
1564 break;
1565 }
1566 case -1 :
1567 {
1568 // couldn't fork for some reason
1569 error_ = errno;
1570 // close any open pipes
1571 close_fd_array(fd);
1572 break;
1573 }
1574 default :
1575 {
1576 // this is the parent process, store process' pid
1577 ppid_ = pid;
1578
1579 // store one end of open pipes and close other end
1580 if (*pin >= 0)
1581 {
1582 wpipe_ = pin[WR];
1583 ::close(pin[RD]);
1584 }
1585 if (*pout >= 0)
1586 {
1587 rpipe_[rsrc_out] = pout[RD];
1588 ::close(pout[WR]);
1589 }
1590 if (*perr >= 0)
1591 {
1592 rpipe_[rsrc_err] = perr[RD];
1593 ::close(perr[WR]);
1594 }
1595 }
1596 }
1597 }
1598 else
1599 {
1600 // close any pipes we opened before failure
1601 close_fd_array(fd);
1602 }
1603 return pid;
1604 }
1605
1615 template <typename C, typename T>
1618 {
1619 const bool running = is_open();
1620
1621 sync(); // this might call wait() and reap the child process
1622
1623 // rather than trying to work out whether or not we need to clean up
1624 // just do it anyway, all cleanup functions are safe to call twice.
1625
1626 destroy_buffers(pstdin|pstdout|pstderr);
1627
1628 // close pipes before wait() so child gets EOF/SIGPIPE
1629 close_fd(wpipe_);
1630 close_fd_array(rpipe_);
1631
1632 do
1633 {
1634 error_ = 0;
1635 } while (wait() == -1 && error() == EINTR);
1636
1637 return running ? this : NULL;
1638 }
1639
1644 template <typename C, typename T>
1645#if __cplusplus >= 201402L && __has_cpp_attribute(deprecated)
1646 [[deprecated]]
1647#elif __GNUC__
1648 __attribute__((deprecated))
1649#endif
1650 inline void
1652 {
1653 rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1654 rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
1655 rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
1656 }
1657
1658 template <typename C, typename T>
1659 void
1660 basic_pstreambuf<C,T>::create_buffers(pmode mode)
1661 {
1662 if (mode & pstdin)
1663 {
1664 delete[] wbuffer_;
1665 wbuffer_ = new char_type[bufsz];
1666 this->setp(wbuffer_, wbuffer_ + bufsz);
1667 }
1668 if (mode & pstdout)
1669 {
1670 delete[] rbuffer_[rsrc_out];
1671 rbuffer_[rsrc_out] = new char_type[bufsz];
1672 rsrc_ = rsrc_out;
1673 this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
1674 rbuffer_[rsrc_out] + pbsz);
1675 }
1676 if (mode & pstderr)
1677 {
1678 delete[] rbuffer_[rsrc_err];
1679 rbuffer_[rsrc_err] = new char_type[bufsz];
1680 if (!(mode & pstdout))
1681 {
1682 rsrc_ = rsrc_err;
1683 this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
1684 rbuffer_[rsrc_err] + pbsz);
1685 }
1686 }
1687 }
1688
1689 template <typename C, typename T>
1690 void
1691 basic_pstreambuf<C,T>::destroy_buffers(pmode mode)
1692 {
1693 if (mode & pstdin)
1694 {
1695 this->setp(NULL, NULL);
1696 delete[] wbuffer_;
1697 wbuffer_ = NULL;
1698 }
1699 if (mode & pstdout)
1700 {
1701 if (rsrc_ == rsrc_out)
1702 this->setg(NULL, NULL, NULL);
1703 delete[] rbuffer_[rsrc_out];
1704 rbuffer_[rsrc_out] = NULL;
1705 }
1706 if (mode & pstderr)
1707 {
1708 if (rsrc_ == rsrc_err)
1709 this->setg(NULL, NULL, NULL);
1710 delete[] rbuffer_[rsrc_err];
1711 rbuffer_[rsrc_err] = NULL;
1712 }
1713 }
1714
1715 template <typename C, typename T>
1717 basic_pstreambuf<C,T>::switch_read_buffer(buf_read_src src)
1718 {
1719 if (rsrc_ != src)
1720 {
1721 char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
1722 this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
1723 for (std::size_t i = 0; i < 3; ++i)
1724 rbufstate_[i] = tmpbufstate[i];
1725 rsrc_ = src;
1726 }
1727 return rsrc_;
1728 }
1729
1746 template <typename C, typename T>
1747 int
1749 {
1750 int child_exited = -1;
1751 if (is_open())
1752 {
1753 int exit_status;
1754 switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0))
1755 {
1756 case 0 :
1757 // nohang was true and process has not exited
1758 child_exited = 0;
1759 break;
1760 case -1 :
1761 error_ = errno;
1762 break;
1763 default :
1764 // process has exited
1765 ppid_ = 0;
1766 status_ = exit_status;
1767 child_exited = 1;
1768 // Close wpipe, would get SIGPIPE if we used it.
1769 destroy_buffers(pstdin);
1770 close_fd(wpipe_);
1771 // Must free read buffers and pipes on destruction
1772 // or next call to open()/close()
1773 break;
1774 }
1775 }
1776 return child_exited;
1777 }
1778
1789 template <typename C, typename T>
1790 inline basic_pstreambuf<C,T>*
1792 {
1793 basic_pstreambuf<C,T>* ret = NULL;
1794 if (is_open())
1795 {
1796 if (::kill(ppid_, signal))
1797 error_ = errno;
1798 else
1799 {
1800#if 0
1801 // TODO call exited() to check for exit and clean up? leave to user?
1802 if (signal==SIGTERM || signal==SIGKILL)
1803 this->exited();
1804#endif
1805 ret = this;
1806 }
1807 }
1808 return ret;
1809 }
1810
1824 template <typename C, typename T>
1825 inline basic_pstreambuf<C,T>*
1827 {
1828 basic_pstreambuf<C,T>* ret = NULL;
1829#ifdef _POSIX_JOB_CONTROL
1830 if (is_open())
1831 {
1832 pid_t pgid = ::getpgid(ppid_);
1833 if (pgid == -1)
1834 error_ = errno;
1835 else if (pgid == ::getpgrp())
1836 error_ = EPERM; // Don't commit suicide
1837 else if (::killpg(pgid, signal))
1838 error_ = errno;
1839 else
1840 ret = this;
1841 }
1842#else
1843 error_ = ENOTSUP;
1844#endif
1845 return ret;
1846 }
1847
1855 template <typename C, typename T>
1856 inline bool
1858 {
1859 return ppid_ == 0 || wait(true)==1;
1860 }
1861
1862
1868 template <typename C, typename T>
1869 inline int
1871 {
1872 return status_;
1873 }
1874
1878 template <typename C, typename T>
1879 inline int
1881 {
1882 return error_;
1883 }
1884
1889 template <typename C, typename T>
1890 inline void
1892 {
1893 sync();
1894 destroy_buffers(pstdin);
1895 close_fd(wpipe_);
1896 }
1897
1908 template <typename C, typename T>
1909 inline bool
1911 {
1912 return ppid_ > 0;
1913 }
1914
1923 template <typename C, typename T>
1924 inline bool
1926 {
1927 buf_read_src src = readerr ? rsrc_err : rsrc_out;
1928 if (rpipe_[src]>=0)
1929 {
1930 switch_read_buffer(src);
1931 return true;
1932 }
1933 return false;
1934 }
1935
1946 template <typename C, typename T>
1947 typename basic_pstreambuf<C,T>::int_type
1949 {
1950 if (!empty_buffer())
1951 return traits_type::eof();
1952 else if (!traits_type::eq_int_type(c, traits_type::eof()))
1953 return this->sputc(c);
1954 else
1955 return traits_type::not_eof(c);
1956 }
1957
1958
1959 template <typename C, typename T>
1960 int
1962 {
1963 return !exited() && empty_buffer() ? 0 : -1;
1964 }
1965
1971 template <typename C, typename T>
1972 std::streamsize
1973 basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
1974 {
1975 std::streamsize done = 0;
1976 while (done < n)
1977 {
1978 if (std::streamsize nbuf = this->epptr() - this->pptr())
1979 {
1980 nbuf = std::min(nbuf, n - done);
1981 traits_type::copy(this->pptr(), s + done, nbuf);
1982 this->pbump(nbuf);
1983 done += nbuf;
1984 }
1985 else if (!empty_buffer())
1986 break;
1987 }
1988 return done;
1989 }
1990
1994 template <typename C, typename T>
1995 bool
1997 {
1998 const std::streamsize count = this->pptr() - this->pbase();
1999 if (count > 0)
2000 {
2001 const std::streamsize written = this->write(this->wbuffer_, count);
2002 if (written > 0)
2003 {
2004 if (const std::streamsize unwritten = count - written)
2005 traits_type::move(this->pbase(), this->pbase()+written, unwritten);
2006 this->pbump(-written);
2007 return true;
2008 }
2009 }
2010 return false;
2011 }
2012
2020 template <typename C, typename T>
2021 typename basic_pstreambuf<C,T>::int_type
2023 {
2024 if (this->gptr() < this->egptr() || fill_buffer())
2025 return traits_type::to_int_type(*this->gptr());
2026 else
2027 return traits_type::eof();
2028 }
2029
2038 template <typename C, typename T>
2039 typename basic_pstreambuf<C,T>::int_type
2041 {
2042 if (this->gptr() != this->eback())
2043 {
2044 this->gbump(-1);
2045 if (!traits_type::eq_int_type(c, traits_type::eof()))
2046 *this->gptr() = traits_type::to_char_type(c);
2047 return traits_type::not_eof(c);
2048 }
2049 else
2050 return traits_type::eof();
2051 }
2052
2053 template <typename C, typename T>
2054 std::streamsize
2056 {
2057 int avail = 0;
2058 if (sizeof(char_type) == 1)
2059 avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
2060#ifdef FIONREAD
2061 else
2062 {
2063 if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
2064 avail = -1;
2065 else if (avail)
2066 avail /= sizeof(char_type);
2067 }
2068#endif
2069 return std::streamsize(avail);
2070 }
2071
2075 template <typename C, typename T>
2076 bool
2078 {
2079 const std::streamsize pb1 = this->gptr() - this->eback();
2080 const std::streamsize pb2 = pbsz;
2081 const std::streamsize npb = std::min(pb1, pb2);
2082
2083 char_type* const rbuf = rbuffer();
2084
2085 if (npb)
2086 traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
2087
2088 std::streamsize rc = -1;
2089
2090 if (non_blocking)
2091 {
2092 const int flags = ::fcntl(rpipe(), F_GETFL);
2093 if (flags != -1)
2094 {
2095 const bool blocking = !(flags & O_NONBLOCK);
2096 if (blocking)
2097 ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking
2098
2099 error_ = 0;
2100 rc = read(rbuf + pbsz, bufsz - pbsz);
2101
2102 if (rc == -1 && error_ == EAGAIN) // nothing available
2103 rc = 0;
2104 else if (rc == 0) // EOF
2105 rc = -1;
2106
2107 if (blocking)
2108 ::fcntl(rpipe(), F_SETFL, flags); // restore
2109 }
2110 }
2111 else
2112 rc = read(rbuf + pbsz, bufsz - pbsz);
2113
2114 if (rc > 0 || (rc == 0 && non_blocking))
2115 {
2116 this->setg( rbuf + pbsz - npb,
2117 rbuf + pbsz,
2118 rbuf + pbsz + rc );
2119 return true;
2120 }
2121 else
2122 {
2123 this->setg(NULL, NULL, NULL);
2124 return false;
2125 }
2126 }
2127
2135 template <typename C, typename T>
2136 inline std::streamsize
2137 basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
2138 {
2139 std::streamsize nwritten = 0;
2140 if (wpipe() >= 0)
2141 {
2142 nwritten = ::write(wpipe(), s, n * sizeof(char_type));
2143 if (nwritten == -1)
2144 error_ = errno;
2145 else
2146 nwritten /= sizeof(char_type);
2147 }
2148 return nwritten;
2149 }
2150
2158 template <typename C, typename T>
2159 inline std::streamsize
2160 basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
2161 {
2162 std::streamsize nread = 0;
2163 if (rpipe() >= 0)
2164 {
2165 nread = ::read(rpipe(), s, n * sizeof(char_type));
2166 if (nread == -1)
2167 error_ = errno;
2168 else
2169 nread /= sizeof(char_type);
2170 }
2171 return nread;
2172 }
2173
2175 template <typename C, typename T>
2176 inline pstreams::fd_type&
2178 {
2179 return wpipe_;
2180 }
2181
2183 template <typename C, typename T>
2184 inline pstreams::fd_type&
2186 {
2187 return rpipe_[rsrc_];
2188 }
2189
2191 template <typename C, typename T>
2192 inline pstreams::fd_type&
2194 {
2195 return rpipe_[which];
2196 }
2197
2199 template <typename C, typename T>
2200 inline typename basic_pstreambuf<C,T>::char_type*
2202 {
2203 return rbuffer_[rsrc_];
2204 }
2205
2206
2207 /*
2208 * member definitions for pstream_common
2209 */
2210
2220 template <typename C, typename T>
2221 inline
2223 : std::basic_ios<C,T>(NULL)
2224 , command_()
2225 , buf_()
2226 {
2227 this->std::basic_ios<C,T>::rdbuf(&buf_);
2228 }
2229
2238 template <typename C, typename T>
2239 inline
2240 pstream_common<C,T>::pstream_common(const std::string& cmd, pmode mode)
2241 : std::basic_ios<C,T>(NULL)
2242 , command_(cmd)
2243 , buf_()
2244 {
2245 this->std::basic_ios<C,T>::rdbuf(&buf_);
2246 do_open(cmd, mode);
2247 }
2248
2258 template <typename C, typename T>
2259 inline
2260 pstream_common<C,T>::pstream_common( const std::string& file,
2261 const argv_type& argv,
2262 pmode mode )
2263 : std::basic_ios<C,T>(NULL)
2264 , command_(file)
2265 , buf_()
2266 {
2267 this->std::basic_ios<C,T>::rdbuf(&buf_);
2268 do_open(file, argv, mode);
2269 }
2270
2280 template <typename C, typename T>
2281 inline
2283 {
2284 }
2285
2294 template <typename C, typename T>
2295 inline void
2296 pstream_common<C,T>::do_open(const std::string& cmd, pmode mode)
2297 {
2298 if (!buf_.open((command_=cmd), mode))
2299 this->setstate(std::ios_base::failbit);
2300 }
2301
2311 template <typename C, typename T>
2312 inline void
2313 pstream_common<C,T>::do_open( const std::string& file,
2314 const argv_type& argv,
2315 pmode mode )
2316 {
2317 if (!buf_.open((command_=file), argv, mode))
2318 this->setstate(std::ios_base::failbit);
2319 }
2320
2323 template <typename C, typename T>
2324 inline int
2326 {
2327 if (!buf_.close())
2328 this->setstate(std::ios_base::failbit);
2329 return buf_.status();
2330 }
2331
2336 template <typename C, typename T>
2337 inline bool
2339 {
2340 return buf_.is_open();
2341 }
2342
2344 template <typename C, typename T>
2345 inline const std::string&
2347 {
2348 return command_;
2349 }
2350
2352 // TODO document behaviour if buffer replaced.
2353 template <typename C, typename T>
2356 {
2357 return const_cast<streambuf_type*>(&buf_);
2358 }
2359
2360
2361#if REDI_EVISCERATE_PSTREAMS
2394 template <typename C, typename T>
2395 std::size_t
2396 basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
2397 {
2398 in = out = err = NULL;
2399 std::size_t open_files = 0;
2400 if (wpipe() > -1)
2401 {
2402 if ((in = ::fdopen(wpipe(), "w")))
2403 {
2404 open_files |= pstdin;
2405 }
2406 }
2407 if (rpipe(rsrc_out) > -1)
2408 {
2409 if ((out = ::fdopen(rpipe(rsrc_out), "r")))
2410 {
2411 open_files |= pstdout;
2412 }
2413 }
2414 if (rpipe(rsrc_err) > -1)
2415 {
2416 if ((err = ::fdopen(rpipe(rsrc_err), "r")))
2417 {
2418 open_files |= pstderr;
2419 }
2420 }
2421 return open_files;
2422 }
2423
2434 template <typename C, typename T>
2435 inline std::size_t
2436 pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
2437 {
2438 return buf_.fopen(fin, fout, ferr);
2439 }
2440
2441#endif // REDI_EVISCERATE_PSTREAMS
2442
2443
2444} // namespace redi
2445
2451#endif // REDI_PSTREAM_H_SEEN
2452
2453// vim: ts=2 sw=2 expandtab
2454
Class template for Input PStreams.
Definition pstream.h:383
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:435
basic_ipstream(const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition pstream.h:452
basic_ipstream()
Default constructor, creates an uninitialised stream.
Definition pstream.h:405
~basic_ipstream()
Destructor.
Definition pstream.h:489
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Start a process.
Definition pstream.h:518
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition pstream.h:402
basic_ipstream & err()
Set streambuf to read from process' stderr.
Definition pstream.h:541
void open(const std::string &cmd, pmode mode=pstdout)
Start a process.
Definition pstream.h:502
basic_ipstream & out()
Set streambuf to read from process' stdout.
Definition pstream.h:530
basic_ipstream(const std::string &cmd, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition pstream.h:420
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition pstream.h:399
Class template for Output PStreams.
Definition pstream.h:563
void open(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Start a process.
Definition pstream.h:696
basic_opstream(const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:624
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:607
basic_opstream()
Default constructor, creates an uninitialised stream.
Definition pstream.h:577
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition pstream.h:571
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition pstream.h:574
~basic_opstream()
Destructor.
Definition pstream.h:668
basic_opstream(const std::string &cmd, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:592
void open(const std::string &cmd, pmode mode=pstdin)
Start a process.
Definition pstream.h:680
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:1108
Class template for Bidirectional PStreams.
Definition pstream.h:723
basic_pstream(const std::string &cmd, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:752
void open(const std::string &cmd, pmode mode=pstdout|pstdin)
Start a process.
Definition pstream.h:840
basic_pstream()
Default constructor, creates an uninitialised stream.
Definition pstream.h:737
~basic_pstream()
Destructor.
Definition pstream.h:828
basic_pstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:784
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition pstream.h:856
basic_pstream & out()
Set streambuf to read from process' stdout.
Definition pstream.h:868
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:767
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition pstream.h:734
basic_pstream & err()
Set streambuf to read from process' stderr.
Definition pstream.h:879
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition pstream.h:731
Class template for stream buffer.
Definition pstream.h:98
fd_type & rpipe(buf_read_src which)
Return the file descriptor for the specified input pipe.
Definition pstream.h:2193
basic_pstreambuf * killpg(int signal=SIGTERM)
Send a signal to the process' process group.
Definition pstream.h:1826
void close_fd(pstreams::fd_type &fd)
Helper function to close a file descriptor.
Definition pstream.h:1339
int status() const
Return the exit status of the process.
Definition pstream.h:1870
basic_pstreambuf * open(const std::string &file, const argv_type &argv, pmode mode)
Initialise the stream buffer with file and argv.
Definition pstream.h:1394
std::streamsize xsputn(const char_type *s, std::streamsize n)
Insert multiple characters into the pipe.
Definition pstream.h:1973
std::streamsize read(char_type *s, std::streamsize n)
Extract a sequence of characters from the pipe.
Definition pstream.h:2160
std::streamsize write(const char_type *s, std::streamsize n)
Insert a sequence of characters into the pipe.
Definition pstream.h:2137
~basic_pstreambuf()
Destructor.
Definition pstream.h:1200
int_type overflow(int_type c)
Transfer characters to the pipe when character buffer overflows.
Definition pstream.h:1948
int sync()
Write any buffered characters to the stream.
Definition pstream.h:1961
basic_pstreambuf * kill(int signal=SIGTERM)
Send a signal to the process.
Definition pstream.h:1791
void peof()
Close the pipe connected to the process' stdin.
Definition pstream.h:1891
pid_t fork(pmode mode)
Initialise pipes and fork process.
Definition pstream.h:1500
basic_pstreambuf * close()
Close the stream buffer and wait for the process to exit.
Definition pstream.h:1617
basic_pstreambuf(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the buffer with file and argv.
Definition pstream.h:1178
int error() const
Return the error number (errno) for the most recent failed operation.
Definition pstream.h:1880
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:1357
fd_type & wpipe()
Return the file descriptor for the output pipe.
Definition pstream.h:2177
bool exited()
Report whether the process has exited.
Definition pstream.h:1857
bool empty_buffer()
Writes buffered characters to the process' stdin pipe.
Definition pstream.h:1996
fd_type fd_t
Definition pstream.h:107
char_type * rbuffer()
Return the active input buffer.
Definition pstream.h:2201
std::streamsize showmanyc()
Report how many characters can be read from active input without blocking.
Definition pstream.h:2055
bool read_err(bool readerr=true)
Change active input source.
Definition pstream.h:1925
bool fill_buffer(bool non_blocking=false)
Definition pstream.h:2077
basic_pstreambuf * open(const std::string &cmd, pmode mode)
Initialise the stream buffer with cmd.
Definition pstream.h:1292
int_type pbackfail(int_type c=traits_type::eof())
Make a character available to be returned by the next extraction.
Definition pstream.h:2040
fd_type & rpipe()
Return the file descriptor for the active input pipe.
Definition pstream.h:2185
basic_pstreambuf()
Default constructor.
Definition pstream.h:1130
bool is_open() const
Report whether the stream buffer has been initialised.
Definition pstream.h:1910
int_type underflow()
Transfer characters from the pipe when the character buffer is empty.
Definition pstream.h:2022
int wait(bool nohang=false)
Wait for the child process to exit.
Definition pstream.h:1748
basic_pstreambuf(const std::string &cmd, pmode mode)
Constructor that initialises the buffer with cmd.
Definition pstream.h:1153
Class template for Restricted PStreams.
Definition pstream.h:914
istream_type & err()
Obtain a reference to the istream that reads the process' stderr.
Definition pstream.h:1074
~basic_rpstream()
Destructor.
Definition pstream.h:1021
basic_rpstream()
Default constructor, creates an uninitialised stream.
Definition pstream.h:929
basic_rpstream(const std::string &cmd, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:944
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition pstream.h:1049
void open(const std::string &cmd, pmode mode=pstdout|pstdin)
Start a process.
Definition pstream.h:1033
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition pstream.h:926
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition pstream.h:923
basic_rpstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition pstream.h:976
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:959
istream_type & out()
Obtain a reference to the istream that reads the process' stdout.
Definition pstream.h:1062
Class template for common base class.
Definition pstream.h:284
pstream_common()
Default constructor.
Definition pstream.h:2222
void do_open(const std::string &cmd, pmode mode)
Start a process.
Definition pstream.h:2296
void do_open(const std::string &file, const argv_type &argv, pmode mode)
Start a process.
Definition pstream.h:2313
pstream_common(const std::string &file, const argv_type &argv, pmode mode)
Constructor that initialises the stream by starting a process.
Definition pstream.h:2260
pstream_common(const std::string &cmd, pmode mode)
Constructor that initialises the stream by starting a process.
Definition pstream.h:2240
streambuf_type * rdbuf() const
Return a pointer to the stream buffer.
Definition pstream.h:2355
streambuf_type buf_
The stream buffer.
Definition pstream.h:364
int close()
Definition pstream.h:2325
virtual ~pstream_common()=0
Pure virtual destructor.
Definition pstream.h:2282
bool is_open() const
Report whether the stream's buffer has been initialised.
Definition pstream.h:2338
std::string command_
The command used to start the process.
Definition pstream.h:363
const std::string & command() const
Return the command used to initialise the stream.
Definition pstream.h:2346
All PStreams classes are declared in namespace redi.
basic_pstreambuf< char > pstreambuf
Type definition for common template specialisation.
Definition pstream.h:1083
basic_ipstream< char > ipstream
Type definition for common template specialisation.
Definition pstream.h:1085
basic_rpstream< char > rpstream
Type definition for common template specialisation.
Definition pstream.h:1091
basic_opstream< char > opstream
Type definition for common template specialisation.
Definition pstream.h:1087
basic_pstream< char > pstream
Type definition for common template specialisation.
Definition pstream.h:1089
Common base class providing constants and typenames.
Definition pstream.h:66
std::ios_base::openmode pmode
Type used to specify how to connect to the process.
Definition pstream.h:68
static const pmode pstderr
Read from stderr.
Definition pstream.h:78
static const pmode pstdin
Write to stdin.
Definition pstream.h:76
static const pmode newpg
Create a new process group for the child process.
Definition pstream.h:81
static const pmode pstdout
Read from stdout.
Definition pstream.h:77
int fd_type
Type used for file descriptors.
Definition pstream.h:74
std::vector< std::string > argv_type
Type used to hold the arguments for a command.
Definition pstream.h:71