/* C++ Stream I/O header file

    Copyright (c) Borland International 1987,1988,1990
    All Rights Reserved.

    %W%  %G% %U%

    NOTE: The data and function variables are declared so that any
    combination of alignment and size-of-enum compiler options will
    produce the same results.
*/

#if ! defined(_I_STREAM_H_)
// protect against multiple inclusion
#define _I_STREAM_H_
#include <stdio.h>

/*
 * whitespace
 */
struct whitespace { char x; };
extern struct whitespace WS;

class istream;
class ostream;

/*
 * basic stream buffer class
 */
class streambuf {
  friend istream;
  friend ostream;

  protected:
    FILE *file;			// if non-0, connected stdio file
    char *base;			// start of buffer
    char *pptr;			// next free char (for output)
    char *gptr;			// next avail char (for input)
    char *eptr;			// one off end of buffer
    int didalloc;		// non-0 if we allocated a buffer

    // empty full output buffer, put c in it
    virtual int _Cdecl overflow( int = EOF );

    // fill empty input buffer, get first char
    virtual int _Cdecl underflow();

    // allocate a buffer
    int _Cdecl allocate();

    // specify a buffer to use, possibly with data in it (offset > 0 )
    streambuf * _Cdecl setbuf( char *, int, unsigned = 0 );

    // add a null byte to a string without advancing pointer
    virtual void _Cdecl terminate();

  public:
    // constructor: no buffer
    _Cdecl streambuf()
	{ file = 0; didalloc = 0; base = pptr = gptr = eptr = 0; }

    // constructor: user buffer
    _Cdecl streambuf( char *buf, int len )
	{ file = 0; didalloc = 0; setbuf(buf, len); }

    // destructor
    virtual _Cdecl ~streambuf();

    // get next char from input buffer
    virtual int _Cdecl snextc();

    // write a char to output buffer
    virtual int _Cdecl sputc( int );

    // return a char to input buffer
    virtual void _Cdecl sputbackc( char );
};


/*
 * file buffer class
 */
enum open_mode { input, output, append }; // mode for opening a file

class filebuf: public streambuf {

  private:
    int fd;			// external file id
    int isopen;			// non-0 if open

  protected:

    // we don't need to add a null byte to a file
    void _Cdecl terminate() { };

  public:
    _Cdecl filebuf() { isopen = 0; fd = 0; } // basic constructor
    _Cdecl filebuf( FILE * );		// tie to existing stdio file
    _Cdecl filebuf( int );		// tie to existing file
    _Cdecl filebuf( int , char *, int ); // tie to file, user buffer
    _Cdecl ~filebuf() { close(); }	// destructor (virtual)

    // open a named external file
    filebuf * _Cdecl open( char *, int );

    // close the external file
    int _Cdecl close();

    // get next char from input buffer
    int _Cdecl snextc() { return ::fgetc(file); }

    // write a char to output buffer
    int _Cdecl sputc( int _C ) { return ::fputc(_C, file); }

    // return a char to input buffer
    void _Cdecl sputbackc( char _C ) { (void) ::ungetc(_C, file); }
};


/*
 * formatting functions
 */
char * _Cdecl dec( long, int = 0 );	// internal to decimal text
char * _Cdecl hex( long, int = 0 );	// internal to hex text
char * _Cdecl oct( long, int = 0 );	// internal to octal text

char * _Cdecl chr( int, int = 0 );	// char to string
char * _Cdecl str( const char *, int = 0 ); // make fixed-width string
char * _Cdecl form( char * ... );	// general formating


/*
 * state of istream or ostream
 */
enum stream_state { _good, _eof, _fail, _bad };

/*
 * class ostream
 */
class ostream {
  friend istream;

  private:
    streambuf *stream;			// connected streambuf or filebuf
    char mystream;			// non-0 if stream was alloc'd here
    char state;				// state of stream

  public:
    _Cdecl ostream( streambuf * );		// connect to existing streambuf
    _Cdecl ostream( int );			// connect to open file
    _Cdecl ostream( int, char * );		// connect to char array
    _Cdecl ~ostream() {			// destructor
	(void) flush();
	if( mystream ) delete stream;
    }

    // test the stream
    _Cdecl operator void*() { return (state==_good) ? this : 0; }
    int _Cdecl operator !() { return (state != _good); }

    ostream& _Cdecl operator << ( int );		// write a char, uns char, short, or int
    ostream& _Cdecl operator << ( long );		// write a long
    ostream& _Cdecl operator << ( unsigned int _U ) {	// write uns short, uns int
	return *this << ((long) _U);
    }
    ostream& _Cdecl operator << ( unsigned long );	// write unsigned long
    ostream& _Cdecl operator << ( const char * );	// write a string
    ostream& _Cdecl operator << ( double );		// write floating-point
    ostream& _Cdecl operator << ( long double );	// write floating-point

    ostream& _Cdecl put( char _C ) {		// write char as a char
	if( stream->sputc(_C) == EOF )
	    state = _fail;
	return *this;
    }

    ostream& _Cdecl flush();			// flush output buffer

    // return stream state
    int _Cdecl rdstate() { return state; }

    // set stream state
    void _Cdecl clear( int _S = _good ) { state = _S; }

    // non-0 if bad
    int _Cdecl bad() { return (state >= _bad); }

    // non-0 if bad or failed
    int _Cdecl fail() { return (state >= _fail); }

    // non-0 if end of input
    int _Cdecl eof() { return (state == _eof); }

    // non-0 if ok
    int _Cdecl good() { return (state == _good); }
};


/*
 * class istream
 */
class istream {
  friend ostream;
  friend void _Cdecl eatwhite( istream & _S ) { _S >> WS; }

  private:
    ostream *tied_to;			// tied ostream, if non-0
    streambuf *stream;			// connected streambuf or filebuf
    char skipping;			// non-0 if skipping whitespace
    char mystream;			// non-0 if stream was alloc'd here
    int state;				// state of stream

    void _Cdecl checkskip( int&, int& );	// used internally
    long _Cdecl get_long( int );		// used internally

  public:
    // connect to streambuf or filebuf
    _Cdecl istream( streambuf *, int = 1, ostream * = 0 );
    // connect to string
    _Cdecl istream( int, char *, int = 1 );
    // connect to open file
    _Cdecl istream( int, int = 1, ostream * = 0 );
    // destructor
    _Cdecl ~istream() {
	if( mystream ) delete stream;
    }

    // test the stream
    _Cdecl operator void*() { return (state==_good) ? this : 0; }
    int _Cdecl operator !() { return (state != _good); }

    /*
     * input functions
     */
    istream& _Cdecl operator >> ( signed char& _C ) {
	unsigned char _X;
	*this >> _X;
	if( state == _good ) _C = (signed char) _X;
	return *this;
    }
    istream& _Cdecl operator >> ( short& _S ) {
	short _T = (short) get_long(0);
	if( state == _good ) _S = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( int& _I ) {
	int _T = (int) get_long(0);
	if( state == _good ) _I = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( long& _L ) {
	long _T = get_long(0);
	if( state == _good ) _L = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( unsigned char& );
    istream& _Cdecl operator >> ( unsigned short& _S ) {
	unsigned short _T = (unsigned short) get_long(1);
	if( state == _good ) _S = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( unsigned int& _I ) {
	unsigned int _T = (unsigned int) get_long(1);
	if( state == _good ) _I = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( unsigned long& _L ) {
	unsigned long _T = (unsigned long) get_long(1);
	if( state == _good ) _L = _T;
	return *this;
    }
    istream& _Cdecl operator >> ( float& );
    istream& _Cdecl operator >> ( double& );
    istream& _Cdecl operator >> ( long double& );
    istream& _Cdecl operator >> ( char * );
    istream& _Cdecl operator >> ( whitespace& );
    istream& _Cdecl get(char& );
    istream& _Cdecl get(char *, int, int = '\n' );

    // set skipping state
    int _Cdecl skip( int _S ) {
	short _T = skipping; skipping = _S; return _T;
    }

    // tie to ostream
    ostream * _Cdecl tie( ostream *_To ) {
	ostream *_T = tied_to; tied_to = _To; return _T;
    }

    // return a character to input
    void _Cdecl putback( char _C ) { stream->sputbackc(_C); };

    // return stream state
    int _Cdecl rdstate() { return state; }

    // set stream state
    void _Cdecl clear( int _S = _good ) { state = _S; }

    // non-0 if bad
    int _Cdecl bad() { return (state >= _bad); }

    // non-0 if bad or failed
    int _Cdecl fail() { return (state >= _fail); }

    // non-0 if end of input
    int _Cdecl eof() { return (state == _eof); }

    // non-0 if ok
    int _Cdecl good() { return (state == _good); }
};

extern istream _Cdecl cin;
extern ostream _Cdecl cout;
extern ostream _Cdecl cerr;
#endif
