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