Fix fsetpos on wide stream.
authorAndreas Schwab <schwab@redhat.com>
Thu, 3 Sep 2009 02:45:33 +0000 (19:45 -0700)
committerUlrich Drepper <drepper@redhat.com>
Thu, 3 Sep 2009 02:45:33 +0000 (19:45 -0700)
ChangeLog
libio/Makefile
libio/bug-wsetpos.c [new file with mode: 0644]
libio/wfileops.c

index ef087c7..23cf69e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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):
index 501e80c..83b9458 100644 (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.
diff --git a/libio/bug-wsetpos.c b/libio/bug-wsetpos.c
new file mode 100644 (file)
index 0000000..ccb22a4
--- /dev/null
@@ -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;
+}
index be8ae78..5bc08be 100644 (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;