barvinok 0.41.7
[barvinok.git] / fdstream.cc
blob82599f883b612f2ea604449f32cf20b1f55a0dd5
1 /* Copyright (C) 2004 and 2005 Chris Vine
3 The following code declares classes to read from and write to
4 Unix file descriptors.
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
20 02111-1307, USA.
24 #include <unistd.h>
25 #include <errno.h>
26 #include "fdstream.h"
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 #ifndef fileno
33 extern "C" int fileno(std::FILE*);
34 #endif
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() {
45 if (stream_p) {
46 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
51 int fdoutbuf::attach_fd(int fd, bool manage) {
52 int return_val = 0;
53 if (stream_p) {
54 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
56 error_condition.error = false;
57 if (fd >= 0) {
58 // duplicate the file descriptor if we are not managing it
59 if (!manage) fd = dup(fd);
60 if (fd == -1) {
61 error_condition.error = true;
62 error_condition.code = fdstream_error::dup;
63 return_val = -1;
65 else {
66 stream_p = fdopen(fd, "w");
67 if (!stream_p) {
68 error_condition.error = true;
69 error_condition.code = fdstream_error::open;
70 return_val = -1;
74 return return_val;
77 // the standard requires sync to return 0 for success and -1 for error
78 int fdoutbuf::sync() {
79 if (!stream_p) return -1;
80 int result;
81 do {
82 result = std::fflush(stream_p);
83 } while (result == EOF && errno == EINTR);
85 if (result == EOF) {
86 error_condition.error = true;
87 error_condition.code = fdstream_error::flush;
88 return -1;
90 return 0;
93 void fdoutbuf::close_filestream() {
94 if(stream_p) {
95 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
97 stream_p = 0;
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())) {
110 int result;
111 do {
112 result = std::fputc(c, stream_p);
113 } while (result == EOF && errno == EINTR);
115 if (result == EOF) {
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;
130 do {
131 result = std::fwrite(source, sizeof(char), remaining, stream_p);
132 source += result;
133 remaining -= result;
134 } while (remaining && (result || errno == EINTR));
136 if (remaining) {
137 error_condition.error = true;
138 error_condition.code = fdstream_error::eof;
139 num -= remaining;
141 return num;
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) {
153 reset();
156 fdinbuf::fdinbuf(int fd, bool manage): stream_p(0) {
157 attach_fd(fd, manage);
160 fdinbuf::~fdinbuf() {
161 if (stream_p) {
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) {
172 int return_val = 0;
173 if (stream_p) {
174 while (std::fclose(stream_p) == EOF && errno == EINTR);
176 reset();
177 if (fd >= 0) {
178 // duplicate the file descriptor if we are not managing it
179 if (!manage) fd = dup(fd);
180 if (fd == -1) {
181 error_condition.error = true;
182 error_condition.code = fdstream_error::dup;
183 return_val = -1;
185 else {
186 stream_p = fdopen(fd, "r");
187 if (!stream_p) {
188 error_condition.error = true;
189 error_condition.code = fdstream_error::open;
190 return_val = -1;
194 return return_val;
197 void fdinbuf::close_filestream() {
198 if (stream_p) {
199 while (std::fclose(stream_p) == EOF && errno == EINTR);
201 stream_p = 0;
202 reset();
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);
219 putback_count = 1;
222 // now insert a character into the bump position
223 int result;
224 do {
225 result = std::fgetc(stream_p);
226 } while (result == EOF && errno == EINTR);
228 if (result != EOF) *(putback_buffer + 1) = result;
229 else {
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),
237 putback_buffer + 1,
238 putback_buffer + 2);
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);
258 gbump(num);
259 chars_read = num;
262 else {
263 // first copy out putback buffer
264 if (available) {
265 traits_type::copy(dest, gptr(), available);
266 chars_read = available;
269 std::streamsize remaining = num - chars_read;
270 std::streamsize result;
271 do {
272 result = std::fread(dest + chars_read, sizeof(char), remaining, stream_p);
273 chars_read += result;
274 remaining -= result;
275 } while (remaining && (result || errno == EINTR));
277 if (remaining) {
278 error_condition.error = true;
279 error_condition.code = fdstream_error::eof;
280 return chars_read;
283 if (chars_read) {
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
287 int putback_count;
288 if (chars_read >= 2) {
289 *putback_buffer = *(dest + (chars_read - 2));
290 putback_count = 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);
300 putback_count = 2;
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),
308 putback_buffer + 2,
309 putback_buffer + 2);
312 return chars_read;
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);