1 /* Copyright (C) 2004 and 2005 Chris Vine
3 The following code declares classes to read from and write to
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public License
8 as published by the Free Software Foundation; either version 2.1 of
9 the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library (see the file LGPL.TXT which came
18 with this source code package); if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 // fdopen() and fileno() are not in the C standard, so declare them here in case they are
29 // not in <cstdio> (in a POSIX conforming implementation they will be declared in <stdio.h>
30 // and will be linkable from the C library)
31 extern "C" std::FILE* fdopen(int, const char*);
32 extern "C" int fileno(std::FILE*);
34 fdoutbuf::fdoutbuf(): stream_p(0) {
35 error_condition
.error
= false;
38 fdoutbuf::fdoutbuf(int fd
, bool manage
): stream_p(0) {
39 attach_fd(fd
, manage
);
42 fdoutbuf::~fdoutbuf() {
44 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
49 int fdoutbuf::attach_fd(int fd
, bool manage
) {
52 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
54 error_condition
.error
= false;
56 // duplicate the file descriptor if we are not managing it
57 if (!manage
) fd
= dup(fd
);
59 error_condition
.error
= true;
60 error_condition
.code
= fdstream_error::dup
;
64 stream_p
= fdopen(fd
, "w");
66 error_condition
.error
= true;
67 error_condition
.code
= fdstream_error::open
;
75 // the standard requires sync to return 0 for success and -1 for error
76 int fdoutbuf::sync() {
77 if (!stream_p
) return -1;
80 result
= std::fflush(stream_p
);
81 } while (result
== EOF
&& errno
== EINTR
);
84 error_condition
.error
= true;
85 error_condition
.code
= fdstream_error::flush
;
91 void fdoutbuf::close_filestream() {
93 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
96 error_condition
.error
= false;
99 int fdoutbuf::get_fd() const {
100 if (!stream_p
) return -1;
101 return fileno(stream_p
);
104 // the standard requires this to return either the character
105 // written on overflow or traits_type::eof() (= EOF with char_type == char)
106 fdoutbuf::traits_type::int_type
fdoutbuf::overflow(int_type c
) {
107 if (!traits_type::eq_int_type(c
, traits_type::eof())) {
110 result
= std::fputc(c
, stream_p
);
111 } while (result
== EOF
&& errno
== EINTR
);
114 error_condition
.error
= true;
115 error_condition
.code
= fdstream_error::eof
;
116 return traits_type::eof();
119 return traits_type::not_eof(c
);
122 // the standard requires this to return the number of characters written
123 // (which will be 0 for stream failure - it is not correct to return EOF)
124 std::streamsize
fdoutbuf::xsputn(const char* source
, std::streamsize num
) {
126 std::streamsize remaining
= num
;
127 std::streamsize result
;
129 result
= std::fwrite(source
, sizeof(char), remaining
, stream_p
);
132 } while (remaining
&& (result
|| errno
== EINTR
));
135 error_condition
.error
= true;
136 error_condition
.code
= fdstream_error::eof
;
142 fdostream::fdostream(int fd
, bool manage
): std::ostream(0), buf(fd
, manage
) {
143 std::ostream::rdbuf(&buf
);
146 fdostream::fdostream(): std::ostream(0) {
147 std::ostream::rdbuf(&buf
);
150 fdinbuf::fdinbuf(): stream_p(0) {
154 fdinbuf::fdinbuf(int fd
, bool manage
): stream_p(0) {
155 attach_fd(fd
, manage
);
158 fdinbuf::~fdinbuf() {
160 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
164 void fdinbuf::reset() {
165 setg(putback_buffer
+ 1, putback_buffer
+ 1, putback_buffer
+ 1);
166 error_condition
.error
= false;
169 int fdinbuf::attach_fd(int fd
, bool manage
) {
172 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
176 // duplicate the file descriptor if we are not managing it
177 if (!manage
) fd
= dup(fd
);
179 error_condition
.error
= true;
180 error_condition
.code
= fdstream_error::dup
;
184 stream_p
= fdopen(fd
, "r");
186 error_condition
.error
= true;
187 error_condition
.code
= fdstream_error::open
;
195 void fdinbuf::close_filestream() {
197 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
203 int fdinbuf::get_fd() const {
204 if (!stream_p
) return -1;
205 return fileno(stream_p
);
208 // the standard requires this to return the first character available
209 // on underflow or traits_type::eof() (= EOF with char_type == char)
210 fdinbuf::traits_type::int_type
fdinbuf::underflow() {
211 if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
213 int putback_count
= 0;
214 // copy the character in bump position (if any) to putback position
215 if (gptr() - eback()) {
216 *putback_buffer
= *(gptr() - 1);
220 // now insert a character into the bump position
223 result
= std::fgetc(stream_p
);
224 } while (result
== EOF
&& errno
== EINTR
);
226 if (result
!= EOF
) *(putback_buffer
+ 1) = result
;
228 error_condition
.error
= true;
229 error_condition
.code
= fdstream_error::eof
;
230 return traits_type::eof();
233 // reset buffer pointers
234 setg(putback_buffer
+ (1 - putback_count
),
238 // return character in bump/peek position
239 return result
; // == *(putback_buffer + 1) == *gptr()
242 // the standard requires this to return the number of characters fetched
243 // (which will be 0 for stream failure - it is not correct to return EOF)
244 std::streamsize
fdinbuf::xsgetn(char* dest
, std::streamsize num
) {
246 std::streamsize chars_read
= 0;
248 // available would normally be 0, but could be up to 2 if there
249 // have been putbacks or a peek and a putback
250 std::streamsize available
= egptr() - gptr();
252 // if num is less than or equal to the characters already in the
253 // putback buffer, extract from buffer
254 if (num
<= available
) {
255 traits_type::copy(dest
, gptr(), num
);
261 // first copy out putback buffer
263 traits_type::copy(dest
, gptr(), available
);
264 chars_read
= available
;
267 std::streamsize remaining
= num
- chars_read
;
268 std::streamsize result
;
270 result
= std::fread(dest
+ chars_read
, sizeof(char), remaining
, stream_p
);
271 chars_read
+= result
;
273 } while (remaining
&& (result
|| errno
== EINTR
));
276 error_condition
.error
= true;
277 error_condition
.code
= fdstream_error::eof
;
282 // now mimic extraction of all characters by sbumpc() by putting
283 // two characters into the putback buffer (if available) and resetting the
284 // putback buffer pointers
286 if (chars_read
>= 2) {
287 *putback_buffer
= *(dest
+ (chars_read
- 2));
290 else { // if we have reached here then we have only fetched
291 // one character and it must have been read with
292 // fread() and not taken from the putback
293 // buffer - otherwise we would have ended
294 // at the first if block in this method
295 // - and this also means that gptr() == egptr()
296 if (gptr() - eback()) {
297 *putback_buffer
= *(gptr() - 1);
300 else putback_count
= 1;
302 *(putback_buffer
+ 1) = *(dest
+ (chars_read
- 1));
304 // reset putback buffer pointers
305 setg(putback_buffer
+ (2 - putback_count
),
313 fdistream::fdistream(int fd
, bool manage
): std::istream(0), buf(fd
, manage
) {
314 std::istream::rdbuf(&buf
);
317 fdistream::fdistream(): std::istream(0) {
318 std::istream::rdbuf(&buf
);