summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-04-09 17:05:32 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-04-09 17:05:32 +0000
commitb00a85c837152d486328282bb94066e835a200a7 (patch)
treeb2e095b3c5e536c0522b59903d984f54e0b29c14
parent6fe5b769d6e013febf722788cb890c3af9701a02 (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.
-rw-r--r--libc/stdio/stdio.c65
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 */