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*);
33 extern "C" int fileno(std::FILE*);
36 fdoutbuf::fdoutbuf(): stream_p(0) {
37 error_condition
.error
= false;
40 fdoutbuf::fdoutbuf(int fd
, bool manage
): stream_p(0) {
41 attach_fd(fd
, manage
);
44 fdoutbuf::~fdoutbuf() {
46 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
51 int fdoutbuf::attach_fd(int fd
, bool manage
) {
54 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
56 error_condition
.error
= false;
58 // duplicate the file descriptor if we are not managing it
59 if (!manage
) fd
= dup(fd
);
61 error_condition
.error
= true;
62 error_condition
.code
= fdstream_error::dup
;
66 stream_p
= fdopen(fd
, "w");
68 error_condition
.error
= true;
69 error_condition
.code
= fdstream_error::open
;
77 // the standard requires sync to return 0 for success and -1 for error
78 int fdoutbuf::sync() {
79 if (!stream_p
) return -1;
82 result
= std::fflush(stream_p
);
83 } while (result
== EOF
&& errno
== EINTR
);
86 error_condition
.error
= true;
87 error_condition
.code
= fdstream_error::flush
;
93 void fdoutbuf::close_filestream() {
95 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
); // this will flush the buffer
98 error_condition
.error
= false;
101 int fdoutbuf::get_fd() const {
102 if (!stream_p
) return -1;
103 return fileno(stream_p
);
106 // the standard requires this to return either the character
107 // written on overflow or traits_type::eof() (= EOF with char_type == char)
108 fdoutbuf::traits_type::int_type
fdoutbuf::overflow(int_type c
) {
109 if (!traits_type::eq_int_type(c
, traits_type::eof())) {
112 result
= std::fputc(c
, stream_p
);
113 } while (result
== EOF
&& errno
== EINTR
);
116 error_condition
.error
= true;
117 error_condition
.code
= fdstream_error::eof
;
118 return traits_type::eof();
121 return traits_type::not_eof(c
);
124 // the standard requires this to return the number of characters written
125 // (which will be 0 for stream failure - it is not correct to return EOF)
126 std::streamsize
fdoutbuf::xsputn(const char* source
, std::streamsize num
) {
128 std::streamsize remaining
= num
;
129 std::streamsize result
;
131 result
= std::fwrite(source
, sizeof(char), remaining
, stream_p
);
134 } while (remaining
&& (result
|| errno
== EINTR
));
137 error_condition
.error
= true;
138 error_condition
.code
= fdstream_error::eof
;
144 fdostream::fdostream(int fd
, bool manage
): std::ostream(0), buf(fd
, manage
) {
145 std::ostream::rdbuf(&buf
);
148 fdostream::fdostream(): std::ostream(0) {
149 std::ostream::rdbuf(&buf
);
152 fdinbuf::fdinbuf(): stream_p(0) {
156 fdinbuf::fdinbuf(int fd
, bool manage
): stream_p(0) {
157 attach_fd(fd
, manage
);
160 fdinbuf::~fdinbuf() {
162 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
166 void fdinbuf::reset() {
167 setg(putback_buffer
+ 1, putback_buffer
+ 1, putback_buffer
+ 1);
168 error_condition
.error
= false;
171 int fdinbuf::attach_fd(int fd
, bool manage
) {
174 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
178 // duplicate the file descriptor if we are not managing it
179 if (!manage
) fd
= dup(fd
);
181 error_condition
.error
= true;
182 error_condition
.code
= fdstream_error::dup
;
186 stream_p
= fdopen(fd
, "r");
188 error_condition
.error
= true;
189 error_condition
.code
= fdstream_error::open
;
197 void fdinbuf::close_filestream() {
199 while (std::fclose(stream_p
) == EOF
&& errno
== EINTR
);
205 int fdinbuf::get_fd() const {
206 if (!stream_p
) return -1;
207 return fileno(stream_p
);
210 // the standard requires this to return the first character available
211 // on underflow or traits_type::eof() (= EOF with char_type == char)
212 fdinbuf::traits_type::int_type
fdinbuf::underflow() {
213 if (gptr() < egptr()) return traits_type::to_int_type(*gptr());
215 int putback_count
= 0;
216 // copy the character in bump position (if any) to putback position
217 if (gptr() - eback()) {
218 *putback_buffer
= *(gptr() - 1);
222 // now insert a character into the bump position
225 result
= std::fgetc(stream_p
);
226 } while (result
== EOF
&& errno
== EINTR
);
228 if (result
!= EOF
) *(putback_buffer
+ 1) = result
;
230 error_condition
.error
= true;
231 error_condition
.code
= fdstream_error::eof
;
232 return traits_type::eof();
235 // reset buffer pointers
236 setg(putback_buffer
+ (1 - putback_count
),
240 // return character in bump/peek position
241 return result
; // == *(putback_buffer + 1) == *gptr()
244 // the standard requires this to return the number of characters fetched
245 // (which will be 0 for stream failure - it is not correct to return EOF)
246 std::streamsize
fdinbuf::xsgetn(char* dest
, std::streamsize num
) {
248 std::streamsize chars_read
= 0;
250 // available would normally be 0, but could be up to 2 if there
251 // have been putbacks or a peek and a putback
252 std::streamsize available
= egptr() - gptr();
254 // if num is less than or equal to the characters already in the
255 // putback buffer, extract from buffer
256 if (num
<= available
) {
257 traits_type::copy(dest
, gptr(), num
);
263 // first copy out putback buffer
265 traits_type::copy(dest
, gptr(), available
);
266 chars_read
= available
;
269 std::streamsize remaining
= num
- chars_read
;
270 std::streamsize result
;
272 result
= std::fread(dest
+ chars_read
, sizeof(char), remaining
, stream_p
);
273 chars_read
+= result
;
275 } while (remaining
&& (result
|| errno
== EINTR
));
278 error_condition
.error
= true;
279 error_condition
.code
= fdstream_error::eof
;
284 // now mimic extraction of all characters by sbumpc() by putting
285 // two characters into the putback buffer (if available) and resetting the
286 // putback buffer pointers
288 if (chars_read
>= 2) {
289 *putback_buffer
= *(dest
+ (chars_read
- 2));
292 else { // if we have reached here then we have only fetched
293 // one character and it must have been read with
294 // fread() and not taken from the putback
295 // buffer - otherwise we would have ended
296 // at the first if block in this method
297 // - and this also means that gptr() == egptr()
298 if (gptr() - eback()) {
299 *putback_buffer
= *(gptr() - 1);
302 else putback_count
= 1;
304 *(putback_buffer
+ 1) = *(dest
+ (chars_read
- 1));
306 // reset putback buffer pointers
307 setg(putback_buffer
+ (2 - putback_count
),
315 fdistream::fdistream(int fd
, bool manage
): std::istream(0), buf(fd
, manage
) {
316 std::istream::rdbuf(&buf
);
319 fdistream::fdistream(): std::istream(0) {
320 std::istream::rdbuf(&buf
);