about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--libio/Makefile4
-rw-r--r--libio/tst-fgetwc.input2
-rw-r--r--libio/wfileops.c48
4 files changed, 47 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 2cb9f7e3b5..59fb6a1e25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
-2009-02-04  Andreas Jaeger  <aj@suse.de>
+2009-02-04  Ulrich Drepper  <drepper@redhat.com>
 
-	* FAQ.in: Remove reference to my mips page.
+	* libio/wfileops.c (_IO_wfile_underflow): Fix handling of
+	incomplete characters at end of input buffer.
+	* libio/Makefile (tests): Add tst-fgetwc.
+	* libio/tst-fgetwc.c: New file.
+	* libio/tst-fgetwc.input: New file.
 
 2009-02-02  Andrew Stubbs  <ams@codesourcery.com>
 
diff --git a/libio/Makefile b/libio/Makefile
index 385040fb96..b94d047f5a 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2004,2006,2007,2008 Free Software Foundation, Inc.
+# Copyright (C) 1995-2004,2006,2007,2008,2009 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
@@ -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-setvbuf1 tst-popen1 tst-fgetwc
 test-srcs = test-freopen
 
 all: # Make this the default target; it will be defined in Rules.
diff --git a/libio/tst-fgetwc.input b/libio/tst-fgetwc.input
new file mode 100644
index 0000000000..b1a48dadb8
--- /dev/null
+++ b/libio/tst-fgetwc.input
@@ -0,0 +1,2 @@
+йцукен
+qwerty
diff --git a/libio/wfileops.c b/libio/wfileops.c
index b930aad067..c5f0eaf6a7 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993,1995,1997-2003,2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1993,1995,1997-2004,2006,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Ulrich Drepper <drepper@cygnus.com>.
    Based on the single byte version by Per Bothner <bothner@cygnus.com>.
@@ -123,8 +123,6 @@ _IO_wfile_underflow (fp)
   struct _IO_codecvt *cd;
   enum __codecvt_result status;
   _IO_ssize_t count;
-  int tries;
-  const char *read_ptr_copy;
 
   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
     {
@@ -236,13 +234,15 @@ _IO_wfile_underflow (fp)
   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
 
-  tries = 0;
+  const char *read_ptr_copy;
+  char accbuf[MB_LEN_MAX];
+  size_t naccbuf = 0;
  again:
   count = _IO_SYSREAD (fp, fp->_IO_read_end,
 		       fp->_IO_buf_end - fp->_IO_read_end);
   if (count <= 0)
     {
-      if (count == 0 && tries == 0)
+      if (count == 0 && naccbuf == 0)
 	fp->_flags |= _IO_EOF_SEEN;
       else
 	fp->_flags |= _IO_ERR_SEEN, count = 0;
@@ -250,7 +250,7 @@ _IO_wfile_underflow (fp)
   fp->_IO_read_end += count;
   if (count == 0)
     {
-      if (tries != 0)
+      if (naccbuf != 0)
 	/* There are some bytes in the external buffer but they don't
            convert to anything.  */
 	__set_errno (EILSEQ);
@@ -262,18 +262,31 @@ _IO_wfile_underflow (fp)
   /* Now convert the read input.  */
   fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
   fp->_IO_read_base = fp->_IO_read_ptr;
+  const char *from = fp->_IO_read_ptr;
+  const char *to = fp->_IO_read_end;
+  size_t to_copy = count;
+  if (__builtin_expect (naccbuf != 0, 0))
+    {
+      to_copy = MIN (sizeof (accbuf) - naccbuf, count);
+      to = __mempcpy (&accbuf[naccbuf], from, to_copy);
+      naccbuf += to_copy;
+      from = accbuf;
+    }
   status = (*cd->__codecvt_do_in) (cd, &fp->_wide_data->_IO_state,
-				   fp->_IO_read_ptr, fp->_IO_read_end,
-				   &read_ptr_copy,
+				   from, to, &read_ptr_copy,
 				   fp->_wide_data->_IO_read_end,
 				   fp->_wide_data->_IO_buf_end,
 				   &fp->_wide_data->_IO_read_end);
 
-  fp->_IO_read_ptr = (char *) read_ptr_copy;
+  if (__builtin_expect (naccbuf != 0, 0))
+    fp->_IO_read_ptr += MAX (0, read_ptr_copy - &accbuf[naccbuf - to_copy]);
+  else
+    fp->_IO_read_ptr = (char *) read_ptr_copy;
   if (fp->_wide_data->_IO_read_end == fp->_wide_data->_IO_buf_base)
     {
-      if (status == __codecvt_error || fp->_IO_read_end == fp->_IO_buf_end)
+      if (status == __codecvt_error)
 	{
+	out_eilseq:
 	  __set_errno (EILSEQ);
 	  fp->_flags |= _IO_ERR_SEEN;
 	  return WEOF;
@@ -281,7 +294,20 @@ _IO_wfile_underflow (fp)
 
       /* The read bytes make no complete character.  Try reading again.  */
       assert (status == __codecvt_partial);
-      ++tries;
+
+      if (naccbuf == 0)
+	{
+	  naccbuf = fp->_IO_read_end - fp->_IO_read_ptr;
+	  if (naccbuf >= sizeof (accbuf))
+	    goto out_eilseq;
+
+	  memcpy (accbuf, fp->_IO_read_ptr, naccbuf);
+	}
+      else if (naccbuf == sizeof (accbuf))
+	goto out_eilseq;
+
+      fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_read_base;
+
       goto again;
     }