ian@0: // ian@0: // Boost.Process ian@0: // ~~~~~~~~~~~~~ ian@0: // ian@0: // Copyright (c) 2006, 2007 Julio M. Merino Vidal ian@0: // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling ian@0: // Copyright (c) 2009 Boris Schaeling ian@0: // Copyright (c) 2010 Felipe Tanus, Boris Schaeling ian@0: // ian@0: // Distributed under the Boost Software License, Version 1.0. (See accompanying ian@0: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ian@0: // ian@0: ian@0: /** ian@0: * \file boost/process/detail/systembuf.hpp ian@0: * ian@0: * Includes the declaration of the systembuf class. ian@0: */ ian@0: ian@0: #ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP ian@0: #define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP ian@0: ian@0: #include ian@0: ian@0: #if defined(BOOST_POSIX_API) ian@0: # include ian@0: # include ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: # include ian@0: #else ian@0: # error "Unsupported platform." ian@0: #endif ian@0: ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: #include ian@0: ian@0: namespace boost { ian@0: namespace process { ian@0: ian@0: class postream; ian@0: ian@0: namespace detail { ian@0: ian@0: /** ian@0: * std::streambuf implementation for handles. ian@0: * ian@0: * systembuf provides a std::streambuf implementation for handles. ian@0: * Contrarywise to the handle class, this class does \b not take ian@0: * ownership of the native handle; this should be taken care of ian@0: * somewhere else. ian@0: * ian@0: * This class follows the expected semantics of a std::streambuf object. ian@0: * However, it is not copyable to avoid introducing inconsistences with ian@0: * the on-disk file and the in-memory buffers. ian@0: */ ian@0: class systembuf : public std::streambuf, public boost::noncopyable ian@0: { ian@0: friend class boost::process::postream; ian@0: ian@0: public: ian@0: #if defined(BOOST_PROCESS_DOXYGEN) ian@0: /** ian@0: * Opaque name for the native handle type. ian@0: */ ian@0: typedef NativeHandleType handle_type; ian@0: #elif defined(BOOST_POSIX_API) ian@0: typedef int handle_type; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: typedef HANDLE handle_type; ian@0: #endif ian@0: ian@0: /** ian@0: * Constructs a new systembuf for the given handle. ian@0: * ian@0: * This constructor creates a new systembuf object that reads or ian@0: * writes data from/to the \a h native handle. This handle ian@0: * is \b not owned by the created systembuf object; the code ian@0: * should take care of it externally. ian@0: * ian@0: * This class buffers input and output; the buffer size may be ian@0: * tuned through the \a bufsize parameter, which defaults to 8192 ian@0: * bytes. ian@0: * ian@0: * \see pistream and postream ian@0: */ ian@0: explicit systembuf(handle_type h, std::size_t bufsize = 8192) ian@0: : handle_(h), ian@0: bufsize_(bufsize), ian@0: read_buf_(new char[bufsize]), ian@0: write_buf_(new char[bufsize]) ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: BOOST_ASSERT(handle_ >= 0); ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE); ian@0: #endif ian@0: BOOST_ASSERT(bufsize_ > 0); ian@0: setp(write_buf_.get(), write_buf_.get() + bufsize_); ian@0: } ian@0: ian@0: protected: ian@0: /** ian@0: * Reads new data from the native handle. ian@0: * ian@0: * This operation is called by input methods when there is no more ian@0: * data in the input buffer. The function fills the buffer with new ian@0: * data, if available. ian@0: * ian@0: * \pre All input positions are exhausted (gptr() >= egptr()). ian@0: * \post The input buffer has new data, if available. ian@0: * \returns traits_type::eof() if a read error occurrs or there are ian@0: * no more data to be read. Otherwise returns ian@0: * traits_type::to_int_type(*gptr()). ian@0: */ ian@0: virtual int_type underflow() ian@0: { ian@0: BOOST_ASSERT(gptr() >= egptr()); ian@0: ian@0: bool ok; ian@0: #if defined(BOOST_POSIX_API) ian@0: ssize_t cnt = read(handle_, read_buf_.get(), bufsize_); ian@0: ok = (cnt != -1 && cnt != 0); ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: DWORD cnt; ian@0: BOOL res = ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL); ian@0: ok = (res && cnt > 0); ian@0: #endif ian@0: ian@0: if (!ok) ian@0: return traits_type::eof(); ian@0: else ian@0: { ian@0: setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt); ian@0: return traits_type::to_int_type(*gptr()); ian@0: } ian@0: } ian@0: ian@0: /** ian@0: * Makes room in the write buffer for additional data. ian@0: * ian@0: * This operation is called by output methods when there is no more ian@0: * space in the output buffer to hold a new element. The function ian@0: * first flushes the buffer's contents to disk and then clears it to ian@0: * leave room for more characters. The given \a c character is ian@0: * stored at the beginning of the new space. ian@0: * ian@0: * \pre All output positions are exhausted (pptr() >= epptr()). ian@0: * \post The output buffer has more space if no errors occurred ian@0: * during the write to disk. ian@0: * \post *(pptr() - 1) is \a c. ian@0: * \returns traits_type::eof() if a write error occurrs. Otherwise ian@0: * returns traits_type::not_eof(c). ian@0: */ ian@0: virtual int_type overflow(int c) ian@0: { ian@0: BOOST_ASSERT(pptr() >= epptr()); ian@0: ian@0: if (sync() == -1) ian@0: return traits_type::eof(); ian@0: ian@0: if (!traits_type::eq_int_type(c, traits_type::eof())) ian@0: { ian@0: traits_type::assign(*pptr(), static_cast( ian@0: c)); ian@0: pbump(1); ian@0: } ian@0: ian@0: return traits_type::not_eof(c); ian@0: } ian@0: ian@0: /** ian@0: * Flushes the output buffer to disk. ian@0: * ian@0: * Synchronizes the systembuf buffers with the contents of the file ian@0: * associated to this object through the native handle. The output buffer ian@0: * is flushed to disk and cleared to leave new room for more data. ian@0: * ian@0: * \returns 0 on success, -1 if an error occurred. ian@0: */ ian@0: virtual int sync() ian@0: { ian@0: #if defined(BOOST_POSIX_API) ian@0: ssize_t cnt = pptr() - pbase(); ian@0: bool ok = (write(handle_, pbase(), cnt) == cnt); ian@0: if (ok) ian@0: pbump(static_cast(-cnt)); ian@0: return ok ? 0 : -1; ian@0: #elif defined(BOOST_WINDOWS_API) ian@0: long cnt = pptr() - pbase(); ian@0: DWORD rcnt; ian@0: BOOL res = WriteFile(handle_, pbase(), cnt, &rcnt, NULL); ian@0: bool ok = (res && static_cast(rcnt) == cnt); ian@0: if (ok) ian@0: pbump(-cnt); ian@0: return ok ? 0 : -1; ian@0: #endif ian@0: } ian@0: ian@0: private: ian@0: /** ian@0: * Native handle used by the systembuf object. ian@0: */ ian@0: handle_type handle_; ian@0: ian@0: /** ian@0: * Internal buffer size used during read and write operations. ian@0: */ ian@0: std::size_t bufsize_; ian@0: ian@0: /** ian@0: * Internal buffer used during read operations. ian@0: */ ian@0: boost::scoped_array read_buf_; ian@0: ian@0: /** ian@0: * Internal buffer used during write operations. ian@0: */ ian@0: boost::scoped_array write_buf_; ian@0: }; ian@0: ian@0: } ian@0: } ian@0: } ian@0: ian@0: #endif