summaryrefslogtreecommitdiff
path: root/libc/stdio/stdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio/stdio.c')
-rw-r--r--libc/stdio/stdio.c94
1 files changed, 66 insertions, 28 deletions
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 3a2f2d073..4d8f2242a 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -65,6 +65,18 @@
* Set EOF to end of buffer when fmemopen used on a readonly stream.
* Note: I really need to run some tests on this to see what the
* glibc code does in each case.
+ *
+ * Sept 21, 2003
+ * Modify _stdio_READ to conform with C99, as stdio input behavior upon
+ * encountering EOF changed with Defect Report #141. In the current
+ * standard, the stream's EOF indicator is "sticky". Once it is set,
+ * all further input from the stream should fail until the application
+ * explicitly clears the EOF indicator (clearerr(), file positioning),
+ * even if more data becomes available.
+ * Fixed a bug in fgets. Wasn't checking for read errors.
+ * Minor thread locking optimizations to avoid some unnecessary locking.
+ * Remove the explicit calls to __builtin_* funcs, as we really need to
+ * implement a more general solution.
*/
/* Before we include anything, convert L_ctermid to L_ctermid_function
@@ -293,7 +305,8 @@ int getw(FILE *stream)
#ifdef __STDIO_WIDE
- return (fread((void *)aw, sizeof(int), 1, stream) > 0) ? (*aw) : EOF;
+ return (fread_unlocked((void *)aw, sizeof(int), 1, stream) > 0)
+ ? (*aw) : EOF;
#else /* __STDIO_WIDE */
@@ -317,7 +330,8 @@ int putw(int w, FILE *stream)
#ifdef __STDIO_WIDE
- return (fwrite((void *)aw, sizeof(int), 1, stream) == 1) ? 0 : EOF;
+ return (fwrite_unlocked((void *)aw, sizeof(int), 1, stream) == 1)
+ ? 0 : EOF;
#else /* __STDIO_WIDE */
@@ -1181,7 +1195,8 @@ ssize_t __getdelim(char **__restrict lineptr, size_t *__restrict n,
*n += GETDELIM_GROWBY;
*lineptr = buf;
}
- } while (((c = getc(stream)) != EOF) && ((buf[pos++ - 1] = c) != delimiter));
+ } while (((c = (getc_unlocked)(stream)) != EOF) /* Disable the macro */
+ && ((buf[pos++ - 1] = c) != delimiter));
__STDIO_THREADUNLOCK(stream);
@@ -1322,7 +1337,8 @@ static ssize_t _stdio_READ(register FILE *stream, unsigned char *buf, size_t buf
{
ssize_t rv;
- if (bufsize == 0) {
+ /* NOTE: C99 change: Input fails once the stream's EOF indicator is set. */
+ if ((bufsize == 0) || (stream->modeflags & __FLAG_EOF)) {
return 0;
}
@@ -2751,7 +2767,8 @@ UNLOCKED(int,fgetc,(FILE *stream),(stream))
#ifdef __STDIO_WIDE
- return (fread(buf, (size_t) 1, (size_t) 1, stream) > 0) ? *buf : EOF;
+ return (fread_unlocked(buf, (size_t) 1, (size_t) 1, stream) > 0)
+ ? *buf : EOF;
#else /* __STDIO_WIDE */
@@ -2773,19 +2790,39 @@ UNLOCKED(char *,fgets,
register char *p;
int c;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: What should fgets do if n <= 0?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ /* Should we assert here? Or set errno? Or just fail... */
+ if (n <= 0) {
+/* __set_errno(EINVAL); */
+ goto ERROR;
+ }
+
p = s;
- while ((n > 1) && ((c = getc(stream)) != EOF) && ((*p++ = c) != '\n')) {
- --n;
- }
- if (p == s) {
- /* TODO -- should we set errno? */
-/* if (n <= 0) { */
-/* errno = EINVAL; */
-/* } */
- return NULL;
+
+ while (--n) {
+ if ((c = (getc_unlocked)(stream)) == EOF) { /* Disable the macro. */
+ if (__FERROR(stream)) {
+ goto ERROR;
+ }
+ break;
+ }
+ if ((*p++ = c) == '\n') {
+ break;
+ }
}
- *p = 0;
- return s;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: If n==1 and not at EOF, should fgets return an empty string?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ if (p > s) {
+ *p = 0;
+ return s;
+ }
+
+ ERROR:
+ return NULL;
}
#endif
@@ -2802,7 +2839,8 @@ UNLOCKED(int,fputc,(int c, FILE *stream),(c,stream))
#ifdef __STDIO_WIDE
- return (fwrite(buf, (size_t) 1, (size_t) 1, stream) > 0) ? (*buf) : EOF;
+ return (fwrite_unlocked(buf, (size_t) 1, (size_t) 1, stream) > 0)
+ ? (*buf) : EOF;
#else /* __STDIO_WIDE */
@@ -2824,7 +2862,7 @@ UNLOCKED(int,fputs,
#ifdef __STDIO_WIDE
- return (fwrite(s, n, (size_t) 1, stream) > 0) ? n : EOF;
+ return (fwrite_unlocked(s, n, (size_t) 1, stream) > 0) ? n : EOF;
#else /* __STDIO_WIDE */
@@ -3484,8 +3522,8 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (!grouping) { /* Finished a group. */
bufend -= __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
- __builtin_memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
- __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
+ memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
+ __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
/* Note: g[1] == -1 means no further grouping. But since
* we'll never wrap around, we can set grouping to -1 without
@@ -3502,9 +3540,9 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (unlikely(outdigit)) {
bufend -= __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
- __builtin_memcpy(bufend,
- (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
- __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
+ memcpy(bufend,
+ (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
+ __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
} else
#endif
{
@@ -3527,8 +3565,8 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (!grouping) { /* Finished a group. */
bufend -= __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
- __builtin_memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
- __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
+ memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
+ __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
/* Note: g[1] == -1 means no further grouping. But since
* we'll never wrap around, we can set grouping to -1 without
@@ -3554,9 +3592,9 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (unlikely(outdigit)) {
bufend -= __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
- __builtin_memcpy(bufend,
- (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
- __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
+ memcpy(bufend,
+ (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
+ __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
} else
#endif
{