diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2002-04-09 17:05:32 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2002-04-09 17:05:32 +0000 |
commit | b00a85c837152d486328282bb94066e835a200a7 (patch) | |
tree | b2e095b3c5e536c0522b59903d984f54e0b29c14 /libc/stdio/stdio.c | |
parent | 6fe5b769d6e013febf722788cb890c3af9701a02 (diff) |
Fix the read/write auto-transition bugs. Note that if we can't
auto-transition, we fail the operation. This is different than glibc's
apparent behavior for writing of clearing the read buffer and still
failing the write without setting the stream's error flag.
Also, change a number of "errno = xxx" assignments to use __set_errno().
Also, change setvbuf(file, NULL, _IO{LF}BF, 0) behavior to more closely
match glibc's by keeping the current buffer and only changing the buffering
mode. Update setlinebuf() in the process to match the man page behavior.
Diffstat (limited to 'libc/stdio/stdio.c')
-rw-r--r-- | libc/stdio/stdio.c | 65 |
1 files changed, 36 insertions, 29 deletions
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index 8ee1a16e2..60d4fe73b 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -347,7 +347,7 @@ void setbuffer(FILE * __restrict stream, register char * __restrict buf, void setlinebuf(FILE * __restrict stream) { #ifdef __STDIO_BUFFERS - setvbuf(stream, NULL, _IOLBF, (size_t) BUFSIZ); + setvbuf(stream, NULL, _IOLBF, (size_t) 0); #else /* __STDIO_BUFFERS */ /* Nothing to do. */ #endif /* __STDIO_BUFFERS */ @@ -458,7 +458,7 @@ static ssize_t fmo_write(void *cookie, register const char *buf, size_t bufsize) if (bufsize > count) { bufsize = count; if (count == 0) { /* We're at the end of the buffer... */ - errno = EFBIG; + __set_errno(EFBIG); return -1; } } @@ -632,7 +632,7 @@ static ssize_t oms_write(void *cookie, const char *buf, size_t bufsize) } else { bufsize = count; if (count == 0) { - errno = EFBIG; /* TODO: check glibc errno setting... */ + __set_errno(EFBIG); /* TODO: check glibc errno setting... */ return -1; } } @@ -1214,7 +1214,7 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, * use this errno for read attempt while writing, as no errno is * specified by posix for this case, even though the restriction is * mentioned in fopen(). */ - errno = EBADF; + __set_errno(EBADF); return 0; } @@ -1237,9 +1237,8 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, } #ifdef __STDIO_AUTO_RW_TRANSITION - if (stream->modeflags & __FLAG_WRITING) { - /* TODO -- return if error? Test glibc behavior with a custom r/w. */ - fflush(stream); + if ((stream->modeflags & __FLAG_WRITING) && (fflush(stream) == EOF)) { + return 0; /* Fail if we need to fflush but can't. */ } #endif /* __STDIO_AUTO_RW_TRANSITION */ @@ -1316,7 +1315,7 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, * use this errno for read attempt while writing, as no errno is * specified by posix for this case, even though the restriction is * mentioned in fopen(). */ - errno = EBADF; + __set_errno(EBADF); return 0; } @@ -1431,35 +1430,39 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, * use this errno for write attempt while reading, as no errno is * specified by posix for this case, even though the restriction is * mentioned in fopen(). */ - errno = EBADF; + __set_errno(EBADF); return 0; } #ifdef __STDIO_AUTO_RW_TRANSITION - /* If we were reading, deal with ungots and buffered chars. */ - if ((stream->modeflags & (__FLAG_EOF|__FLAG_WRITING|__FLAG_WRITEONLY)) - == 0) { - /* If appending, we might as well seek to end to save a seek. */ - fseek(stream, 0L, - ((stream->modeflags & __FLAG_APPEND) ? SEEK_END : SEEK_CUR)); - /* TODO: set EOF in fseek when appropriate? */ + /* If reading, deal with ungots and read-buffered chars. */ + if (stream->modeflags & __FLAG_READING) { + if (((stream->bufrpos < stream->bufwpos) + || (stream->modeflags & __MASK_UNGOT)) + /* If appending, we might as well seek to end to save a seek. */ + /* TODO: set EOF in fseek when appropriate? */ + && fseek(stream, 0L, + ((stream->modeflags & __FLAG_APPEND) + ? SEEK_END : SEEK_CUR)) + ) { + /* Note: This differs from glibc's apparent behavior of + not setting the error flag and discarding the buffered + read data. */ + stream->modeflags |= __FLAG_ERROR; /* fseek may not set this. */ + return 0; /* Fail if we need to fseek but can't. */ + } + /* Always reset even if fseek called (saves a test). */ +#ifdef __STDIO_GETC_MACRO + stream->bufgetc = +#endif /* __STDIO_GETC_MACRO */ + stream->bufrpos = stream->bufwpos = stream->bufstart; } #endif - /* We need to disable putc and getc macros in case of error */ -#if defined(__STDIO_AUTO_RW_TRANSITION) \ - || defined(__STDIO_PUTC_MACRO) || defined(__STDIO_GETC_MACRO) -#ifdef __STDIO_AUTO_RW_TRANSITION - stream->bufrpos = /* TODO -- necessary? */ -#endif /* __STDIO_AUTO_RW_TRANSITION */ #ifdef __STDIO_PUTC_MACRO - stream->bufputc = + /* We need to disable putc macro in case of error */ + stream->bufputc = stream->bufstart; #endif /* __STDIO_GETC_MACRO */ -#ifdef __STDIO_GETC_MACRO - stream->bufgetc = -#endif /* __STDIO_GETC_MACRO */ - stream->bufstart; -#endif /* not using ansi restrictions ; or using putc and/or getc macro */ /* Clear both reading and writing flags. We need to clear the writing * flag in case we're fflush()ing or in case of an error. */ @@ -1568,7 +1571,7 @@ size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes, * use this errno for write attempt while reading, as no errno is * specified by posix for this case, even though the restriction is * mentioned in fopen(). */ - errno = EBADF; + __set_errno(EBADF); return 0; } @@ -2408,6 +2411,10 @@ int setvbuf(register FILE * __restrict stream, register char * __restrict buf, if (mode == _IONBF) { size = 0; buf = NULL; + } else if (!buf && !size) { + /* If buf==NULL && size==0 && either _IOFBF or _IOLBF, keep + * current buffer and only set buffering mode. */ + size = stream->bufend - stream->bufstart; } stream->modeflags &= ~(__MASK_BUFMODE); /* Clear current mode */ |