1 /* Copyright (C) 2004 The glibmm Development Team
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <glibmm/main.h>
22 fdstreambuf::fdstreambuf()
27 fdstreambuf::fdstreambuf(int fd, bool manage)
29 create_iochannel(fd, manage);
32 fdstreambuf::~fdstreambuf()
37 void fdstreambuf::reset()
39 setg(putback_buffer + 1, putback_buffer + 1, putback_buffer + 1);
40 error_condition.error = false;
43 void fdstreambuf::create_iochannel(int fd, bool manage)
50 iochannel_ = Glib::IOChannel::create_from_fd(fd);
52 #ifdef GLIBMM_EXCEPTIONS_ENABLED
53 iochannel_->set_encoding("");
55 std::auto_ptr<Glib::Error> ex;
56 iochannel_->set_encoding("", ex);
57 #endif //GLIBMM_EXCEPTIONS_ENABLED
59 iochannel_->set_buffered(true);
60 iochannel_->set_close_on_unref(manage);
64 void fdstreambuf::detach_fd()
66 iochannel_->set_close_on_unref(false);
69 void fdstreambuf::connect(const sigc::slot<bool, Glib::IOCondition>& callback,
70 Glib::IOCondition condition)
72 Glib::signal_io().connect(callback, iochannel_, condition);
75 fdstream_error fdstreambuf::get_error() const
77 return error_condition;
80 // the standard requires sync to return 0 for success and -1 for error
81 int fdstreambuf::sync()
86 #ifdef GLIBMM_EXCEPTIONS_ENABLED
91 catch(Glib::IOChannelError& io_error)
93 error_condition.error = true;
94 error_condition.code = io_error.code();
98 std::auto_ptr<Glib::Error> io_error;
99 iochannel_->flush(io_error);
102 error_condition.error = true;
103 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
106 #endif //GLIBMM_EXCEPTIONS_ENABLED
111 void fdstreambuf::close_iochannel()
113 iochannel_->set_close_on_unref(false);
116 #ifdef GLIBMM_EXCEPTIONS_ENABLED
119 iochannel_->close(true);
121 catch(Glib::IOChannelError& io_error)
123 error_condition.error = true;
124 error_condition.code = io_error.code();
127 std::auto_ptr<Glib::Error> io_error;
128 iochannel_->close(true, io_error);
131 error_condition.error = true;
132 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
134 #endif //GLIBMM_EXCEPTIONS_ENABLED
138 // the standard requires this to return either the character
139 // written on overflow or traits_type::eof() (= EOF with char_type == char)
140 fdstreambuf::traits_type::int_type fdstreambuf::overflow(int_type c)
142 if(!traits_type::eq_int_type(c, traits_type::eof()))
144 #ifdef GLIBMM_EXCEPTIONS_ENABLED
149 iochannel_->write(&write_char, 1, result);
151 catch(Glib::IOChannelError& io_error)
153 error_condition.error = true;
154 error_condition.code = io_error.code();
155 return traits_type::eof();
158 std::auto_ptr<Glib::Error> io_error;
161 iochannel_->write(&write_char, 1, result, io_error);
164 error_condition.error = true;
165 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
166 return traits_type::eof();;
168 #endif //GLIBMM_EXCEPTIONS_ENABLED
170 return traits_type::not_eof(c);
173 // the standard requires this to return the number of characters written
174 // (which will be 0 for stream failure - it is not correct to return EOF)
175 std::streamsize fdstreambuf::xsputn(const char* source, std::streamsize num)
179 // the documentation for Glib::IOChannel indicates that Glib::IOChannel::write()
180 // will only do a short write in the event of stream failure, so there is no
181 // need to check result and have a second bite (byte) at it as would be
182 // necessary with Unix write()
183 #ifdef GLIBMM_EXCEPTIONS_ENABLED
186 iochannel_->write(source, num, result);
188 catch(Glib::IOChannelError& io_error)
190 error_condition.error = true;
191 error_condition.code = io_error.code();
195 std::auto_ptr<Glib::Error> io_error;
196 iochannel_->write(source, num, result, io_error);
199 error_condition.error = true;
200 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
203 #endif //GLIBMM_EXCEPTIONS_ENABLED
208 // the standard requires this to return the first character available
209 // on underflow or traits_type::eof() (= EOF with char_type == char)
210 fdstreambuf::traits_type::int_type fdstreambuf::underflow()
213 return traits_type::to_int_type(*gptr());
215 // copy the character in bump position (if any) to putback position
217 *putback_buffer = *(gptr() - 1);
219 // now insert a character into the bump position
221 #ifdef GLIBMM_EXCEPTIONS_ENABLED
224 iochannel_->read(putback_buffer + 1, 1, result);
226 catch(Glib::IOChannelError& io_error)
228 error_condition.error = true;
229 error_condition.code = io_error.code();
230 return traits_type::eof();
233 std::auto_ptr<Glib::Error> io_error;
234 iochannel_->read(putback_buffer + 1, 1, result, io_error);
237 error_condition.error = true;
238 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
239 return traits_type::eof();
241 #endif //GLIBMM_EXCEPTIONS_ENABLED
243 // some other error - is this possible? In case it is, cater for it
245 return traits_type::eof();
247 // reset buffer pointers
252 // return character in bump/peek position
253 return traits_type::to_int_type(*gptr()); // == *(putback_buffer + 1)
256 // the standard requires this to return the number of characters fetched
257 // (which will be 0 for stream failure - it is not correct to return EOF)
258 std::streamsize fdstreambuf::xsgetn(char* dest, std::streamsize num)
260 std::streamsize chars_read = 0;
262 // available would normally be 0, but could be up to 2 if there
263 // have been putbacks or a peek and a putback
264 std::streamsize available = egptr() - gptr();
266 // if num is less than or equal to the characters already in the
267 // putback buffer, extract from buffer
268 if (num <= available)
270 traits_type::copy(dest, gptr(), num);
276 // first copy out putback buffer
279 traits_type::copy(dest, gptr(), available);
280 chars_read = available;
283 // read up to everything else we need with Glib::IOChannel::read()
285 #ifdef GLIBMM_EXCEPTIONS_ENABLED
289 std::auto_ptr<Glib::Error> io_error;
290 #endif //GLIBMM_EXCEPTIONS_ENABLED
293 #ifdef GLIBMM_EXCEPTIONS_ENABLED
294 iochannel_->read(dest + chars_read,
298 iochannel_->read(dest + chars_read,
301 #endif //GLIBMM_EXCEPTIONS_ENABLED
304 chars_read += result;
306 while (result > 0 && result < static_cast<gsize>(num - chars_read));
307 #ifdef GLIBMM_EXCEPTIONS_ENABLED
309 catch(Glib::IOChannelError& io_error)
312 #endif //GLIBMM_EXCEPTIONS_ENABLED
314 error_condition.error = true;
316 #ifdef GLIBMM_EXCEPTIONS_ENABLED
317 error_condition.code = io_error.code();
319 error_condition.code = (Glib::IOChannelError::Code)io_error->code();
320 #endif //GLIBMM_EXCEPTIONS_ENABLED
326 // now mimic extraction of all characters by sbumpc() by putting
327 // two characters into the buffer (if available) and resetting the
329 int putback_count = 0;
332 *putback_buffer = *(dest + (chars_read - 2));
336 { // if we have reached here then we have only fetched
337 // one character and it must have been read with
338 // Glib::IOChannel::read() and not taken from the
339 // putback buffer - otherwise we would have ended
340 // at the first if block in this method
341 // - and this also means that gptr() == egptr()
344 *putback_buffer = *(gptr() - 1);
347 else putback_count = 1;
350 *(putback_buffer + 1) = *(dest + (chars_read - 1));
352 // reset buffer pointers
353 this->setg(putback_buffer + (2 - putback_count),
361 fdstream::fdstream(int fd, bool manage)
366 std::istream::rdbuf(&buf);
367 std::ostream::rdbuf(&buf);
374 std::istream::rdbuf(&buf);
375 std::ostream::rdbuf(&buf);
378 void fdstream::attach(int fd, bool manage)
380 buf.create_iochannel(fd, manage);
383 void fdstream::detach()
388 void fdstream::close()
390 buf.close_iochannel();
393 void fdstream::connect(const sigc::slot<bool, Glib::IOCondition>& callback,
394 Glib::IOCondition condition)
396 buf.connect(callback, condition);
399 fdstream_error fdstream::get_error() const
401 return buf.get_error();