summaryrefslogblamecommitdiffstats
path: root/private/crt32/iostream/stdiostr.cxx
blob: 58c385a7853224e55f272405030522549bca53ab (plain) (tree)









































































































































































































































































                                                                                   
/***
*stdiostr.cxx -
*
*	Copyright (c) 1991-1992, Microsoft Corporation.  All rights reserved.
*
*Purpose:
*
*Revision History:
*
*	07-10-91   KRS	Created.
*	08-26-91   KRS	Switch out cout/cerr. etc. for Windows non-QuickWin.
*	09-09-91   KRS	Modify sync_with_stdio() for filebuf defaults.
*	09-12-91   KRS	Add stdiostream class.
*	09-19-91   KRS	Use delbuf(1) in stdiostream constructor.
*	09-20-91   KRS	C700 #4453: Improve efficiency in overflow().
*	10-21-91   KRS	Eliminate last use of default iostream constructor.
*	10-24-91   KRS	Avoid virtual calls from virtual functions.
*	11-13-91   KRS	Split out streambuf::dbp() into separate file.
*			Improve default buffer handling in underflow/overflow.
*			Fix bug in sync().
*	01-20-92   KRS	C700 #5803: account for CR/LF pairs in ssync().
*
*******************************************************************************/

#include <cruntime.h>
#include <internal.h>
#include <string.h>
#include <stdiostr.h>
#pragma hdrstop

extern "C" {
#include <file2.h>
#include <msdos.h>
}
#include <dos.h>

	stdiobuf::stdiobuf(FILE * f)
: streambuf()
{
	unbuffered(1);			// initially unbuffered
	_str = f;
}

	stdiobuf::~stdiobuf()
// : ~streambuf()
{
	stdiobuf::sync();		// make sure buffer flushed
//	_str = 0;
}

	int stdiobuf::setrwbuf(int readsize, int writesize)
{
    char * tbuf;
    unbuffered(!(readsize+writesize));
    if (unbuffered())
	return(0);

    tbuf = new char[(readsize+writesize)];
    if (!tbuf)
	return(EOF);

    setb( tbuf, tbuf + (readsize+writesize), 1);

    if (readsize)
	{
	setg(base(),base()+readsize,base()+readsize);
	}
    else
	{
	setg(0,0,0);
	}

    if (writesize)
	{
	setp(base()+readsize,ebuf());
	}
    else
	{
	setp(0,0);
	}

    return(1);
}

int stdiobuf::overflow(int c) {
    long count, nout;
    if (allocate()==EOF)	// make sure there is a reserve area
	return EOF;	
    if (!unbuffered() && epptr())
	{
	if ((count = pptr() - pbase()) > 0)
	    {
	    nout=fwrite((void *) pbase(), 1, (int)count, _str);
	    pbump(-(int)nout);
	    if (nout != count)
		{
		memmove(pbase(),pbase()+nout,(int)(count-nout));
		return(EOF);
		}
	    }
	}
    if ((!unbuffered()) && (!epptr()))
	setp(base()+(blen()>>1),ebuf());	// hack: default to 2nd half
    if (c!=EOF)
	{
	if ((!unbuffered()) && (pptr() < epptr())) // guard against recursion
	    sputc(c);
	else
	    return fputc(c, _str);
	}
    return(1);	// return something other than EOF if successful
}

int stdiobuf::underflow()
{
    int count;
    if (allocate()==EOF)	// make sure there is a reserve area
	return EOF;	
    if ((!unbuffered()) && (!egptr()))
	setg(base(),(base()+(blen()>>1)),(base()+(blen()>>1))); // hack: default

    if (unbuffered() || (!egptr()))
	return fgetc(_str);
    if (gptr() >= egptr())
// buffer empty, try for more
    {
    if (!(count = fread((void *)eback(), 1, (size_t)(egptr()-eback()), _str)))
	return(EOF); // reach EOF, nothing read
    setg(eback(),(egptr()-count),egptr());   // _gptr = _egptr - count
    if (gptr()!=eback())
	{
	// CONSIDER: expensive, is there a better sol'n?
	memmove(gptr(), eback(), count);	// overlapping memory!
	}
    }
    return sbumpc();		// CONSIDER: possible recursion
}

streampos stdiobuf::seekoff(streamoff off, ios::seek_dir dir, int)
{

    int fdir;
    long retpos;
    switch (dir) {
	case ios::beg :
	    fdir = SEEK_SET;
	    break;
	case ios::cur :
	    fdir = SEEK_CUR;
	    break;
	case ios::end :
	    fdir = SEEK_END;
	    break;
	default:
	// error
	    return(EOF);
	}
		
// CONSIDER: is this needed?
    stdiobuf::overflow(EOF);
    if (fseek(_str, off, fdir))
	return (EOF);
    if ((retpos=ftell(_str))==-1L)
	return(EOF);
    return((streampos)retpos);
}

int stdiobuf::pbackfail(int c)
{
    if (eback()<gptr()) return sputbackc((char)c); // CONSIDER: should never happen

    if (stdiobuf::seekoff( -1, ios::cur, ios::in)==EOF)
	return EOF;
    if (!unbuffered() && egptr())
	{
	memmove((gptr()+1),gptr(),(egptr()-(gptr()+1)));
	*gptr()=(char)c;
	}
    return(c);
}

int stdiobuf::sync()
{
    long count;
    char * p;
    char flags;
    if (!unbuffered())
	{
	if (stdiobuf::overflow(EOF)==EOF)
	    return(EOF);
	if ((count=in_avail())>0)
	    {
	    flags = _osfile[_fileno(_str)];
	    if (flags & FTEXT)
		{
	        // If text mode, need to account for CR/LF etc.
		for (p = gptr(); p < egptr(); p++)
		    if (*p == '\n')
			count++;

		// account for EOF if read, not counted by _read
		// UNDONE: is this necessary?
		if (_str->_flag & _IOCTRLZ)
		    count++;
#if 0
		// UNDONE: is this correct?
		if ((gptr()==eback()) && (flags & FCRLF))
		    count--;
#endif
		}
	    if (stdiobuf::seekoff( -count, ios::cur, ios::in)==EOF)
		return(EOF);
	
	    setg(eback(),egptr(),egptr()); // empty get area (_gptr = _egptr;)
	    }
	}
    return(0);
}

	stdiostream::stdiostream(FILE * file)
: iostream(new stdiobuf(file))
{
istream::delbuf(1);
ostream::delbuf(1);
// CONSIDER: do anything else?
}

	stdiostream::~stdiostream()
{
// CONSIDER: do anything else?
}

// include here for better granularity

int ios::sunk_with_stdio = 0;

void ios::sync_with_stdio()
{
#if ((!defined(_WINDOWS)) || defined(_QWIN))
    if (!sunk_with_stdio)	// first time only
	{
//	printf("In sync_with_stdio\n");

	cin = new stdiobuf(stdin);
	cin.delbuf(1);
	cin.setf(ios::stdio);

	cout = new stdiobuf(stdout);
	cout.delbuf(1);
	cout.setf(ios::stdio|ios::unitbuf);
	((stdiobuf*)(cout.rdbuf()))->setrwbuf(0,80);	// UNDONE: size??

	cerr = new stdiobuf(stderr);
	cerr.delbuf(1);
	cerr.setf(ios::stdio|ios::unitbuf);
	((stdiobuf*)(cerr.rdbuf()))->setrwbuf(0,80);	// UNDONE: size??

	clog = new stdiobuf(stderr);
	clog.delbuf(1);
	clog.setf(ios::stdio);
	((stdiobuf*)(clog.rdbuf()))->setrwbuf(0,BUFSIZ);

	sunk_with_stdio++;
	}
#endif
}