Module Name: src Committed By: christos Date: Sat Aug 27 13:15:48 UTC 2016
Modified Files: src/lib/libc/stdio: fgetwln.c Log Message: Improvements to fgetwln(3) from Andrey Chernov: 1) Set the stdio error indicator on __slbexpand() failure. 2) fgetwc(3) may succeed even when ferror(3) is already set (for example, consider a program using SIG_IGN on SIGTTIN, reading from the tty while in the background, getting EIO, then coming to the foreground and reading again). So do not force fgetwln(3) to fail in such a case either. (Yes, the program should probably clearerr(3) before reading again, but let's be nicer in case it forgets.) To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/lib/libc/stdio/fgetwln.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/stdio/fgetwln.c diff -u src/lib/libc/stdio/fgetwln.c:1.7 src/lib/libc/stdio/fgetwln.c:1.8 --- src/lib/libc/stdio/fgetwln.c:1.7 Mon Aug 22 03:41:10 2016 +++ src/lib/libc/stdio/fgetwln.c Sat Aug 27 09:15:48 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: fgetwln.c,v 1.7 2016/08/22 07:41:10 christos Exp $ */ +/* $NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $ */ /*- * Copyright (c) 2002-2004 Tim J. Robbins. @@ -31,7 +31,7 @@ #if 0 __FBSDID("$FreeBSD: src/lib/libc/stdio/fgetwln.c,v 1.2 2004/08/06 17:00:09 tjr Exp $"); #else -__RCSID("$NetBSD: fgetwln.c,v 1.7 2016/08/22 07:41:10 christos Exp $"); +__RCSID("$NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -88,13 +88,25 @@ fgetwln(FILE * __restrict fp, size_t *le while ((wc = __fgetwc_unlock(fp)) != WEOF) { #define GROW 512 if (len * sizeof(wchar_t) >= _EXT(fp)->_fgetstr_len && - __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) + __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) { + fp->_flags |= __SERR; goto error; + } *((wchar_t *)(void *)_EXT(fp)->_fgetstr_buf + len++) = wc; if (wc == L'\n') break; } - if (len == 0 || fp->_flags & __SERR) + + /* + * The following test assumes that fgetwc() fails when + * feof() is already set, and that fgetwc() will never + * set feof() in the same call where it also sets ferror() + * or returns non-WEOF. + * Testing ferror() would not be better because fgetwc() + * may succeed even when ferror() is already set. + */ + + if (len == 0 || (wc == WEOF && !__sfeof(fp))) goto error; FUNLOCKFILE(fp);