diff --git a/ChangeLog b/ChangeLog index ef087c7944..23cf69eae4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-09-02 Andreas Schwab + + * 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 * sysdeps/x86_64/multiarch/strstr-c.c (__strstr_sse42, __strstr_sse2): diff --git a/libio/Makefile b/libio/Makefile index 501e80c2ee..83b9458dc2 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -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. diff --git a/libio/bug-wsetpos.c b/libio/bug-wsetpos.c new file mode 100644 index 0000000000..ccb22a4b62 --- /dev/null +++ b/libio/bug-wsetpos.c @@ -0,0 +1,75 @@ +/* Test program for fsetpos on a wide character stream. */ + +#include +#include +#include + +static void do_prepare (void); +#define PREPARE(argc, argv) do_prepare () +static int do_test (void); +#define TEST_FUNCTION do_test () +#include + +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; +} diff --git a/libio/wfileops.c b/libio/wfileops.c index be8ae78bfb..5bc08bedfb 100644 --- a/libio/wfileops.c +++ b/libio/wfileops.c @@ -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;