160 lines
4.2 KiB
C++
160 lines
4.2 KiB
C++
|
/* 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 int 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);
|
||
|
}
|
||
|
}
|
||
|
}
|