mirror of
https://sourceware.org/git/glibc.git
synced 2026-10-28 10:25:13 +08:00
After a buffer refill, _IO_getwline_info reads the first character through __wuflow and handles it on a separate path from the rest of the buffer. When extract_delim is negative, that path calls _IO_sputbackc, the narrow-stream putback, on a wide stream, so it would operate on fp->_IO_read_ptr instead of fp->_wide_data->_IO_read_ptr. No current caller passes a negative extract_delim, so this is not reachable today. Refill the buffer with __wunderflow instead, which does not consume anything, and let the wmemchr path handle every character including the delimiter. This removes the duplicated delimiter handling and the wrong putback. Every wide underflow implementation either returns WEOF or leaves at least one character in the buffer, so the loop cannot spin. No functional change for fgetws and fgetws_unlocked. Tested with the libio tests on x86_64-linux-gnu, including tst-fgetws and tst-widetext. Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com> Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
94 lines
2.9 KiB
C
94 lines
2.9 KiB
C
/* Copyright (C) 1993-2026 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>.
|
|
|
|
As a special exception, if you link the code in this file with
|
|
files compiled with a GNU compiler to produce an executable,
|
|
that does not cause the resulting executable to be covered by
|
|
the GNU Lesser General Public License. This exception does not
|
|
however invalidate any other reasons why the executable file
|
|
might be covered by the GNU Lesser General Public License.
|
|
This exception applies to code released by its copyright holders
|
|
in files containing the exception. */
|
|
|
|
#include "libioP.h"
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
size_t
|
|
_IO_getwline (FILE *fp, wchar_t *buf, size_t n, wint_t delim,
|
|
int extract_delim)
|
|
{
|
|
return _IO_getwline_info (fp, buf, n, delim, extract_delim, (wint_t *) 0);
|
|
}
|
|
|
|
/* Algorithm based on that used by Berkeley pre-4.4 fgets implementation.
|
|
|
|
Read chars into buf (of size n), until delim is seen.
|
|
Return number of chars read (at most n).
|
|
Does not put a terminating '\0' in buf.
|
|
If extract_delim < 0, leave delimiter unread.
|
|
If extract_delim > 0, insert delim in output. */
|
|
|
|
size_t
|
|
_IO_getwline_info (FILE *fp, wchar_t *buf, size_t n, wint_t delim,
|
|
int extract_delim, wint_t *eof)
|
|
{
|
|
wchar_t *ptr = buf;
|
|
if (eof != NULL)
|
|
*eof = 0;
|
|
if (__builtin_expect (fp->_mode, 1) == 0)
|
|
_IO_fwide (fp, 1);
|
|
while (n != 0)
|
|
{
|
|
wchar_t *read_ptr = fp->_wide_data->_IO_read_ptr;
|
|
if (fp->_wide_data->_IO_read_end <= read_ptr)
|
|
{
|
|
/* Refill the buffer without consuming anything, so that the
|
|
delimiter is always handled by the block path below. */
|
|
if (__wunderflow (fp) == WEOF)
|
|
{
|
|
if (eof != NULL)
|
|
*eof = WEOF;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
size_t len = fp->_wide_data->_IO_read_end - read_ptr;
|
|
if (len > n)
|
|
len = n;
|
|
wchar_t *t = wmemchr (read_ptr, delim, len);
|
|
if (t != NULL)
|
|
{
|
|
len = t - read_ptr;
|
|
if (extract_delim >= 0)
|
|
{
|
|
++t;
|
|
if (extract_delim > 0)
|
|
++len;
|
|
}
|
|
__wmemcpy (ptr, read_ptr, len);
|
|
fp->_wide_data->_IO_read_ptr = t;
|
|
return (ptr - buf) + len;
|
|
}
|
|
__wmemcpy (ptr, read_ptr, len);
|
|
fp->_wide_data->_IO_read_ptr = read_ptr + len;
|
|
ptr += len;
|
|
n -= len;
|
|
}
|
|
return ptr - buf;
|
|
}
|