1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal 2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling 3 // Copyright (c) 2009 Boris Schaeling 4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling 5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 10 11 #ifndef BOOST_PROCESS_PIPE_HPP 12 #define BOOST_PROCESS_PIPE_HPP 13 14 #include <boost/config.hpp> 15 #include <boost/process/detail/config.hpp> 16 #include <streambuf> 17 #include <istream> 18 #include <ostream> 19 #include <vector> 20 21 #if defined(BOOST_POSIX_API) 22 #include <boost/process/detail/posix/basic_pipe.hpp> 23 #elif defined(BOOST_WINDOWS_API) 24 #include <boost/process/detail/windows/basic_pipe.hpp> 25 #endif 26 27 namespace boost { namespace process { 28 29 using ::boost::process::detail::api::basic_pipe; 30 31 #if defined(BOOST_PROCESS_DOXYGEN) 32 /** Class implementation of a pipe. 33 * 34 */ 35 template<class CharT, class Traits = std::char_traits<CharT>> 36 class basic_pipe 37 { 38 public: 39 typedef CharT char_type ; 40 typedef Traits traits_type; 41 typedef typename Traits::int_type int_type ; 42 typedef typename Traits::pos_type pos_type ; 43 typedef typename Traits::off_type off_type ; 44 typedef ::boost::detail::winapi::HANDLE_ native_handle; 45 46 /// Default construct the pipe. Will be opened. 47 basic_pipe(); 48 49 ///Construct a named pipe. 50 inline explicit basic_pipe(const std::string & name); 51 /** Copy construct the pipe. 52 * \note Duplicated the handles. 53 */ 54 inline basic_pipe(const basic_pipe& p); 55 /** Move construct the pipe. */ 56 basic_pipe(basic_pipe&& lhs); 57 /** Copy assign the pipe. 58 * \note Duplicated the handles. 59 */ 60 inline basic_pipe& operator=(const basic_pipe& p); 61 /** Move assign the pipe. */ 62 basic_pipe& operator=(basic_pipe&& lhs); 63 /** Destructor closes the handles. */ 64 ~basic_pipe(); 65 /** Get the native handle of the source. */ 66 native_handle native_source() const; 67 /** Get the native handle of the sink. */ 68 native_handle native_sink () const; 69 70 /** Assign a new value to the source */ 71 void assign_source(native_handle h); 72 /** Assign a new value to the sink */ 73 void assign_sink (native_handle h); 74 75 76 ///Write data to the pipe. 77 int_type write(const char_type * data, int_type count); 78 ///Read data from the pipe. 79 int_type read(char_type * data, int_type count); 80 ///Check if the pipe is open. 81 bool is_open(); 82 ///Close the pipe 83 void close(); 84 }; 85 86 #endif 87 88 89 90 typedef basic_pipe<char> pipe; 91 typedef basic_pipe<wchar_t> wpipe; 92 93 94 /** Implementation of the stream buffer for a pipe. 95 */ 96 template< 97 class CharT, 98 class Traits = std::char_traits<CharT> 99 > 100 struct basic_pipebuf : std::basic_streambuf<CharT, Traits> 101 { 102 typedef basic_pipe<CharT, Traits> pipe_type; 103 104 typedef CharT char_type ; 105 typedef Traits traits_type; 106 typedef typename Traits::int_type int_type ; 107 typedef typename Traits::pos_type pos_type ; 108 typedef typename Traits::off_type off_type ; 109 110 constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE; 111 112 ///Default constructor, will also construct the pipe. basic_pipebufboost::process::basic_pipebuf113 basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size) 114 { 115 this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); 116 this->setp(_write.data(), _write.data() + _write.size()); 117 } 118 ///Copy Constructor. 119 basic_pipebuf(const basic_pipebuf & ) = default; 120 ///Move Constructor 121 basic_pipebuf(basic_pipebuf && ) = default; 122 123 ///Destructor -> writes the frest of the data ~basic_pipebufboost::process::basic_pipebuf124 ~basic_pipebuf() 125 { 126 if (basic_pipebuf::is_open()) 127 basic_pipebuf::overflow(Traits::eof()); 128 } 129 130 ///Move construct from a pipe. basic_pipebufboost::process::basic_pipebuf131 basic_pipebuf(pipe_type && p) : _pipe(std::move(p)), 132 _write(default_buffer_size), 133 _read(default_buffer_size) 134 { 135 this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); 136 this->setp(_write.data(), _write.data() + _write.size()); 137 } 138 ///Construct from a pipe. basic_pipebufboost::process::basic_pipebuf139 basic_pipebuf(const pipe_type & p) : _pipe(p), 140 _write(default_buffer_size), 141 _read(default_buffer_size) 142 { 143 this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); 144 this->setp(_write.data(), _write.data() + _write.size()); 145 } 146 ///Copy assign. 147 basic_pipebuf& operator=(const basic_pipebuf & ) = delete; 148 ///Move assign. 149 basic_pipebuf& operator=(basic_pipebuf && ) = default; 150 ///Move assign a pipe. operator =boost::process::basic_pipebuf151 basic_pipebuf& operator=(pipe_type && p) 152 { 153 _pipe = std::move(p); 154 return *this; 155 } 156 ///Copy assign a pipe. operator =boost::process::basic_pipebuf157 basic_pipebuf& operator=(const pipe_type & p) 158 { 159 _pipe = p; 160 return *this; 161 } 162 ///Writes characters to the associated output sequence from the put area overflowboost::process::basic_pipebuf163 int_type overflow(int_type ch = traits_type::eof()) override 164 { 165 if (_pipe.is_open() && (ch != traits_type::eof())) 166 { 167 if (this->pptr() == this->epptr()) 168 { 169 bool wr = this->_write_impl(); 170 if (wr) 171 { 172 *this->pptr() = ch; 173 this->pbump(1); 174 return ch; 175 } 176 } 177 else 178 { 179 *this->pptr() = ch; 180 this->pbump(1); 181 if (this->_write_impl()) 182 return ch; 183 } 184 } 185 else if (ch == traits_type::eof()) 186 this->sync(); 187 188 return traits_type::eof(); 189 } 190 ///Synchronizes the buffers with the associated character sequence syncboost::process::basic_pipebuf191 int sync() override { return this->_write_impl() ? 0 : -1; } 192 193 ///Reads characters from the associated input sequence to the get area underflowboost::process::basic_pipebuf194 int_type underflow() override 195 { 196 if (!_pipe.is_open()) 197 return traits_type::eof(); 198 199 if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer 200 this->setg(_read.data(), _read.data()+ 10, _read.data() + 10); 201 202 203 auto len = &_read.back() - this->egptr() ; 204 auto res = _pipe.read( 205 this->egptr(), 206 static_cast<typename pipe_type::int_type>(len)); 207 if (res == 0) 208 return traits_type::eof(); 209 210 this->setg(this->eback(), this->gptr(), this->egptr() + res); 211 auto val = *this->gptr(); 212 213 return traits_type::to_int_type(val); 214 } 215 216 217 ///Set the pipe of the streambuf. pipeboost::process::basic_pipebuf218 void pipe(pipe_type&& p) {_pipe = std::move(p); } 219 ///Set the pipe of the streambuf. pipeboost::process::basic_pipebuf220 void pipe(const pipe_type& p) {_pipe = p; } 221 ///Get a reference to the pipe. pipeboost::process::basic_pipebuf222 pipe_type & pipe() & {return _pipe;} 223 ///Get a const reference to the pipe. pipeboost::process::basic_pipebuf224 const pipe_type &pipe() const & {return _pipe;} 225 ///Get a rvalue reference to the pipe. Qualified as rvalue. pipeboost::process::basic_pipebuf226 pipe_type && pipe() && {return std::move(_pipe);} 227 228 ///Check if the pipe is open is_openboost::process::basic_pipebuf229 bool is_open() const {return _pipe.is_open(); } 230 231 ///Open a new pipe openboost::process::basic_pipebuf232 basic_pipebuf<CharT, Traits>* open() 233 { 234 if (is_open()) 235 return nullptr; 236 _pipe = pipe(); 237 return this; 238 } 239 240 ///Open a new named pipe openboost::process::basic_pipebuf241 basic_pipebuf<CharT, Traits>* open(const std::string & name) 242 { 243 if (is_open()) 244 return nullptr; 245 _pipe = pipe(name); 246 return this; 247 } 248 249 ///Flush the buffer & close the pipe closeboost::process::basic_pipebuf250 basic_pipebuf<CharT, Traits>* close() 251 { 252 if (!is_open()) 253 return nullptr; 254 overflow(Traits::eof()); 255 return this; 256 } 257 private: 258 pipe_type _pipe; 259 std::vector<char_type> _write; 260 std::vector<char_type> _read; 261 _write_implboost::process::basic_pipebuf262 bool _write_impl() 263 { 264 if (!_pipe.is_open()) 265 return false; 266 267 auto base = this->pbase(); 268 269 if (base == this->pptr()) 270 return true; 271 272 std::ptrdiff_t wrt = _pipe.write(base, 273 static_cast<typename pipe_type::int_type>(this->pptr() - base)); 274 275 std::ptrdiff_t diff = this->pptr() - base; 276 277 if (wrt < diff) 278 std::move(base + wrt, base + diff, base); 279 else if (wrt == 0) //broken pipe 280 return false; 281 282 this->pbump(-wrt); 283 284 return true; 285 } 286 }; 287 288 typedef basic_pipebuf<char> pipebuf; 289 typedef basic_pipebuf<wchar_t> wpipebuf; 290 291 /** Implementation of a reading pipe stream. 292 * 293 */ 294 template< 295 class CharT, 296 class Traits = std::char_traits<CharT> 297 > 298 class basic_ipstream : public std::basic_istream<CharT, Traits> 299 { 300 mutable basic_pipebuf<CharT, Traits> _buf; 301 public: 302 303 typedef basic_pipe<CharT, Traits> pipe_type; 304 305 typedef CharT char_type ; 306 typedef Traits traits_type; 307 typedef typename Traits::int_type int_type ; 308 typedef typename Traits::pos_type pos_type ; 309 typedef typename Traits::off_type off_type ; 310 311 ///Get access to the underlying stream_buf rdbuf() const312 basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; 313 314 ///Default constructor. basic_ipstream()315 basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr) 316 { 317 std::basic_istream<CharT, Traits>::rdbuf(&_buf); 318 }; 319 ///Copy constructor. 320 basic_ipstream(const basic_ipstream & ) = delete; 321 ///Move constructor. basic_ipstream(basic_ipstream && lhs)322 basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) 323 { 324 std::basic_istream<CharT, Traits>::rdbuf(&_buf); 325 } 326 327 ///Move construct from a pipe. basic_ipstream(pipe_type && p)328 basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p)) 329 { 330 std::basic_istream<CharT, Traits>::rdbuf(&_buf); 331 } 332 333 ///Copy construct from a pipe. basic_ipstream(const pipe_type & p)334 basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p) 335 { 336 std::basic_istream<CharT, Traits>::rdbuf(&_buf); 337 } 338 339 ///Copy assignment. 340 basic_ipstream& operator=(const basic_ipstream & ) = delete; 341 ///Move assignment operator =(basic_ipstream && lhs)342 basic_ipstream& operator=(basic_ipstream && lhs) 343 { 344 std::basic_istream<CharT, Traits>::operator=(std::move(lhs)); 345 _buf = std::move(lhs._buf); 346 std::basic_istream<CharT, Traits>::rdbuf(&_buf); 347 return *this; 348 }; 349 ///Move assignment of a pipe. operator =(pipe_type && p)350 basic_ipstream& operator=(pipe_type && p) 351 { 352 _buf = std::move(p); 353 return *this; 354 } 355 ///Copy assignment of a pipe. operator =(const pipe_type & p)356 basic_ipstream& operator=(const pipe_type & p) 357 { 358 _buf = p; 359 return *this; 360 } 361 ///Set the pipe of the streambuf. pipe(pipe_type && p)362 void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } 363 ///Set the pipe of the streambuf. pipe(const pipe_type & p)364 void pipe(const pipe_type& p) {_buf.pipe(p); } 365 ///Get a reference to the pipe. pipe()366 pipe_type & pipe() & {return _buf.pipe();} 367 ///Get a const reference to the pipe. pipe() const368 const pipe_type &pipe() const & {return _buf.pipe();} 369 ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe()370 pipe_type && pipe() && {return std::move(_buf).pipe();} 371 ///Check if the pipe is open is_open() const372 bool is_open() const {return _buf.is_open();} 373 374 ///Open a new pipe open()375 void open() 376 { 377 if (_buf.open() == nullptr) 378 this->setstate(std::ios_base::failbit); 379 else 380 this->clear(); 381 } 382 383 ///Open a new named pipe open(const std::string & name)384 void open(const std::string & name) 385 { 386 if (_buf.open() == nullptr) 387 this->setstate(std::ios_base::failbit); 388 else 389 this->clear(); 390 } 391 392 ///Flush the buffer & close the pipe close()393 void close() 394 { 395 if (_buf.close() == nullptr) 396 this->setstate(std::ios_base::failbit); 397 } 398 }; 399 400 typedef basic_ipstream<char> ipstream; 401 typedef basic_ipstream<wchar_t> wipstream; 402 403 /** Implementation of a write pipe stream. 404 * 405 */ 406 template< 407 class CharT, 408 class Traits = std::char_traits<CharT> 409 > 410 class basic_opstream : public std::basic_ostream<CharT, Traits> 411 { 412 mutable basic_pipebuf<CharT, Traits> _buf; 413 public: 414 typedef basic_pipe<CharT, Traits> pipe_type; 415 416 typedef CharT char_type ; 417 typedef Traits traits_type; 418 typedef typename Traits::int_type int_type ; 419 typedef typename Traits::pos_type pos_type ; 420 typedef typename Traits::off_type off_type ; 421 422 423 ///Get access to the underlying stream_buf rdbuf() const424 basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; 425 426 ///Default constructor. basic_opstream()427 basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr) 428 { 429 std::basic_ostream<CharT, Traits>::rdbuf(&_buf); 430 }; 431 ///Copy constructor. 432 basic_opstream(const basic_opstream & ) = delete; 433 ///Move constructor. basic_opstream(basic_opstream && lhs)434 basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) 435 { 436 std::basic_ostream<CharT, Traits>::rdbuf(&_buf); 437 } 438 ///Move construct from a pipe. basic_opstream(pipe_type && p)439 basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p)) 440 { 441 std::basic_ostream<CharT, Traits>::rdbuf(&_buf); 442 }; 443 ///Copy construct from a pipe. basic_opstream(const pipe_type & p)444 basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p) 445 { 446 std::basic_ostream<CharT, Traits>::rdbuf(&_buf); 447 }; 448 ///Copy assignment. 449 basic_opstream& operator=(const basic_opstream & ) = delete; 450 ///Move assignment operator =(basic_opstream && lhs)451 basic_opstream& operator=(basic_opstream && lhs) 452 { 453 std::basic_ostream<CharT, Traits>::operator=(std::move(lhs)); 454 _buf = std::move(lhs._buf); 455 std::basic_ostream<CharT, Traits>::rdbuf(&_buf); 456 return *this; 457 }; 458 459 ///Move assignment of a pipe. operator =(pipe_type && p)460 basic_opstream& operator=(pipe_type && p) 461 { 462 _buf = std::move(p); 463 return *this; 464 } 465 ///Copy assignment of a pipe. operator =(const pipe_type & p)466 basic_opstream& operator=(const pipe_type & p) 467 { 468 _buf = p; 469 return *this; 470 } 471 ///Set the pipe of the streambuf. pipe(pipe_type && p)472 void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } 473 ///Set the pipe of the streambuf. pipe(const pipe_type & p)474 void pipe(const pipe_type& p) {_buf.pipe(p); } 475 ///Get a reference to the pipe. pipe()476 pipe_type & pipe() & {return _buf.pipe();} 477 ///Get a const reference to the pipe. pipe() const478 const pipe_type &pipe() const & {return _buf.pipe();} 479 ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe()480 pipe_type && pipe() && {return std::move(_buf).pipe();} 481 482 ///Open a new pipe open()483 void open() 484 { 485 if (_buf.open() == nullptr) 486 this->setstate(std::ios_base::failbit); 487 else 488 this->clear(); 489 } 490 491 ///Open a new named pipe open(const std::string & name)492 void open(const std::string & name) 493 { 494 if (_buf.open() == nullptr) 495 this->setstate(std::ios_base::failbit); 496 else 497 this->clear(); 498 } 499 500 ///Flush the buffer & close the pipe close()501 void close() 502 { 503 if (_buf.close() == nullptr) 504 this->setstate(std::ios_base::failbit); 505 } 506 }; 507 508 typedef basic_opstream<char> opstream; 509 typedef basic_opstream<wchar_t> wopstream; 510 511 512 /** Implementation of a read-write pipe stream. 513 * 514 */ 515 template< 516 class CharT, 517 class Traits = std::char_traits<CharT> 518 > 519 class basic_pstream : public std::basic_iostream<CharT, Traits> 520 { 521 mutable basic_pipebuf<CharT, Traits> _buf; 522 public: 523 typedef basic_pipe<CharT, Traits> pipe_type; 524 525 typedef CharT char_type ; 526 typedef Traits traits_type; 527 typedef typename Traits::int_type int_type ; 528 typedef typename Traits::pos_type pos_type ; 529 typedef typename Traits::off_type off_type ; 530 531 532 ///Get access to the underlying stream_buf rdbuf() const533 basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;}; 534 535 ///Default constructor. basic_pstream()536 basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr) 537 { 538 std::basic_iostream<CharT, Traits>::rdbuf(&_buf); 539 }; 540 ///Copy constructor. 541 basic_pstream(const basic_pstream & ) = delete; 542 ///Move constructor. basic_pstream(basic_pstream && lhs)543 basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf)) 544 { 545 std::basic_iostream<CharT, Traits>::rdbuf(&_buf); 546 } 547 ///Move construct from a pipe. basic_pstream(pipe_type && p)548 basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p)) 549 { 550 std::basic_iostream<CharT, Traits>::rdbuf(&_buf); 551 }; 552 ///Copy construct from a pipe. basic_pstream(const pipe_type & p)553 basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p) 554 { 555 std::basic_iostream<CharT, Traits>::rdbuf(&_buf); 556 }; 557 ///Copy assignment. 558 basic_pstream& operator=(const basic_pstream & ) = delete; 559 ///Move assignment operator =(basic_pstream && lhs)560 basic_pstream& operator=(basic_pstream && lhs) 561 { 562 std::basic_istream<CharT, Traits>::operator=(std::move(lhs)); 563 _buf = std::move(lhs._buf); 564 std::basic_iostream<CharT, Traits>::rdbuf(&_buf); 565 return *this; 566 }; 567 ///Move assignment of a pipe. operator =(pipe_type && p)568 basic_pstream& operator=(pipe_type && p) 569 { 570 _buf = std::move(p); 571 return *this; 572 } 573 ///Copy assignment of a pipe. operator =(const pipe_type & p)574 basic_pstream& operator=(const pipe_type & p) 575 { 576 _buf = p; 577 return *this; 578 } 579 ///Set the pipe of the streambuf. pipe(pipe_type && p)580 void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } 581 ///Set the pipe of the streambuf. pipe(const pipe_type & p)582 void pipe(const pipe_type& p) {_buf.pipe(p); } 583 ///Get a reference to the pipe. pipe()584 pipe_type & pipe() & {return _buf.pipe();} 585 ///Get a const reference to the pipe. pipe() const586 const pipe_type &pipe() const & {return _buf.pipe();} 587 ///Get a rvalue reference to the pipe. Qualified as rvalue. pipe()588 pipe_type && pipe() && {return std::move(_buf).pipe();} 589 590 ///Open a new pipe open()591 void open() 592 { 593 if (_buf.open() == nullptr) 594 this->setstate(std::ios_base::failbit); 595 else 596 this->clear(); 597 } 598 599 ///Open a new named pipe open(const std::string & name)600 void open(const std::string & name) 601 { 602 if (_buf.open() == nullptr) 603 this->setstate(std::ios_base::failbit); 604 else 605 this->clear(); 606 } 607 608 ///Flush the buffer & close the pipe close()609 void close() 610 { 611 if (_buf.close() == nullptr) 612 this->setstate(std::ios_base::failbit); 613 } 614 }; 615 616 typedef basic_pstream<char> pstream; 617 typedef basic_pstream<wchar_t> wpstream; 618 619 620 621 }} 622 623 624 625 #endif 626