ian@0
|
1 //
|
ian@0
|
2 // Boost.Process
|
ian@0
|
3 // ~~~~~~~~~~~~~
|
ian@0
|
4 //
|
ian@0
|
5 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
ian@0
|
6 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
ian@0
|
7 // Copyright (c) 2009 Boris Schaeling
|
ian@0
|
8 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
ian@0
|
9 //
|
ian@0
|
10 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
ian@0
|
11 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
ian@0
|
12 //
|
ian@0
|
13
|
ian@0
|
14 /**
|
ian@0
|
15 * \file boost/process/detail/systembuf.hpp
|
ian@0
|
16 *
|
ian@0
|
17 * Includes the declaration of the systembuf class.
|
ian@0
|
18 */
|
ian@0
|
19
|
ian@0
|
20 #ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
|
ian@0
|
21 #define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
|
ian@0
|
22
|
ian@0
|
23 #include <boost/process/config.hpp>
|
ian@0
|
24
|
ian@0
|
25 #if defined(BOOST_POSIX_API)
|
ian@0
|
26 # include <sys/types.h>
|
ian@0
|
27 # include <unistd.h>
|
ian@0
|
28 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
29 # include <windows.h>
|
ian@0
|
30 #else
|
ian@0
|
31 # error "Unsupported platform."
|
ian@0
|
32 #endif
|
ian@0
|
33
|
ian@0
|
34 #include <boost/noncopyable.hpp>
|
ian@0
|
35 #include <boost/scoped_array.hpp>
|
ian@0
|
36 #include <boost/assert.hpp>
|
ian@0
|
37 #include <streambuf>
|
ian@0
|
38 #include <cstddef>
|
ian@0
|
39
|
ian@0
|
40 namespace boost {
|
ian@0
|
41 namespace process {
|
ian@0
|
42
|
ian@0
|
43 class postream;
|
ian@0
|
44
|
ian@0
|
45 namespace detail {
|
ian@0
|
46
|
ian@0
|
47 /**
|
ian@0
|
48 * std::streambuf implementation for handles.
|
ian@0
|
49 *
|
ian@0
|
50 * systembuf provides a std::streambuf implementation for handles.
|
ian@0
|
51 * Contrarywise to the handle class, this class does \b not take
|
ian@0
|
52 * ownership of the native handle; this should be taken care of
|
ian@0
|
53 * somewhere else.
|
ian@0
|
54 *
|
ian@0
|
55 * This class follows the expected semantics of a std::streambuf object.
|
ian@0
|
56 * However, it is not copyable to avoid introducing inconsistences with
|
ian@0
|
57 * the on-disk file and the in-memory buffers.
|
ian@0
|
58 */
|
ian@0
|
59 class systembuf : public std::streambuf, public boost::noncopyable
|
ian@0
|
60 {
|
ian@0
|
61 friend class boost::process::postream;
|
ian@0
|
62
|
ian@0
|
63 public:
|
ian@0
|
64 #if defined(BOOST_PROCESS_DOXYGEN)
|
ian@0
|
65 /**
|
ian@0
|
66 * Opaque name for the native handle type.
|
ian@0
|
67 */
|
ian@0
|
68 typedef NativeHandleType handle_type;
|
ian@0
|
69 #elif defined(BOOST_POSIX_API)
|
ian@0
|
70 typedef int handle_type;
|
ian@0
|
71 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
72 typedef HANDLE handle_type;
|
ian@0
|
73 #endif
|
ian@0
|
74
|
ian@0
|
75 /**
|
ian@0
|
76 * Constructs a new systembuf for the given handle.
|
ian@0
|
77 *
|
ian@0
|
78 * This constructor creates a new systembuf object that reads or
|
ian@0
|
79 * writes data from/to the \a h native handle. This handle
|
ian@0
|
80 * is \b not owned by the created systembuf object; the code
|
ian@0
|
81 * should take care of it externally.
|
ian@0
|
82 *
|
ian@0
|
83 * This class buffers input and output; the buffer size may be
|
ian@0
|
84 * tuned through the \a bufsize parameter, which defaults to 8192
|
ian@0
|
85 * bytes.
|
ian@0
|
86 *
|
ian@0
|
87 * \see pistream and postream
|
ian@0
|
88 */
|
ian@0
|
89 explicit systembuf(handle_type h, std::size_t bufsize = 8192)
|
ian@0
|
90 : handle_(h),
|
ian@0
|
91 bufsize_(bufsize),
|
ian@0
|
92 read_buf_(new char[bufsize]),
|
ian@0
|
93 write_buf_(new char[bufsize])
|
ian@0
|
94 {
|
ian@0
|
95 #if defined(BOOST_POSIX_API)
|
ian@0
|
96 BOOST_ASSERT(handle_ >= 0);
|
ian@0
|
97 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
98 BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE);
|
ian@0
|
99 #endif
|
ian@0
|
100 BOOST_ASSERT(bufsize_ > 0);
|
ian@0
|
101 setp(write_buf_.get(), write_buf_.get() + bufsize_);
|
ian@0
|
102 }
|
ian@0
|
103
|
ian@0
|
104 protected:
|
ian@0
|
105 /**
|
ian@0
|
106 * Reads new data from the native handle.
|
ian@0
|
107 *
|
ian@0
|
108 * This operation is called by input methods when there is no more
|
ian@0
|
109 * data in the input buffer. The function fills the buffer with new
|
ian@0
|
110 * data, if available.
|
ian@0
|
111 *
|
ian@0
|
112 * \pre All input positions are exhausted (gptr() >= egptr()).
|
ian@0
|
113 * \post The input buffer has new data, if available.
|
ian@0
|
114 * \returns traits_type::eof() if a read error occurrs or there are
|
ian@0
|
115 * no more data to be read. Otherwise returns
|
ian@0
|
116 * traits_type::to_int_type(*gptr()).
|
ian@0
|
117 */
|
ian@0
|
118 virtual int_type underflow()
|
ian@0
|
119 {
|
ian@0
|
120 BOOST_ASSERT(gptr() >= egptr());
|
ian@0
|
121
|
ian@0
|
122 bool ok;
|
ian@0
|
123 #if defined(BOOST_POSIX_API)
|
ian@0
|
124 ssize_t cnt = read(handle_, read_buf_.get(), bufsize_);
|
ian@0
|
125 ok = (cnt != -1 && cnt != 0);
|
ian@0
|
126 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
127 DWORD cnt;
|
ian@0
|
128 BOOL res = ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL);
|
ian@0
|
129 ok = (res && cnt > 0);
|
ian@0
|
130 #endif
|
ian@0
|
131
|
ian@0
|
132 if (!ok)
|
ian@0
|
133 return traits_type::eof();
|
ian@0
|
134 else
|
ian@0
|
135 {
|
ian@0
|
136 setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt);
|
ian@0
|
137 return traits_type::to_int_type(*gptr());
|
ian@0
|
138 }
|
ian@0
|
139 }
|
ian@0
|
140
|
ian@0
|
141 /**
|
ian@0
|
142 * Makes room in the write buffer for additional data.
|
ian@0
|
143 *
|
ian@0
|
144 * This operation is called by output methods when there is no more
|
ian@0
|
145 * space in the output buffer to hold a new element. The function
|
ian@0
|
146 * first flushes the buffer's contents to disk and then clears it to
|
ian@0
|
147 * leave room for more characters. The given \a c character is
|
ian@0
|
148 * stored at the beginning of the new space.
|
ian@0
|
149 *
|
ian@0
|
150 * \pre All output positions are exhausted (pptr() >= epptr()).
|
ian@0
|
151 * \post The output buffer has more space if no errors occurred
|
ian@0
|
152 * during the write to disk.
|
ian@0
|
153 * \post *(pptr() - 1) is \a c.
|
ian@0
|
154 * \returns traits_type::eof() if a write error occurrs. Otherwise
|
ian@0
|
155 * returns traits_type::not_eof(c).
|
ian@0
|
156 */
|
ian@0
|
157 virtual int_type overflow(int c)
|
ian@0
|
158 {
|
ian@0
|
159 BOOST_ASSERT(pptr() >= epptr());
|
ian@0
|
160
|
ian@0
|
161 if (sync() == -1)
|
ian@0
|
162 return traits_type::eof();
|
ian@0
|
163
|
ian@0
|
164 if (!traits_type::eq_int_type(c, traits_type::eof()))
|
ian@0
|
165 {
|
ian@0
|
166 traits_type::assign(*pptr(), static_cast<traits_type::char_type>(
|
ian@0
|
167 c));
|
ian@0
|
168 pbump(1);
|
ian@0
|
169 }
|
ian@0
|
170
|
ian@0
|
171 return traits_type::not_eof(c);
|
ian@0
|
172 }
|
ian@0
|
173
|
ian@0
|
174 /**
|
ian@0
|
175 * Flushes the output buffer to disk.
|
ian@0
|
176 *
|
ian@0
|
177 * Synchronizes the systembuf buffers with the contents of the file
|
ian@0
|
178 * associated to this object through the native handle. The output buffer
|
ian@0
|
179 * is flushed to disk and cleared to leave new room for more data.
|
ian@0
|
180 *
|
ian@0
|
181 * \returns 0 on success, -1 if an error occurred.
|
ian@0
|
182 */
|
ian@0
|
183 virtual int sync()
|
ian@0
|
184 {
|
ian@0
|
185 #if defined(BOOST_POSIX_API)
|
ian@0
|
186 ssize_t cnt = pptr() - pbase();
|
ian@0
|
187 bool ok = (write(handle_, pbase(), cnt) == cnt);
|
ian@0
|
188 if (ok)
|
ian@0
|
189 pbump(static_cast<int>(-cnt));
|
ian@0
|
190 return ok ? 0 : -1;
|
ian@0
|
191 #elif defined(BOOST_WINDOWS_API)
|
ian@0
|
192 long cnt = pptr() - pbase();
|
ian@0
|
193 DWORD rcnt;
|
ian@0
|
194 BOOL res = WriteFile(handle_, pbase(), cnt, &rcnt, NULL);
|
ian@0
|
195 bool ok = (res && static_cast<long>(rcnt) == cnt);
|
ian@0
|
196 if (ok)
|
ian@0
|
197 pbump(-cnt);
|
ian@0
|
198 return ok ? 0 : -1;
|
ian@0
|
199 #endif
|
ian@0
|
200 }
|
ian@0
|
201
|
ian@0
|
202 private:
|
ian@0
|
203 /**
|
ian@0
|
204 * Native handle used by the systembuf object.
|
ian@0
|
205 */
|
ian@0
|
206 handle_type handle_;
|
ian@0
|
207
|
ian@0
|
208 /**
|
ian@0
|
209 * Internal buffer size used during read and write operations.
|
ian@0
|
210 */
|
ian@0
|
211 std::size_t bufsize_;
|
ian@0
|
212
|
ian@0
|
213 /**
|
ian@0
|
214 * Internal buffer used during read operations.
|
ian@0
|
215 */
|
ian@0
|
216 boost::scoped_array<char> read_buf_;
|
ian@0
|
217
|
ian@0
|
218 /**
|
ian@0
|
219 * Internal buffer used during write operations.
|
ian@0
|
220 */
|
ian@0
|
221 boost::scoped_array<char> write_buf_;
|
ian@0
|
222 };
|
ian@0
|
223
|
ian@0
|
224 }
|
ian@0
|
225 }
|
ian@0
|
226 }
|
ian@0
|
227
|
ian@0
|
228 #endif
|