diff options
Diffstat (limited to 'libio/stdiostream.cc')
-rw-r--r-- | libio/stdiostream.cc | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libio/stdiostream.cc b/libio/stdiostream.cc new file mode 100644 index 00000000000..80db5e59bfd --- /dev/null +++ b/libio/stdiostream.cc @@ -0,0 +1,159 @@ +/* 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); + } + } +} |