diff --git a/newlib/libc/stdio/setvbuf.c b/newlib/libc/stdio/setvbuf.c index 41bdff6b6..52dd306e5 100644 --- a/newlib/libc/stdio/setvbuf.c +++ b/newlib/libc/stdio/setvbuf.c @@ -104,21 +104,20 @@ _DEFUN(setvbuf, (fp, buf, mode, size), { int ret = 0; struct _reent *reent = _REENT; + size_t iosize; + int ttyflag; CHECK_INIT (reent, fp); - _newlib_flockfile_start (fp); - /* * Verify arguments. The `int' limit on `size' is due to this - * particular implementation. + * particular implementation. Note, buf and size are ignored + * when setting _IONBF. */ - - if ((mode != _IOFBF && mode != _IOLBF && mode != _IONBF) || (int)(_POINTER_INT) size < 0) - { - _newlib_flockfile_exit (fp); + if (mode != _IONBF) + if ((mode != _IOFBF && mode != _IOLBF) || (int)(_POINTER_INT) size < 0) return (EOF); - } + /* * Write current buffer, if any; drop read count, if any. @@ -126,34 +125,49 @@ _DEFUN(setvbuf, (fp, buf, mode, size), * Free old buffer if it was from malloc(). Clear line and * non buffer flags, and clear malloc flag. */ - + _newlib_flockfile_start (fp); _fflush_r (reent, fp); - fp->_r = 0; - fp->_lbfsize = 0; + if (HASUB(fp)) + FREEUB(reent, fp); + fp->_r = fp->_lbfsize = 0; if (fp->_flags & __SMBF) _free_r (reent, (_PTR) fp->_bf._base); - fp->_flags &= ~(__SLBF | __SNBF | __SMBF); + fp->_flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF); if (mode == _IONBF) goto nbf; /* - * Allocate buffer if needed. */ + * Find optimal I/O size for seek optimization. This also returns + * a `tty flag' to suggest that we check isatty(fd), but we do not + * care since our caller told us how to buffer. + */ + fp->_flags |= __swhatbuf_r (reent, fp, &iosize, &ttyflag); + if (size == 0) + { + buf = NULL; + size = iosize; + } + + /* Allocate buffer if needed. */ if (buf == NULL) { - /* we need this here because malloc() may return a pointer - even if size == 0 */ - if (!size) size = BUFSIZ; if ((buf = malloc (size)) == NULL) { + /* + * Unable to honor user's request. We will return + * failure, but try again with file system size. + */ ret = EOF; - /* Try another size... */ - buf = malloc (BUFSIZ); - size = BUFSIZ; + if (size != iosize) + { + size = iosize; + buf = malloc (size); + } } if (buf == NULL) { - /* Can't allocate it, let's try another approach */ + /* No luck; switch to unbuffered I/O. */ nbf: fp->_flags |= __SNBF; fp->_w = 0; @@ -164,35 +178,54 @@ nbf: } fp->_flags |= __SMBF; } - /* - * Now put back whichever flag is needed, and fix _lbfsize - * if line buffered. Ensure output flush on exit if the - * stream will be buffered at all. - * If buf is NULL then make _lbfsize 0 to force the buffer - * to be flushed and hence malloced on first use - */ - - switch (mode) - { - case _IOLBF: - fp->_flags |= __SLBF; - fp->_lbfsize = buf ? -size : 0; - /* FALLTHROUGH */ - - case _IOFBF: - /* no flag */ - reent->__cleanup = _cleanup_r; - fp->_bf._base = fp->_p = (unsigned char *) buf; - fp->_bf._size = size; - break; - } /* - * Patch up write count if necessary. + * We're committed to buffering from here, so make sure we've + * registered to flush buffers on exit. */ + if (!reent->__sdidinit) + __sinit(reent); +#ifdef _FSEEK_OPTIMIZATION + /* + * Kill any seek optimization if the buffer is not the + * right size. + * + * SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? + */ + if (size != iosize) + fp->_flags |= __SNPT; +#endif + + /* + * Fix up the FILE fields, and set __cleanup for output flush on + * exit (since we are buffered in some way). + */ + if (mode == _IOLBF) + fp->_flags |= __SLBF; + reent->__cleanup = _cleanup_r; + fp->_bf._base = fp->_p = (unsigned char *) buf; + fp->_bf._size = size; + /* fp->_lbfsize is still 0 */ if (fp->_flags & __SWR) - fp->_w = fp->_flags & (__SLBF | __SNBF) ? 0 : size; + { + /* + * Begin or continue writing: see __swsetup(). Note + * that __SNBF is impossible (it was handled earlier). + */ + if (fp->_flags & __SLBF) + { + fp->_w = 0; + fp->_lbfsize = -fp->_bf._size; + } + else + fp->_w = size; + } + else + { + /* begin/continue reading, or stay in intermediate state */ + fp->_w = 0; + } _newlib_flockfile_end (fp); return 0;