about summary refs log tree commit diff
path: root/wcsmbs/mbsrtowcs_l.c
diff options
context:
space:
mode:
Diffstat (limited to 'wcsmbs/mbsrtowcs_l.c')
-rw-r--r--wcsmbs/mbsrtowcs_l.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/wcsmbs/mbsrtowcs_l.c b/wcsmbs/mbsrtowcs_l.c
index 1e46856172..8da3095566 100644
--- a/wcsmbs/mbsrtowcs_l.c
+++ b/wcsmbs/mbsrtowcs_l.c
@@ -102,18 +102,36 @@ __mbsrtowcs_l (dst, src, len, ps, l)
       /* This code is based on the safe assumption that all internal
 	 multi-byte encodings use the NUL byte only to mark the end
 	 of the string.  */
+      const unsigned char *srcp = (const unsigned char *) *src;
       const unsigned char *srcend;
 
-      srcend = (const unsigned char *) (*src
-					+ __strnlen (*src, len * MB_CUR_MAX)
-					+ 1);
-
       data.__outbuf = (unsigned char *) dst;
       data.__outbufend = data.__outbuf + len * sizeof (wchar_t);
 
-      status = DL_CALL_FCT (towc->__fct,
-			    (towc, &data, (const unsigned char **) src, srcend,
-			     NULL, &non_reversible, 0, 1));
+      status = __GCONV_FULL_OUTPUT;
+
+      while (len > 0)
+	{
+	  /* Pessimistic guess as to how much input we can use.  In the
+	     worst case we need one input byte for one output wchar_t.  */
+	  srcend = srcp + __strnlen (srcp, len) + 1;
+
+	  status = DL_CALL_FCT (towc->__fct,
+				(towc, &data, &srcp, srcend, NULL,
+				 &non_reversible, 0, 1));
+	  if ((status != __GCONV_EMPTY_INPUT
+	       && status != __GCONV_INCOMPLETE_INPUT)
+	      /* Not all input read.  */
+	      || srcp != srcend
+	      /* Reached the end of the input.  */
+	      || srcend[-1] == '\0')
+	    break;
+
+	  len = (wchar_t *) data.__outbufend - (wchar_t *) data.__outbuf;
+	}
+
+      /* Make the end if the input known to the caller.  */
+      *src = srcp;
 
       result = (wchar_t *) data.__outbuf - dst;