diff options
| -rw-r--r-- | libc/stdio/stdio.c | 50 | 
1 files changed, 33 insertions, 17 deletions
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index cf6450995..b4208f97c 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -25,6 +25,19 @@   *   *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */ +/*  8-05-2002 + *  Changed fflush() behavior to no-op for r/w streams in read-mode. + *     This falls under undefined behavior wrt ANSI/ISO C99, but + *     SUSv3 seems to treat it as a no-op and it occurs in some apps. + *  Fixed a problem with _stdio_fwrite() not checking for underlying + *     write() failures. + *  Fixed both _stdio_fwrite() and _stdio_fread() to make sure that + *     the putc and getc macros were disabled if the stream was in + *     and error state. + *  The above changes should take care of a problem initially reported + *  by "Steven J. Hill" <sjhill@realitydiluted.com>. + */ +  /* Before we include anything, convert L_ctermid to L_ctermid_function   * and undef L_ctermid if defined.  This is necessary as L_ctermid is   * a SUSv3 standard macro defined in stdio.h. */ @@ -1385,7 +1398,9 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream)  		}  #ifdef __STDIO_GETC_MACRO -		if (!(stream->modeflags & (__FLAG_WIDE|__MASK_UNGOT|__MASK_BUFMODE))) { +		if (!(stream->modeflags +			  & (__FLAG_WIDE|__MASK_UNGOT|__MASK_BUFMODE|__FLAG_ERROR)) +			) {  			stream->bufgetc = stream->bufread; /* Enable getc macro. */  		}  #endif @@ -1565,6 +1580,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,  	{  		const unsigned char *buf0 = buffer; +		size_t write_count = 1;	/* 0 means a write failed */  		if (!buffer) {				/* fflush the stream */  		FFLUSH: @@ -1578,9 +1594,9 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,  				}  				{ -					size_t rv = _stdio_WRITE(stream, p, count); -					p += rv; -					count -= rv; +					write_count = _stdio_WRITE(stream, p, count); +					p += write_count; +					count -= write_count;  				}  				stream->bufpos = stream->bufstart; @@ -1624,21 +1640,23 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,  				--count;  			} -			if (bytes) { -				goto FFLUSH; -			} +			if (write_count) {	/* no write errors */ +				if (bytes) { +					goto FFLUSH; +				} -			if (stream->modeflags & __FLAG_LBF) { -				while (p < buffer) { /* check for newline. */ -					if (*p++ == '\n') { -						goto FFLUSH; +				if (stream->modeflags & __FLAG_LBF) { +					while (p < buffer) { /* check for newline. */ +						if (*p++ == '\n') { +							goto FFLUSH; +						}  					}  				}  			}  		}  #ifdef __STDIO_PUTC_MACRO -		if (!(stream->modeflags & (__FLAG_WIDE|__MASK_BUFMODE))) { +		if (!(stream->modeflags & (__FLAG_WIDE|__MASK_BUFMODE|__FLAG_ERROR))) {  			/* Not wide, no errors and fully buffered, so enable putc macro. */  			stream->bufputc = stream->bufend;  		} @@ -2127,13 +2145,11 @@ int fflush_unlocked(register FILE *stream)  		if (_stdio_fwrite(NULL, 0, stream) > 0) { /* flush buffer contents. */  			rv = -1;			/* Not all chars written. */  		} -	} else if (stream->modeflags & (__FLAG_READONLY|__FLAG_READING)) { -		/* TODO - __FLAG_READING too?  check glibc behavior */ +	} else if (stream->modeflags & __FLAG_READONLY) {  		/* According to info, glibc returns an error when the file is opened  		 * in read-only mode.  		 * ANSI/ISO says behavior in this case is undefined but also says you -		 * shouldn't flush a stream you were reading from. -		 */ +		 * shouldn't flush a stream you were reading from. */  		stream->modeflags |= __FLAG_ERROR; /* TODO - check glibc behavior */  		__set_errno(EBADF);  		rv = -1; @@ -2156,7 +2172,7 @@ int fflush_unlocked(register FILE *stream)  	/* TODO -- check glibc behavior regarding error indicator */  	return ((stream != NULL) -			&& (stream->modeflags & (__FLAG_READONLY|__FLAG_READING)) +			&& (stream->modeflags & __FLAG_READONLY)  			? ((stream->modeflags |= __FLAG_ERROR), __set_errno(EBADF), EOF)  			: 0 );  | 
