diff options
Diffstat (limited to 'private/crt32/stdio/fflush.c')
-rw-r--r-- | private/crt32/stdio/fflush.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/private/crt32/stdio/fflush.c b/private/crt32/stdio/fflush.c new file mode 100644 index 000000000..7eb01c67b --- /dev/null +++ b/private/crt32/stdio/fflush.c @@ -0,0 +1,424 @@ +/*** +*fflush.c - flush a stream buffer +* +* Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines fflush() - flush the buffer on a stream +* _flushall() - flush all stream buffers +* +*Revision History: +* 09-01-83 RN initial version +* 11-02-87 JCR Multi-thread support +* 12-11-87 JCR Added "_LOAD_DS" to declaration +* 01-13-88 JCR Removed unnecessary calls to mthread fileno/feof/ferror +* 05-27-88 PHG Merge DLL and normal versions +* 06-14-88 JCR Use near pointer to reference _iob[] entries +* 08-24-88 GJF Don't use FP_OFF() macro for the 386 +* 08-17-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 flat +* model). Also fixed copyright and indents. +* 11-29-89 GJF Added support for fflush(NULL) (per ANSI). Merged in +* flushall(). +* 01-24-90 GJF Fixed fflush(NULL) functionality to comply with ANSI +* (must only call fflush() for output streams) +* 03-16-90 GJF Made calling type _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-26-90 GJF Made flsall() _CALLTYPE4. +* 05-09-90 SBM _fflush_lk became _flush, added new [_]fflush[_lk] +* 07-11-90 SBM Commit mode on a per stream basis +* 10-02-90 GJF New-style function declarators. +* 12-12-90 GJF Fixed mis-placed paran in ternary expr commiting the +* buffers. +* 01-16-91 SRW Reversed test of _commit return value +* 01-21-91 GJF ANSI naming. +* 06-05-91 GJF On a successful _flush of a read/write stream in write +* mode, clear _IOWRT so that the next operation can be a +* read. ANSI requirement (C700 bug #2531). +* 07-30-91 GJF Added support for termination scheme used on +* non-Cruiser targets [_WIN32_]. +* 08-19-91 JCR Added _exitflag, _endstdio +* 03-16-92 SKS Moved _cflush to the initializer module (in assembler) +* 03-27-92 DJM POSIX support. +* 08-26-92 GJF Include unistd.h for POSIX build. +* 03-18-93 CFW fflush_lk returns 0 before exit. +* 03-19-93 GJF Revised flsall() so that, in multi-thread models, +* unused streams are not locked unnecessarily. +* 05-10-93 GJF Purged ftell call accidently checked in 3/10/93. +* +*******************************************************************************/ + +#include <cruntime.h> +#ifdef _POSIX_ +#include <unistd.h> +#include <fcntl.h> +#endif +#include <stdio.h> +#include <file2.h> +#include <io.h> +#include <os2dll.h> +#include <internal.h> + + +#pragma data_seg(".CRT$XPX") + +const void (__cdecl *__pendstdio)(void) = _endstdio; + +#pragma data_seg() + +/* + * _cflush is a dummy variable used to pull in _endstdio() when any STDIO + * routine is included in the user program. + */ +int _cflush = 1; + +/* Values passed to flsall() to distinguish between _flushall() and + * fflush(NULL) behavior + */ +#define FLUSHALL 1 +#define FFLUSHNULL 0 + +/* Core routine for fflush(NULL) and flushall() + */ +static int _CRTAPI3 flsall(int); + +/*** +*int fflush(stream) - flush the buffer on a stream +* +*Purpose: +* if file open for writing and buffered, flush the buffer. if problems +* flushing the buffer, set the stream flag to error +* Always flushes the stdio stream and forces a commit to disk if file +* was opened in commit mode. +* +*Entry: +* FILE *stream - stream to flush +* +*Exit: +* returns 0 if flushed successfully, or no buffer to flush +* returns EOF and sets file error flag if fails. +* FILE struct entries affected: _ptr, _cnt, _flag. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +int _CRTAPI1 fflush ( + REG1 FILE *stream + ) +{ + int rc; + int index; + + /* if stream is NULL, flush all streams + */ + if ( stream == NULL ) + return(flsall(FFLUSHNULL)); + + index = _iob_index(stream); + + _lock_str(index); + + rc = _fflush_lk(stream); + + _unlock_str(index); + + return(rc); +} + + +/*** +*_fflush_lk() - Flush the buffer on a stream (stream is already locked) +* +*Purpose: +* Core flush routine; assumes stream lock is held by caller. +* +* [See fflush() above for more information.] +* +*Entry: +* [See fflush()] +*Exit: +* [See fflush()] +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI1 _fflush_lk ( + REG1 FILE *str + ) +{ + +#else /* non multi-thread */ + +int _CRTAPI1 fflush ( + REG1 FILE *str + ) +{ + + /* if stream is NULL, flush all streams */ + if ( str == NULL ) { + return(flsall(FFLUSHNULL)); + } + +#endif /* rejoin common code */ + + if (_flush(str) != 0) { + /* _flush failed, don't attempt to commit */ + return(EOF); + } + + /* lowio commit to ensure data is written to disk */ +#ifndef _POSIX_ + if (str->_flag & _IOCOMMIT) { + return (_commit(_fileno(str)) ? EOF : 0); + } +#endif + return 0; +} + + +/*** +*int _flush(stream) - flush the buffer on a single stream +* +*Purpose: +* If file open for writing and buffered, flush the buffer. If +* problems flushing the buffer, set the stream flag to error. +* Multi-thread version assumes stream lock is held by caller. +* +*Entry: +* FILE* stream - stream to flush +* +*Exit: +* Returns 0 if flushed successfully, or if no buffer to flush., +* Returns EOF and sets file error flag if fails. +* File struct entries affected: _ptr, _cnt, _flag. +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI1 _flush ( + FILE *str + ) +{ + REG1 FILE *stream; + REG2 int rc = 0; /* assume good return */ + REG3 int nchar; + + /* Init pointer to stream */ + stream = str; + +#ifdef _POSIX_ + + /* + * Insure that EBADF is returned whenever the underlying + * file descriptor is closed. + */ + + if (-1 == fcntl(fileno(stream), F_GETFL)) + return(EOF); + + /* + * Posix ignores read streams to insure that the result of + * ftell() is the same before and after fflush(), and to + * avoid seeking on pipes, ttys, etc. + */ + + if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOREAD) { + return 0; + } + +#endif /* _POSIX_ */ + + if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream) + && (nchar = stream->_ptr - stream->_base) > 0) + { +#ifdef _POSIX_ + if ( write(fileno(stream), stream->_base, nchar) == nchar ) { +#else + if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) { +#endif + /* if this is a read/write file, clear _IOWRT so that + * next operation can be a read + */ + if ( _IORW & stream->_flag ) + stream->_flag &= ~_IOWRT; + } + else { + stream->_flag |= _IOERR; + rc = EOF; + } + } + + stream->_ptr = stream->_base; + stream->_cnt = 0; + + return(rc); +} + + +/*** +*int _flushall() - flush all output buffers +* +*Purpose: +* flushes all the output buffers to the file, clears all input buffers. +* +*Entry: +* None. +* +*Exit: +* returns number of open streams +* +*Exceptions: +* +*******************************************************************************/ + +int _CRTAPI1 _flushall ( + void + ) +{ + return(flsall(FLUSHALL)); +} + + +/*** +*static int flsall(flushflag) - flush all output buffers +* +*Purpose: +* Flushes all the output buffers to the file and, if FLUSHALL is passed, +* clears all input buffers. Core routine for both fflush(NULL) and +* flushall(). +* +* MTHREAD Note: All the locking/unlocking required for both fflush(NULL) +* and flushall() is performed in this routine. +* +*Entry: +* int flushflag - flag indicating the exact semantics, there are two +* legal values: FLUSHALL and FFLUSHNULL +* +*Exit: +* if flushflag == FFLUSHNULL then flsbuf returns: + 0, if successful +* EOF, if an error occurs while flushing one of the streams +* +* if flushflag == FLUSHALL then flsbuf returns the number of streams +* successfully flushed +* +*Exceptions: +* +*******************************************************************************/ + +static int _CRTAPI3 flsall ( + int flushflag + ) +{ + REG1 FILE *stream = _iob; + REG2 int count = 0; + int errcode = 0; +#ifdef MTHREAD + int index; +#endif + + _mlock(_IOB_SCAN_LOCK); + + for (; stream <= _lastiob; stream++) + + if ( inuse(stream) ) { + +#ifdef MTHREAD + /* + * lock the stream. this is not done until testing + * the stream is in use to avoid unnecessarily creating + * a lock for every stream. the price is having to + * retest the stream after the lock has been asserted. + */ + index = _iob_index(stream); + _lock_str(index); + + /* + * if the stream is STILL in use (it may have been + * closed before the lock was asserted), see about + * flushing it. + */ + if ( inuse(stream) ) { +#endif + + if ( flushflag == FLUSHALL ) { + /* + * FLUSHALL functionality: fflush the read or + * write stream and, if successful, update the + * count of flushed streams + */ + if ( _fflush_lk(stream) != EOF ) + /* update count of successfully flushed + * streams + */ + count++; + } + else if ( (flushflag == FFLUSHNULL) && + (stream->_flag & _IOWRT) ) { + /* + * FFLUSHNULL functionality: fflush the write + * stream and kept track of the error, if one + * occurs + */ + if ( _fflush_lk(stream) == EOF ) + errcode = EOF; + } + +#ifdef MTHREAD + } + _unlock_str(index); +#endif + + } + + _munlock(_IOB_SCAN_LOCK); + + if ( flushflag == FLUSHALL ) + return(count); + else + return(errcode); +} + + +#ifndef _CRUISER_ + +/*** +* _endstdio - Terminate the stdio system +* +*Purpose: +* Terminate the stdio system +* +* (1) Flush all streams. (Do this even if we're going to +* call fcloseall since that routine won't do anything to the +* std streams.) +* +* (2) If returning to caller, close all streams. This is +* not necessary if the exe is terminating because the OS will +* close the files for us (much more efficiently, too). +* +*Entry: <void> +* +*Exit: <void> +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +void _endstdio(void) + +{ + /* flush all streams */ + _flushall(); /*flush all streams + + /* if in callable exit, close all streams */ + if (_exitflag) + _fcloseall(); +} + +#endif |