blob: 201d0fa6219313480a9caab4ba41c92af94e91d1 [file] [log] [blame]
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_PIPE_HPP
#define BOOST_PROCESS_PIPE_HPP
#include <boost/config.hpp>
#include <boost/process/detail/config.hpp>
#include <streambuf>
#include <istream>
#include <ostream>
#include <vector>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/basic_pipe.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/basic_pipe.hpp>
#endif
namespace boost { namespace process {
using ::boost::process::detail::api::basic_pipe;
#if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementation of a pipe.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_pipe
{
public:
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef ::boost::detail::winapi::HANDLE_ native_handle;
/// Default construct the pipe. Will be opened.
basic_pipe();
///Construct a named pipe.
inline explicit basic_pipe(const std::string & name);
/** Copy construct the pipe.
* \note Duplicated the handles.
*/
inline basic_pipe(const basic_pipe& p);
/** Move construct the pipe. */
basic_pipe(basic_pipe&& lhs);
/** Copy assign the pipe.
* \note Duplicated the handles.
*/
inline basic_pipe& operator=(const basic_pipe& p);
/** Move assign the pipe. */
basic_pipe& operator=(basic_pipe&& lhs);
/** Destructor closes the handles. */
~basic_pipe();
/** Get the native handle of the source. */
native_handle native_source() const;
/** Get the native handle of the sink. */
native_handle native_sink () const;
/** Assign a new value to the source */
void assign_source(native_handle h);
/** Assign a new value to the sink */
void assign_sink (native_handle h);
///Write data to the pipe.
int_type write(const char_type * data, int_type count);
///Read data from the pipe.
int_type read(char_type * data, int_type count);
///Check if the pipe is open.
bool is_open();
///Close the pipe
void close();
};
#endif
typedef basic_pipe<char> pipe;
typedef basic_pipe<wchar_t> wpipe;
/** Implementation of the stream buffer for a pipe.
*/
template<
class CharT,
class Traits = std::char_traits<CharT>
>
struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
{
typedef basic_pipe<CharT, Traits> pipe_type;
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE;
///Default constructor, will also construct the pipe.
basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size)
{
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
this->setp(_write.data(), _write.data() + _write.size());
}
///Copy Constructor.
basic_pipebuf(const basic_pipebuf & ) = default;
///Move Constructor
basic_pipebuf(basic_pipebuf && ) = default;
///Destructor -> writes the frest of the data
~basic_pipebuf()
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
}
///Move construct from a pipe.
basic_pipebuf(pipe_type && p) : _pipe(std::move(p)),
_write(default_buffer_size),
_read(default_buffer_size)
{
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
this->setp(_write.data(), _write.data() + _write.size());
}
///Construct from a pipe.
basic_pipebuf(const pipe_type & p) : _pipe(p),
_write(default_buffer_size),
_read(default_buffer_size)
{
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
this->setp(_write.data(), _write.data() + _write.size());
}
///Copy assign.
basic_pipebuf& operator=(const basic_pipebuf & ) = delete;
///Move assign.
basic_pipebuf& operator=(basic_pipebuf && ) = default;
///Move assign a pipe.
basic_pipebuf& operator=(pipe_type && p)
{
_pipe = std::move(p);
return *this;
}
///Copy assign a pipe.
basic_pipebuf& operator=(const pipe_type & p)
{
_pipe = p;
return *this;
}
///Writes characters to the associated output sequence from the put area
int_type overflow(int_type ch = traits_type::eof()) override
{
if (_pipe.is_open() && (ch != traits_type::eof()))
{
if (this->pptr() == this->epptr())
{
bool wr = this->_write_impl();
if (wr)
{
*this->pptr() = ch;
this->pbump(1);
return ch;
}
}
else
{
*this->pptr() = ch;
this->pbump(1);
if (this->_write_impl())
return ch;
}
}
else if (ch == traits_type::eof())
this->sync();
return traits_type::eof();
}
///Synchronizes the buffers with the associated character sequence
int sync() override { return this->_write_impl() ? 0 : -1; }
///Reads characters from the associated input sequence to the get area
int_type underflow() override
{
if (!_pipe.is_open())
return traits_type::eof();
if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer
this->setg(_read.data(), _read.data()+ 10, _read.data() + 10);
auto len = &_read.back() - this->egptr() ;
auto res = _pipe.read(
this->egptr(),
static_cast<typename pipe_type::int_type>(len));
if (res == 0)
return traits_type::eof();
this->setg(this->eback(), this->gptr(), this->egptr() + res);
auto val = *this->gptr();
return traits_type::to_int_type(val);
}
///Set the pipe of the streambuf.
void pipe(pipe_type&& p) {_pipe = std::move(p); }
///Set the pipe of the streambuf.
void pipe(const pipe_type& p) {_pipe = p; }
///Get a reference to the pipe.
pipe_type & pipe() & {return _pipe;}
///Get a const reference to the pipe.
const pipe_type &pipe() const & {return _pipe;}
///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe_type && pipe() && {return std::move(_pipe);}
///Check if the pipe is open
bool is_open() const {return _pipe.is_open(); }
///Open a new pipe
basic_pipebuf<CharT, Traits>* open()
{
if (is_open())
return nullptr;
_pipe = pipe();
return this;
}
///Open a new named pipe
basic_pipebuf<CharT, Traits>* open(const std::string & name)
{
if (is_open())
return nullptr;
_pipe = pipe(name);
return this;
}
///Flush the buffer & close the pipe
basic_pipebuf<CharT, Traits>* close()
{
if (!is_open())
return nullptr;
overflow(Traits::eof());
return this;
}
private:
pipe_type _pipe;
std::vector<char_type> _write;
std::vector<char_type> _read;
bool _write_impl()
{
if (!_pipe.is_open())
return false;
auto base = this->pbase();
if (base == this->pptr())
return true;
std::ptrdiff_t wrt = _pipe.write(base,
static_cast<typename pipe_type::int_type>(this->pptr() - base));
std::ptrdiff_t diff = this->pptr() - base;
if (wrt < diff)
std::move(base + wrt, base + diff, base);
else if (wrt == 0) //broken pipe
return false;
this->pbump(-wrt);
return true;
}
};
typedef basic_pipebuf<char> pipebuf;
typedef basic_pipebuf<wchar_t> wpipebuf;
/** Implementation of a reading pipe stream.
*
*/
template<
class CharT,
class Traits = std::char_traits<CharT>
>
class basic_ipstream : public std::basic_istream<CharT, Traits>
{
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr)
{
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
};
///Copy constructor.
basic_ipstream(const basic_ipstream & ) = delete;
///Move constructor.
basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p))
{
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
}
///Copy construct from a pipe.
basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p)
{
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
}
///Copy assignment.
basic_ipstream& operator=(const basic_ipstream & ) = delete;
///Move assignment
basic_ipstream& operator=(basic_ipstream && lhs)
{
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs._buf);
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
return *this;
};
///Move assignment of a pipe.
basic_ipstream& operator=(pipe_type && p)
{
_buf = std::move(p);
return *this;
}
///Copy assignment of a pipe.
basic_ipstream& operator=(const pipe_type & p)
{
_buf = p;
return *this;
}
///Set the pipe of the streambuf.
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
///Set the pipe of the streambuf.
void pipe(const pipe_type& p) {_buf.pipe(p); }
///Get a reference to the pipe.
pipe_type & pipe() & {return _buf.pipe();}
///Get a const reference to the pipe.
const pipe_type &pipe() const & {return _buf.pipe();}
///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe_type && pipe() && {return std::move(_buf).pipe();}
///Check if the pipe is open
bool is_open() const {return _buf.is_open();}
///Open a new pipe
void open()
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Open a new named pipe
void open(const std::string & name)
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Flush the buffer & close the pipe
void close()
{
if (_buf.close() == nullptr)
this->setstate(std::ios_base::failbit);
}
};
typedef basic_ipstream<char> ipstream;
typedef basic_ipstream<wchar_t> wipstream;
/** Implementation of a write pipe stream.
*
*/
template<
class CharT,
class Traits = std::char_traits<CharT>
>
class basic_opstream : public std::basic_ostream<CharT, Traits>
{
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr)
{
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy constructor.
basic_opstream(const basic_opstream & ) = delete;
///Move constructor.
basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p))
{
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy construct from a pipe.
basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p)
{
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy assignment.
basic_opstream& operator=(const basic_opstream & ) = delete;
///Move assignment
basic_opstream& operator=(basic_opstream && lhs)
{
std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs._buf);
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
return *this;
};
///Move assignment of a pipe.
basic_opstream& operator=(pipe_type && p)
{
_buf = std::move(p);
return *this;
}
///Copy assignment of a pipe.
basic_opstream& operator=(const pipe_type & p)
{
_buf = p;
return *this;
}
///Set the pipe of the streambuf.
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
///Set the pipe of the streambuf.
void pipe(const pipe_type& p) {_buf.pipe(p); }
///Get a reference to the pipe.
pipe_type & pipe() & {return _buf.pipe();}
///Get a const reference to the pipe.
const pipe_type &pipe() const & {return _buf.pipe();}
///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe_type && pipe() && {return std::move(_buf).pipe();}
///Open a new pipe
void open()
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Open a new named pipe
void open(const std::string & name)
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Flush the buffer & close the pipe
void close()
{
if (_buf.close() == nullptr)
this->setstate(std::ios_base::failbit);
}
};
typedef basic_opstream<char> opstream;
typedef basic_opstream<wchar_t> wopstream;
/** Implementation of a read-write pipe stream.
*
*/
template<
class CharT,
class Traits = std::char_traits<CharT>
>
class basic_pstream : public std::basic_iostream<CharT, Traits>
{
mutable basic_pipebuf<CharT, Traits> _buf;
public:
typedef basic_pipe<CharT, Traits> pipe_type;
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
///Get access to the underlying stream_buf
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
///Default constructor.
basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr)
{
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy constructor.
basic_pstream(const basic_pstream & ) = delete;
///Move constructor.
basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
{
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
}
///Move construct from a pipe.
basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p))
{
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy construct from a pipe.
basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p)
{
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
};
///Copy assignment.
basic_pstream& operator=(const basic_pstream & ) = delete;
///Move assignment
basic_pstream& operator=(basic_pstream && lhs)
{
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
_buf = std::move(lhs._buf);
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
return *this;
};
///Move assignment of a pipe.
basic_pstream& operator=(pipe_type && p)
{
_buf = std::move(p);
return *this;
}
///Copy assignment of a pipe.
basic_pstream& operator=(const pipe_type & p)
{
_buf = p;
return *this;
}
///Set the pipe of the streambuf.
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
///Set the pipe of the streambuf.
void pipe(const pipe_type& p) {_buf.pipe(p); }
///Get a reference to the pipe.
pipe_type & pipe() & {return _buf.pipe();}
///Get a const reference to the pipe.
const pipe_type &pipe() const & {return _buf.pipe();}
///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe_type && pipe() && {return std::move(_buf).pipe();}
///Open a new pipe
void open()
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Open a new named pipe
void open(const std::string & name)
{
if (_buf.open() == nullptr)
this->setstate(std::ios_base::failbit);
else
this->clear();
}
///Flush the buffer & close the pipe
void close()
{
if (_buf.close() == nullptr)
this->setstate(std::ios_base::failbit);
}
};
typedef basic_pstream<char> pstream;
typedef basic_pstream<wchar_t> wpstream;
}}
#endif