home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_11_01
/
1101046a
< prev
next >
Wrap
Text File
|
1992-11-09
|
16KB
|
580 lines
#if !defined TSTREAM_H
#define TSTREAM_H
#include <iostream.h> // for base class definitions
// class tbuf<>. Derived publicly from streambuf to
// allow class ios which contains pointer to streambuf
// access to virtual functions. tbuf<> implements
// basic buffering, reading, writing and seeking on
// a stream. It also provides open, close, attach,
// and utility functions.
template <class T>
class tbuf : public streambuf {
public:
// openProtection provides a default parameter to the
// open functions to specify what protection a file
// will be created with. You can ignore this if it is
// not necessary
static const int openProtect;
// tbufSize specifies the default buffer size. It is
// set to 516 bytes.
static const int tbufSize;
// Default contructor. Make a buffer without a
// stream attached. mode has a dual meaning, if it
// is zero it means that any operation is allowable,
// and the stream should not be deleted when closing.
tbuf()
: stream(0), mode(0), opened(0)
{
makbuf();
}
// create buffer and attach to t. t is assumed to be
// already opened in read/write mode. t will not be
// deleted or closed when closing this buffer
tbuf(T &t)
: stream(&t), mode(0), opened(1)
{
makbuf();
}
// create buffer from parameters, and attach to t.
tbuf(T &t, char* b, int l)
: stream(&t), mode(0), opened(1)
{
setbuf(b, l);
}
// destroy buffer. If mode is not zero, t will be
// closed and deleted. Otherwise just flush the
// output buffer.
~tbuf()
{
if(mode)
close();
else
overflow(EOF);
}
// return open status
int is_open() const
{
return opened;
}
// return reference to stream
T &fd() const
{
return *stream;
}
// open stream. mode must not be zero. stream will
// be closed and deleted when closing buffer.
tbuf *open(const char *name, int mode,
int prot = tbuf::openProtect);
// close buffer and optionally delete stream.
tbuf *close();
// attach stream to buffer. Stream is assumed to
// be opened in read/write mode.
tbuf *attach(T &);
// write buffer to stream and reset pointers.
virtual int overflow(int = EOF);
// read data into buffer and reset pointers.
virtual int underflow();
// sync input and output.
virtual int sync();
// seek to offset and flush output buffers.
virtual long seekoff(long, ios::seek_dir, int);
// set buffer. For unbuffered i/o set char * to 0.
virtual streambuf *setbuf(char *, int);
protected:
int putBackSize()
{
return (blen() > 8) ? 4 : 1;
}
void resetpg(int end = 0);
void makbuf()
{
setbuf(new char[tbufSize], tbufSize);
}
int unbuffered()
{
return streambuf::unbuffered() | !base();
}
T *stream;
int mode;
short opened;
char lookAhead[2];
};
template <class T>
const int tbuf<T>::tbufSize = 516;
template <class T>
const int tbuf<T>::openProtect = 0;
// Attach an open stream to this buffer. When this
// buffer is closed don't try to close stream. If
// not yet buffered, try to create a buffer. Reset
// the put and get pointers. Return 0 on error, or
// this if OK.
template <class T>
tbuf<T>* tbuf<T>::attach(T &t)
{
if(opened) // if already opened, return 0
return 0;
stream = &t; // attach stream.
opened = 1; // set to opened.
mode = 0; // buffer doesn't own stream.
if(!base()) // if no buffer yet...
makbuf(); // try to make one.
else
resetpg(); // reset put and get pointers.
return this;
}
// Close buffer, and optionally stream attached to it.
// Flush buffer if data inside. Return 0 on error or
// this if OK.
template <class T>
tbuf<T>* tbuf<T>::close()
{
if(!*stream) // if stream closed,
opened = 0; // set opened off.
if(!opened) // if not on return 0.
return 0;
int ret = 0;
if(out_waiting()) // if output in buffer.
// flush output buffer.
ret = (overflow(EOF) == EOF) ? 1 : 0;
if(mode) // if mode is 0, don't
delete stream; // close or delete stream.
opened = 0; // set opened off.
return ret ? 0 : this;
}
// Write data from buffer to stream. This function
// is called when the buffer is full and we need to
// output more characters. The parameter c is the
// character that caused the overflow. If the
// stream is buffered, it will be placed in the
// buffer, otherwise it is written to the stream.
// If input char is EOF, don't write, just flush.
// Returns EOF on error, or 1 on success.
template <class T>
int tbuf<T>::overflow(int c)
{
if(!opened || // check to see if stream
mode == 0 || // is on and mode is out.
!(mode&ios::out))
return EOF;
if(unbuffered())
{
if(c != EOF)
{ // if unbuffered,
char b = c; // write single char
if(stream->write(&b, 1) != 1)
return EOF;
}
}
else // else if buffered.
{
if(sync() != 0) // sync input and output
return EOF; // when writing
resetpg(1); // reset the put/get pointers
if(c != EOF)
{
sputc(c); // add c to the buffer
gbump(1); // move the get pointer
}
}
return 1; // return OK
}
// Open stream. If mode ios::ate (at end) is on,
// seek to end
template <class T>
tbuf<T>* tbuf<T>::open(const char* n, int m, int p)
{
if(opened || !m) // if already on, or no mode,
return 0; // return error.
stream = new T; // make new stream pointer.
stream->open(n, m, p);// open stream.
if(!*stream) // if stream not open,
return 0; // return error.
opened = 1; // set to on.
mode = m; // remeber mode.
if((mode & ios::ate) &&
stream->seek(0L, ios::end) == EOF)
return 0; // seek to end if ios::ate.
resetpg(); // reset put/get pointers.
return this; // return OK.
}
// Set the buffer, reset the put/get pointers.
// Return 0 on error, this if OK.
template <class T>
streambuf* tbuf<T>::setbuf(char* b, int l)
{
if(!b) // turn off buffering.
{
streambuf::unbuffered(1);
return this;
}
if(opened && base())// check if stream is opened,
return 0; // , and no buffer yet.
setb(b, b+l, 0); // set buffer pointers.
resetpg(); // reset put/get pointers.
return this; // return OK.
}
// Seek to offset. dir indicates the relativity of
// the offset, ethier from beginning, current postion,
// or end (ios::beg, ios::cur, ios::end).
// First make sure there's nothing in the buffer.
template <class T>
long tbuf<T>::seekoff(long off, ios::seek_dir dir,
int /* mode ignored */)
{
long loff = off;
int count = out_waiting(); // flush output first.
if(count)
{
if(stream->write(pbase(), count) != count)
return EOF;
}
else if(dir == ios::cur && // if relative seek,
(count = in_avail()) != 0)
loff -= count; // discount input.
resetpg(); // reset pointers.
return stream->seek(loff, dir);
}
// sync input and output buffer pointers. If output
// is waiting, write it, if input is waiting,
// back up to read it again
template <class T>
int tbuf<T>::sync()
{
if (!opened) // check if opened.
return EOF;
int count = out_waiting(); // check for output,
if(count) // in buffer.
{
if(stream->write(pbase(), count) != count)
return EOF; // write output.
resetpg(1);
}
else if(in_avail()) // check for input
{ // in buffer
long pos = stream->seek(long(-in_avail()),
ios::cur);
setg(eback(), gptr(), gptr());
setp(gptr(), gptr()); // set up to re-read.
if(pos == EOF)
return EOF;
}
return 0;
}
// Read from stream to fill buffer. Must be opened and
// in input mode. If there is input in the buffer,
// return it. Otherwise call sync, read from stream,
// and set pointers. If the input is unbuffered,
// use the lookahead buffer.
template <class T>
int tbuf<T>::underflow()
{
if(!opened || mode == 0 || !(mode&ios::in))
return EOF; // check for correct mode.
if(in_avail()) // if available from buffer,
return *gptr()&0xFF; // don't bother.
int c;
int count;
if(unbuffered()) // if unbuffered.
{
count = stream->read(lookAhead, 1);
if(count == EOF) // read one char
{ // into look ahead
c = EOF; // buffer.
setg(0, 0, 0);
}
else
{
c = lookAhead[0]&0xFF;
setg(lookAhead, lookAhead, lookAhead+1);
}
}
else // else buffered.
{
if(sync() != 0) // sync pointers.
return EOF;
int pb = putBackSize();
char *b = base(); // read into buffer.
count = stream->read(b+pb, blen()-pb);
if(count == EOF) // check read return.
return EOF;
setg(b, b+pb, b+pb+count);
setp(b+pb, b+pb); // set pointers.
if(count) // return first char.
c = *gptr()&0xFF;
}
if(!count)
c = EOF;
return c;
}
// reset the put and get pointers. If end is
// true set the end pointers to the end of
// the buffer.
template<class T>
void tbuf<T>::resetpg(int end)
{
char *buf = base(); // get the start of buffer.
char *sbuf = buf + (buf ? putBackSize() : 0);
char *ebuf; // set start and end pointers.
if(end)
ebuf = buf + blen();
else
ebuf = sbuf;
setp(sbuf, ebuf); // set put pointer
setg(buf, sbuf, sbuf);// set get pointer
}
// tstreambase is virtually derived from ios. ios
// does not define any functionality for tstreambase
// but allows communication between tstreambase and
// istream, ostream and stream classes. The functions
// defined in tstreambase typically call the same
// named function for its tbuf<> member and set ios
// status flags. When a tstreambase is constructed
// ios is initialized with a pointer to the tbuf<>
// member. ios see this pointer as a streambuf
// pointer, and only has access to tbuf<> through the
// virtual functions, overflow, underflow, sync, and
// seekoff.
template <class T>
class tstreambase : virtual public ios {
public:
// Default constructor. Make an unattached
// buffer, and initialize ios with it's pointer.
tstreambase()
: tbbuf()
{
ios::init(&tbbuf);
}
// Make a buffer attach to named stream, and open
// stream
tstreambase(const char* n, int m,
int p = tbuf<T>::openProtect)
: tbbuf()
{
ios::init(&tbbuf);
open(n, m, p);
}
// Make a buffer attached to already opened stream.
tstreambase(T &f)
: tbbuf(f)
{
ios::init(&tbbuf);
}
// Make a buffer using parameters, and attach
// to already opened stream.
tstreambase(T &f, char* b, int l)
: tbbuf(f, b, l)
{
ios::init(&tbbuf);
}
// Destroy buffer
~tstreambase()
{
;
}
// close attached stream and set ios flags.
void close()
{
if(tbbuf.close())
clear(ios::goodbit);
else
setstate(ios::failbit);
}
// set buffer and set ios flags.
void tstreambase::setbuf(char* b, int l)
{
if(tbbuf.setbuf(b, l))
clear(ios::goodbit);
else
setstate(ios::failbit);
}
// open stream and set ios flags.
void open(const char *, int,
int = tbuf<T>::openProtect);
// attach opened stream and set ios flags.
void attach(T &);
// return the buffer.
tbuf<T> *rdbuf()
{
return &tbbuf;
}
private:
tbuf<T> tbbuf;
};
// Attempt to open tbuf<>, and set ios flags
// accordingly. Opening an already open stream
// results in an error. If ios::app (append to
// file) is set, also set ios::out. If ios::out
// is set, and ios::app, ios::in, and ios::ate
// (start at end) are not set, set the ios::trunc bit.
template <class T>
void tstreambase<T>::open(const char *n, int m, int p)
{
if(m & ios::app)
m |= ios::out;
else if((m & (ios::out|ios::ate|ios::app|ios::in))
== ios::out)
m |= ios::trunc;
if(tbbuf.is_open())
clear(ios::failbit);
else if(tbbuf.open(n, m, p))
clear(ios::goodbit);
else
clear(ios::badbit);
}
// Attach an opened stream to buffer, and set the ios
// bits accordingly.
template <class T>
void tstreambase<T>::attach(T &f)
{
if(tbbuf.is_open())
setstate(ios::failbit);
else if(tbbuf.attach(f))
clear(ios::goodbit);
else
clear(ios::badbit);
}
// The itstream, otstream and tstream class are merely
// "shell" classes, and serve only to combine the
// functionality of it's base class. The only functions
// defined are the constructor and destructors, and
// open and rdbuf. There are no addition data members
// and all functions call directly the functions of the
// base class. The default open mode is ios::in for
// itstream, ios::out for otstream, and both for
// tstream.
template <class T>
class itstream : public tstreambase<T>,
public istream {
public:
itstream()
{
;
}
itstream(const char* n, int m = ios::in,
int p = tbuf<T>::openProtect)
: tstreambase<T>(n, m | ios::in, p)
{
;
}
itstream(T &f)
: tstreambase<T>(f)
{
;
}
itstream(T &f, char* b, int l)
: tstreambase<T>(f, b, l)
{
;
}
~itstream()
{
;
}
tbuf<T> *rdbuf()
{
return tstreambase<T>::rdbuf();
}
void open(const char *n, int m = ios::in,
int p = tbuf<T>::openProtect)
{
tstreambase<T>::open(n, m | ios::in, p);
}
};
template <class T>
class otstream : public tstreambase<T>,
public ostream {
public:
otstream()
{
;
}
otstream(const char* n, int m = ios::out,
int p = tbuf<T>::openProtect)
: tstreambase<T>(n, m | ios::out, p)
{
;
}
otstream(T &f)
: tstreambase<T>(f)
{
;
}
otstream(T &f, char* b, int l)
: tstreambase<T>(f, b, l)
{
;
}
~otstream()
{
;
}
tbuf<T> *rdbuf()
{
return tstreambase<T>::rdbuf();
}
void open(const char *n, int m = ios::out,
int p = tbuf<T>::openProtect)
{
tstreambase<T>::open(n, m | ios::out, p);
}
};
template <class T>
class tstream : public tstreambase<T>,
public iostream {
public:
tstream()
{
;
}
tstream(const char *n, int m,
int p = tbuf<T>::openProtect)
: tstreambase<T>(n, m, p)
{
;
}
tstream(T &f)
: tstreambase<T>(f)
{
;
}
tstream(T &f, char *b, int l)
: tstreambase<T>(f, b, l), iostream()
{
;
}
~tstream()
{
;
}
tbuf<T> *rdbuf()
{
return tstreambase<T>::rdbuf();
}
void open(const char *n, int m,
int p = tbuf<T>::openProtect)
{
tstreambase<T>::open(n, m, p);
}
};
#endif