/*** *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 #include #include #include #pragma hdrstop extern "C" { #include #include } #include 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()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 }