doc: clean up "exponential substitution" section
[barvinok/uuh.git] / fdstream.cc
blob7d20f7680231645ecda19b7721ee1bea37f3dc42
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 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() {
43 if (stream_p) {
44 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
49 int fdoutbuf::attach_fd(int fd, bool manage) {
50 int return_val = 0;
51 if (stream_p) {
52 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
54 error_condition.error = false;
55 if (fd >= 0) {
56 // duplicate the file descriptor if we are not managing it
57 if (!manage) fd = dup(fd);
58 if (fd == -1) {
59 error_condition.error = true;
60 error_condition.code = fdstream_error::dup;
61 return_val = -1;
63 else {
64 stream_p = fdopen(fd, "w");
65 if (!stream_p) {
66 error_condition.error = true;
67 error_condition.code = fdstream_error::open;
68 return_val = -1;
72 return return_val;
75 // the standard requires sync to return 0 for success and -1 for error
76 int fdoutbuf::sync() {
77 if (!stream_p) return -1;
78 int result;
79 do {
80 result = std::fflush(stream_p);
81 } while (result == EOF && errno == EINTR);
83 if (result == EOF) {
84 error_condition.error = true;
85 error_condition.code = fdstream_error::flush;
86 return -1;
88 return 0;
91 void fdoutbuf::close_filestream() {
92 if(stream_p) {
93 while (std::fclose(stream_p) == EOF && errno == EINTR); // this will flush the buffer
95 stream_p = 0;
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())) {
108 int result;
109 do {
110 result = std::fputc(c, stream_p);
111 } while (result == EOF && errno == EINTR);
113 if (result == EOF) {
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;
128 do {
129 result = std::fwrite(source, sizeof(char), remaining, stream_p);
130 source += result;
131 remaining -= result;
132 } while (remaining && (result || errno == EINTR));
134 if (remaining) {
135 error_condition.error = true;
136 error_condition.code = fdstream_error::eof;
137 num -= remaining;
139 return num;
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) {
151 reset();
154 fdinbuf::fdinbuf(int fd, bool manage): stream_p(0) {
155 attach_fd(fd, manage);
158 fdinbuf::~fdinbuf() {
159 if (stream_p) {
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) {
170 int return_val = 0;
171 if (stream_p) {
172 while (std::fclose(stream_p) == EOF && errno == EINTR);
174 reset();
175 if (fd >= 0) {
176 // duplicate the file descriptor if we are not managing it
177 if (!manage) fd = dup(fd);
178 if (fd == -1) {
179 error_condition.error = true;
180 error_condition.code = fdstream_error::dup;
181 return_val = -1;
183 else {
184 stream_p = fdopen(fd, "r");
185 if (!stream_p) {
186 error_condition.error = true;
187 error_condition.code = fdstream_error::open;
188 return_val = -1;
192 return return_val;
195 void fdinbuf::close_filestream() {
196 if (stream_p) {
197 while (std::fclose(stream_p) == EOF && errno == EINTR);
199 stream_p = 0;
200 reset();
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);
217 putback_count = 1;
220 // now insert a character into the bump position
221 int result;
222 do {
223 result = std::fgetc(stream_p);
224 } while (result == EOF && errno == EINTR);
226 if (result != EOF) *(putback_buffer + 1) = result;
227 else {
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),
235 putback_buffer + 1,
236 putback_buffer + 2);
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);
256 gbump(num);
257 chars_read = num;
260 else {
261 // first copy out putback buffer
262 if (available) {
263 traits_type::copy(dest, gptr(), available);
264 chars_read = available;
267 std::streamsize remaining = num - chars_read;
268 std::streamsize result;
269 do {
270 result = std::fread(dest + chars_read, sizeof(char), remaining, stream_p);
271 chars_read += result;
272 remaining -= result;
273 } while (remaining && (result || errno == EINTR));
275 if (remaining) {
276 error_condition.error = true;
277 error_condition.code = fdstream_error::eof;
278 return chars_read;
281 if (chars_read) {
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
285 int putback_count;
286 if (chars_read >= 2) {
287 *putback_buffer = *(dest + (chars_read - 2));
288 putback_count = 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);
298 putback_count = 2;
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),
306 putback_buffer + 2,
307 putback_buffer + 2);
310 return chars_read;
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);