|
|
#include <iostream.h>typedef long streamoff, streampos; class ios { public: enum seek_dir { beg, cur, end }; enum open_mode { in, out, ate, app, trunc, nocreate, noreplace }; // and lots of other stuff, see ios(C++) ... } ;
class streambuf { public: streambuf() ; streambuf(char* p, int len); void dbp() ; protected: int allocate(); char* base(); int blen(); char* eback(); char* ebuf(); char* egptr(); char* epptr(); void gbump(int n); char* gptr(); char* pbase(); void pbump(int n); char* pptr(); void setg(char* eb, char* g, char* eg); void setp(char* p, char* ep); void setb(char* b, char* eb, int a=0); int unbuffered(); void unbuffered(int);
virtual int doallocate(); virtual ~streambuf() ;
public: virtual int pbackfail(int c); virtual int overflow(int c=EOF); virtual int underflow(); virtual streambuf* setbuf(char* p, int len); streambuf* setbuf(unsigned char* p, in len); virtual streampos seekpos(streampos, int =ios::in|ios:out); virtual streampos seekoff(streamoff, seek_dir, int =ios::in|ios:out); virtual int sync(); };
streambuf
s implement the buffer abstraction described in
sbuf.pub(C++).
However, the streambuf
class itself contains
only basic members for manipulating the characters and normally
a class derived from streambuf
will be used.
This man page describes the interface needed by programmers who are
coding a derived class.
Broadly speaking there are two kinds of member functions described here.
The non-virtual functions are provided for manipulating a streambuf
in ways that are appropriate in a derived class.
Their descriptions reveal details of the implementation that would
be inappropriate in the public interface.
The virtual functions permit the derived class to specialize the
streambuf
class in ways appropriate to the specific sources
and sinks that it is implementing.
The descriptions of the virtual functions explain the obligations of the
virtuals of the derived class. If the virtuals behave as specified,
the streambuf
will behave as specified in the
public interface. However, if the virtuals do not behave as
specified, then the streambuf
may not behave properly,
and an iostream
(or any other code) that relies on proper
behavior of the streambuf
may not behave properly either.
In the following descriptions assume:
streambuf*
int
s
char*
s
int
character (positive or EOF)
streampos
; see
sbuf.pub(C++)
streamoff
seekdir
int
representing an open_mode
streambuf()
streambuf(
b,
len)
streambuf
present an interface to derived classes organized around
three areas (arrays of bytes) managed cooperatively by
the base and derived classes.
They are the get area, the put area, and the
reserve area (or buffer).
The get and the put areas are normally disjoint, but they
may both overlap the reserve area, whose primary purpose is
to be a resource in which
space for the put and get areas can be allocated.
The get and the put areas are changed as characters are put into and
gotten from the buffer, but the reserve area normally remains
fixed.
The areas are defined by a collection of char*
values.
The buffer abstraction is described in terms of pointers that point
between characters, but the char*
values must point at
char
s.
To establish a correspondence, the char*
values should be thought
of as pointing just before the byte they really point at.
=
sb->base()
->base()
and sb->ebuf()
is the reserve area.
=
sb->eback()
->gptr()
.
Space between sb->eback()
and sb->gptr()
is available
for putback.
=
sb->ebuf()
=
sb->egptr()
=
sb->epptr()
=
sb->gptr()
->gptr()
and sb->egptr()
.
The next character fetched will
be *
sb->gptr())
unless sb->egptr()
is less than
or equal to sb->gptr()
.
=
sb->pbase()
->pbase()
and sb->pptr()
have been stored into the buffer and not yet consumed.
=
sb->pptr()
sb
->pptr()
and sb
->epptr()
is the put area and characters will be stored here.
->setb(
b,
eb,
i)
base()
and ebuf()
to b and eb respectively.
i controls whether the area will be subject to automatic deletion.
If i is non-zero, then
b will be deleted when base
is changed by
another call of setb()
, or when the destructor is called for
*
sb.
If b and eb
are both null then we say that there is no reserve area.
If b is non-null, there is a reserve area even if
eb is less than b and so the reserve area
has zero length.
->setp(
p,
ep)
pptr()
to p, pbase()
to p, and epptr()
to ep.
->setg(
eb,
g,
eg)
eback()
to eb, gptr()
to g, and egptr()
to eg.
=
sb->allocate()
->unbuffered()
is nonzero, allocate()
returns 0 without doing anything.
If the attempt to allocate space fails, allocate()
returns EOF, otherwise (allocation succeeds)
allocate()
returns 0.
allocate()
is not called by any non-virtual member function
of streambuf
.
=
sb->blen()
char
s) of the current reserve area.
dbp()
->gbump(
n)
gptr()
by n
which may be positive or negative.
No checks are made on whether the new
value of gptr()
is in bounds.
->pbump(
n)
pptr()
by n
which may be positive or negative.
No checks are made on whether the new
value of pptr()
is in bounds.
->unbuffered(i)
=
sb->unbuffered()
->unbuffered(
i)
sets the value of this variable
to i and sb->unbuffered()
returns the current value.
This state is independent of the actual
allocation of a reserve area. Its primary purpose is to
control whether a reserve area is allocated automatically
by allocate
.
streambuf
s.
This section describes the behavior that these virtual functions
should have in any derived classes;
the next section describes the behavior that these functions
are defined to have in base class streambuf
.
=
sb->doallocate()
allocate()
determines that space is needed.
doallocate()
is required to call setb()
to provide a reserve
area or to return EOF if it cannot. It is only called
if sb->unbuffered()
is zero and sb->base()
is zero.
=overflow(
c)
overflow()
also must either save c or consume it.
Usually it is called when the put area is full and
an attempt is being made to store a new character, but
it can be called at other times.
The normal action is to consume the characters
between pbase()
and pptr()
,
call setp()
to establish a new put area, and
if c!=EOF store it (using sputc()
).
sb->overflow()
should return EOF to indicate an error; otherwise it should
return something else.
=
sb->pbackfail(
c)-
Is called when
eback()
equals gptr()
and an attempt
has been made to putback c.
If this situation can be dealt with (e.g., by repositioning
an external file), pbackfail()
should return c;
otherwise it should return EOF.
=
sb->seekoff(
off,
dir,
mode)
pptr()
and gptr()
). The
meanings of off and dir are discussed in
sbuf.pub(C++).
mode specifies whether the put pointer (ios::out
bit set) or
the get pointer (ios::in
bit set) is to be modified.
Both bits may be set, in which case both pointers should be affected.
A class derived from streambuf
is not required to
support repositioning.
seekoff()
should return EOF if
the class does not support repositioning.
If the class does support repositioning,
seekoff()
should return the new position or EOF on error.
=
sb->seekpos(
pos,
mode)
streambuf
get and/or put pointer to pos.
mode specifies which pointers are affected as for seekoff()
.
Returns pos (the argument) or EOF if the class does
not support repositioning or an error occurs.
=
sb->setbuf(
ptr,
len)
setbuf()
should return sb if it honors the request.
Otherwise it should return 0.
i=
sb->sync()
sync()
should
consume any characters that have been stored into the put area,
and if possible give back to the source any characters in the get area
that have not been fetched.
When sync()
returns there should not
be any unconsumed characters, and the get area should be empty.
sync()
should return EOF if some kind of failure occurs.
=
sb->underflow()
underflow()
should return EOF and leave an empty get area.
The default definitions of the virtual functions:
=
sb->streambuf::doallocate()
operator new
.
=
sb->streambuf::overflow(
c)
streambuf::overflow()
should be treated as if
it had undefined behavior. That is, derived classes should
always define it.
=
sb->streambuf::pbackfail(
c)-
Returns
EOF.
=
sb->streambuf::seekpos(
pos,
mode)
->seekoff(streamoff(
pos),ios::beg,
mode)
.
Thus, to define seeking in a derived class, it is frequently
only necessary to define seekoff()
and use the inherited
streambuf::seekpos()
.
=
sb->streambuf::seekoff(
off,
dir,
mode)
=
sb->streambuf::setbuf(
ptr,
len)
=
sb->streambuf::sync()
i=
sb->streambuf::underflow()
streambuf::underflow()
should be treated as if
it had undefined behavior. That is, it should always be defined
in derived classes.
The interface for unbuffered actions is awkward.
It's hard to write underflow()
and overflow()
virtuals that behave properly
for unbuffered streambuf()
s without special casing.
Also there is no way for the virtuals to react sensibly to
multi-character gets or puts.
Although the public interface to streambuf
s
deals in characters and bytes,
the interface to derived classes deals in char
s.
Since a decision had to be made on the types of the real data
pointers, it seemed easier to reflect that choice in the
types of the protected members than to duplicate all
the members with both plain and unsigned char versions.
But perhaps all these uses of char*
ought to have been
with a typedef
.
The implementation contains a variant
of setbuf()
that accepts a third argument.
It is present only for compatibility
with the old stream package.