| /* This is part of libio/iostream, providing -*- C++ -*- input/output. |
| Copyright (C) 1993 Free Software Foundation |
| |
| This file is part of the GNU IO Library. This library is free |
| software; you can redistribute it and/or modify it under the |
| terms of the GNU General Public License as published by the |
| Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this library; see the file COPYING. If not, write to the Free |
| Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| |
| As a special exception, if you link this library with files |
| compiled with a GNU compiler to produce an executable, this does not cause |
| the resulting executable to be covered by the GNU General Public License. |
| This exception does not however invalidate any other reasons why |
| the executable file might be covered by the GNU General Public License. */ |
| |
| /* Written by Per Bothner (bothner@cygnus.com). */ |
| |
| #ifdef __GNUG__ |
| #pragma implementation |
| #endif |
| |
| #include <stdiostream.h> |
| #include "libioP.h" |
| |
| // A stdiobuf is "tied" to a FILE object (as used by the stdio package). |
| // Thus a stdiobuf is always synchronized with the corresponding FILE, |
| // though at the cost of some overhead. (If you use the implementation |
| // of stdio supplied with this library, you don't need stdiobufs.) |
| // This implementation inherits from filebuf, but implement the virtual |
| // functions sys_read/..., using the stdio functions fread/... instead |
| // of the low-level read/... system calls. This has the advantage that |
| // we get all of the nice filebuf semantics automatically, though |
| // with some overhead. |
| |
| |
| #ifndef SEEK_SET |
| #define SEEK_SET 0 |
| #endif |
| #ifndef SEEK_CUR |
| #define SEEK_CUR 1 |
| #endif |
| #ifndef SEEK_END |
| #define SEEK_END 2 |
| #endif |
| |
| stdiobuf::stdiobuf(FILE *f) : filebuf(fileno(f)) |
| { |
| _file = f; |
| // Turn off buffer in stdiobuf. Instead, rely on buffering in (FILE). |
| // Thus the stdiobuf will be synchronized with the FILE. |
| setbuf(NULL, 0); |
| } |
| |
| stdiobuf::~stdiobuf() |
| { |
| /* Only needed if we're buffered. Not buffered is the default. */ |
| _IO_do_flush((_IO_FILE*)this); |
| } |
| |
| streamsize stdiobuf::sys_read(char* buf, streamsize size) |
| { |
| // A minor optimization, but it makes a noticable difference. |
| // A bigger optimization would be to write stdiobuf::underflow, |
| // but that has some modularity disadvantages. Re-evaluate that |
| // after we have gotten rid of the double indirection. FIXME |
| if (size == 1) |
| { |
| register ch = getc(_file); |
| if (ch == EOF) |
| return 0; |
| *buf = (char)ch; |
| return 1; |
| } |
| else |
| return fread(buf, 1, size, _file); |
| } |
| |
| streamsize stdiobuf::sys_write(const char *buf, streamsize n) |
| { |
| _IO_ssize_t count = fwrite(buf, 1, n, _file); |
| if (_offset >= 0) |
| _offset += n; |
| return count; |
| } |
| |
| streampos stdiobuf::sys_seek(streamoff offset, _seek_dir dir) |
| { |
| // Normally, equivalent to: fdir=dir |
| int fdir = |
| (dir == ios::beg) ? SEEK_SET : |
| (dir == ios::cur) ? SEEK_CUR : |
| (dir == ios::end) ? SEEK_END : |
| dir; |
| return fseek(_file, offset, fdir); |
| } |
| |
| int stdiobuf::sys_close() |
| { |
| int status = fclose(_file); |
| _file = NULL; |
| return status; |
| } |
| |
| int stdiobuf::sync() |
| { |
| if (_IO_do_flush((_IO_FILE*)this)) |
| return EOF; |
| if (!(xflags() & _IO_NO_WRITES)) |
| if (fflush(_file)) |
| return EOF; |
| return 0; |
| } |
| |
| int stdiobuf::overflow(int c /* = EOF*/) |
| { |
| if (filebuf::overflow(c) == EOF) |
| return EOF; |
| if (c != EOF) |
| return c; |
| return fflush(_file); |
| } |
| |
| streamsize stdiobuf::xsputn(const char* s, streamsize n) |
| { |
| if (buffered ()) |
| { |
| // The filebuf implementation of sputn loses. |
| return streambuf::xsputn(s, n); |
| } |
| else |
| return fwrite (s, 1, n, _file); |
| } |
| |
| void stdiobuf::buffered (int b) |
| { |
| if (b) |
| { |
| if (_flags & _IO_UNBUFFERED) |
| { /* Was unbuffered, make it buffered. */ |
| _flags &= ~_IO_UNBUFFERED; |
| } |
| } |
| else |
| { |
| if (!(_flags & _IO_UNBUFFERED)) |
| { /* Was buffered, make it unbuffered. */ |
| setbuf(NULL, 0); |
| } |
| } |
| } |