267 lines
5.6 KiB
C++
267 lines
5.6 KiB
C++
|
/***
|
||
|
*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
|
||
|
}
|