diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2016-03-13 01:37:01 +0300 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2016-03-13 01:37:01 +0300 |
commit | 99d0e2341d3ff37b98eff9163b195b715ff8bddf (patch) | |
tree | 1f07ba8d032a413f253d0efd199c0ce7f8925be8 /newlib/libc/stdio | |
parent | 6b97fabf1ba0c13921549ec4a89b6953da881078 (diff) |
Add __swhatbuf function from OpenBSD
To fix a long-standing setvbuf bug, import __swhatbuf function from
OpenBSD and only slightly rearrange for newlib.
* libc/stdio/local.h (__swhatbuf_r): Declare.
* libc/stdio/makebuf (__smakebuf_r): New function.
(__smakebuf_r): Drop file handling code and call __smakebuf_r.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'newlib/libc/stdio')
-rw-r--r-- | newlib/libc/stdio/local.h | 1 | ||||
-rw-r--r-- | newlib/libc/stdio/makebuf.c | 108 |
2 files changed, 60 insertions, 49 deletions
diff --git a/newlib/libc/stdio/local.h b/newlib/libc/stdio/local.h index cf8e6a921..471442e26 100644 --- a/newlib/libc/stdio/local.h +++ b/newlib/libc/stdio/local.h @@ -182,6 +182,7 @@ extern int _EXFUN(__stextmode,(int)); extern _VOID _EXFUN(__sinit,(struct _reent *)); extern _VOID _EXFUN(_cleanup_r,(struct _reent *)); extern _VOID _EXFUN(__smakebuf_r,(struct _reent *, FILE *)); +extern int _EXFUN(__swhatbuf_r,(struct _reent *, FILE *, size_t *, int *)); extern int _EXFUN(_fwalk,(struct _reent *, int (*)(FILE *))); extern int _EXFUN(_fwalk_reent,(struct _reent *, int (*)(struct _reent *, FILE *))); struct _glue * _EXFUN(__sfmoreglue,(struct _reent *,int n)); diff --git a/newlib/libc/stdio/makebuf.c b/newlib/libc/stdio/makebuf.c index 349783ded..c592578b8 100644 --- a/newlib/libc/stdio/makebuf.c +++ b/newlib/libc/stdio/makebuf.c @@ -39,13 +39,10 @@ _DEFUN(__smakebuf_r, (ptr, fp), struct _reent *ptr _AND register FILE *fp) { - register size_t size, couldbetty; register _PTR p; -#ifdef __USE_INTERNAL_STAT64 - struct stat64 st; -#else - struct stat st; -#endif + int flags; + size_t size; + int couldbetty; if (fp->_flags & __SNBF) { @@ -53,49 +50,7 @@ _DEFUN(__smakebuf_r, (ptr, fp), fp->_bf._size = 1; return; } -#ifdef __USE_INTERNAL_STAT64 - if (fp->_file < 0 || _fstat64_r (ptr, fp->_file, &st) < 0) -#else - if (fp->_file < 0 || _fstat_r (ptr, fp->_file, &st) < 0) -#endif - { - couldbetty = 0; - /* Check if we are be called by asprintf family for initial buffer. */ - if (fp->_flags & __SMBF) - size = _DEFAULT_ASPRINTF_BUFSIZE; - else - size = BUFSIZ; -#ifdef _FSEEK_OPTIMIZATION - /* do not try to optimise fseek() */ - fp->_flags |= __SNPT; -#endif - } - else - { - couldbetty = (st.st_mode & S_IFMT) == S_IFCHR; -#ifdef HAVE_BLKSIZE - size = st.st_blksize <= 0 ? BUFSIZ : st.st_blksize; -#else - size = BUFSIZ; -#endif -#ifdef _FSEEK_OPTIMIZATION - /* - * Optimize fseek() only if it is a regular file. - * (The test for __sseek is mainly paranoia.) - */ - if ((st.st_mode & S_IFMT) == S_IFREG && fp->_seek == __sseek) - { - fp->_flags |= __SOPT; -#ifdef HAVE_BLKSIZE - fp->_blksize = st.st_blksize; -#else - fp->_blksize = 1024; -#endif - } - else - fp->_flags |= __SNPT; -#endif - } + flags = __swhatbuf_r (ptr, fp, &size, &couldbetty); if ((p = _malloc_r (ptr, size)) == NULL) { if (!(fp->_flags & __SSTR)) @@ -113,5 +68,60 @@ _DEFUN(__smakebuf_r, (ptr, fp), fp->_bf._size = size; if (couldbetty && _isatty_r (ptr, fp->_file)) fp->_flags |= __SLBF; + fp->_flags |= flags; } } + +/* + * Internal routine to determine `proper' buffering for a file. + */ +int +_DEFUN(__swhatbuf_r, (ptr, fp, bufsize, couldbetty), + struct _reent *ptr _AND + FILE *fp _AND + size_t *bufsize _AND + int *couldbetty) +{ +#ifdef _FSEEK_OPTIMIZATION + const int snpt = __SNPT; +#else + const int snpt = 0; +#endif + +#ifdef __USE_INTERNAL_STAT64 + struct stat64 st; + + if (fp->_file < 0 || _fstat64_r (ptr, fp->_file, &st) < 0) +#else + struct stat st; + + if (fp->_file < 0 || _fstat_r (ptr, fp->_file, &st) < 0) +#endif + { + *couldbetty = 0; + /* Check if we are be called by asprintf family for initial buffer. */ + if (fp->_flags & __SMBF) + *bufsize = _DEFAULT_ASPRINTF_BUFSIZE; + else + *bufsize = BUFSIZ; + return (0); + } + + /* could be a tty iff it is a character device */ + *couldbetty = S_ISCHR(st.st_mode); +#ifdef HAVE_BLKSIZE + if (st.st_blksize > 0) + { + /* + * Optimise fseek() only if it is a regular file. (The test for + * __sseek is mainly paranoia.) It is safe to set _blksize + * unconditionally; it will only be used if __SOPT is also set. + */ + *bufsize = st.st_blksize; + fp->_blksize = st.st_blksize; + return ((st.st_mode & S_IFMT) == S_IFREG ? __SOPT : snpt); + } +#endif + *bufsize = BUFSIZ; + return (snpt); +} |