Fix fsetpos on wide stream.

This commit is contained in:
Andreas Schwab 2009-09-02 19:45:33 -07:00 committed by Ulrich Drepper
parent 22bb992d51
commit 5d2e69766a
4 changed files with 97 additions and 36 deletions

View File

@ -1,3 +1,10 @@
2009-09-02 Andreas Schwab <schwab@redhat.com>
* libio/wfileops.c (_IO_wfile_seekoff): Account for readahead in
external buffer. Always discard readahead in internal buffer.
* libio/Makefile (tests): Add bug-wsetpos.
* libio/bug-wsetpos.c: New file.
2009-09-02 Jakub Jelinek <jakub@redhat.com>
* sysdeps/x86_64/multiarch/strstr-c.c (__strstr_sse42, __strstr_sse2):

View File

@ -58,7 +58,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
tst-memstream1 tst-memstream2 \
tst-wmemstream1 tst-wmemstream2 \
bug-memstream1 bug-wmemstream1 \
tst-setvbuf1 tst-popen1 tst-fgetwc
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos
test-srcs = test-freopen
all: # Make this the default target; it will be defined in Rules.

75
libio/bug-wsetpos.c Normal file
View File

@ -0,0 +1,75 @@
/* Test program for fsetpos on a wide character stream. */
#include <assert.h>
#include <stdio.h>
#include <wchar.h>
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include <test-skeleton.c>
static const char pattern[] = "12345";
static char *temp_file;
static void
do_prepare (void)
{
int fd = create_temp_file ("bug-wsetpos.", &temp_file);
if (fd == -1)
{
printf ("cannot create temporary file: %m\n");
exit (1);
}
write (fd, pattern, sizeof (pattern));
close (fd);
}
static int
do_test (void)
{
FILE *fp = fopen (temp_file, "r");
fpos_t pos;
wchar_t c;
if (fp == NULL)
{
printf ("fdopen: %m\n");
return 1;
}
c = fgetwc (fp); assert (c == L'1');
c = fgetwc (fp); assert (c == L'2');
if (fgetpos (fp, &pos) == EOF)
{
printf ("fgetpos: %m\n");
return 1;
}
rewind (fp);
if (ferror (fp))
{
printf ("rewind: %m\n");
return 1;
}
c = fgetwc (fp); assert (c == L'1');
if (fsetpos (fp, &pos) == EOF)
{
printf ("fsetpos: %m\n");
return 1;
}
c = fgetwc (fp);
if (c != L'3')
{
puts ("fsetpos failed");
return 1;
}
puts ("Test succeeded.");
return 0;
}

View File

@ -631,8 +631,12 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
clen = (*cv->__codecvt_do_encoding) (cv);
if (clen > 0)
offset -= (fp->_wide_data->_IO_read_end
- fp->_wide_data->_IO_read_ptr) * clen;
{
offset -= (fp->_wide_data->_IO_read_end
- fp->_wide_data->_IO_read_ptr) * clen;
/* Adjust by readahead in external buffer. */
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
}
else
{
int nread;
@ -690,39 +694,11 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
fp->_IO_buf_base + (offset - start_offset),
fp->_IO_read_end);
_IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
/* Now set the pointer for the internal buffer. This
might be an iterative process. Though the read
pointer is somewhere in the current external buffer
this does not mean we can convert this whole buffer
at once fitting in the internal buffer. */
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
read_ptr_copy = fp->_IO_read_base;
fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
do
{
wchar_t buffer[1024];
wchar_t *ignore;
status = (*cd->__codecvt_do_in) (cd,
&fp->_wide_data->_IO_state,
read_ptr_copy,
fp->_IO_read_ptr,
&read_ptr_copy,
buffer,
buffer
+ (sizeof (buffer)
/ sizeof (buffer[0])),
&ignore);
if (status != __codecvt_ok && status != __codecvt_partial)
{
fp->_flags |= _IO_ERR_SEEN;
goto dumb;
}
}
while (read_ptr_copy != fp->_IO_read_ptr);
fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_base;
_IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base);
_IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base);
_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
goto resync;
}
@ -760,6 +736,9 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
_IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
fp->_IO_buf_base + count);
_IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
_IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
_IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
fp->_offset = result + count;
_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
return offset;