]> granicus.if.org Git - mutt/commitdiff
Make my_wcstombs more robust. From EGE.
authorThomas Roessler <roessler@does-not-exist.org>
Tue, 2 Jan 2001 16:34:26 +0000 (16:34 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Tue, 2 Jan 2001 16:34:26 +0000 (16:34 +0000)
enter.c

diff --git a/enter.c b/enter.c
index 6f17f3bc606d2ed12b9d25ef234982bb57683d9a..13e2fc3e4439cefd5ab9fdc43e359f75e56cbb53 100644 (file)
--- a/enter.c
+++ b/enter.c
@@ -63,16 +63,43 @@ static size_t width_ceiling (const wchar_t *s, size_t n, int w1)
   return s - s0;  
 }
 
-void my_wcstombs(char *dest, size_t dlen, const wchar_t *src, size_t slen)
+static void my_wcstombs (char *dest, size_t dlen, const wchar_t *src, size_t slen)
 {
   mbstate_t st;
-  size_t  k;
+  size_t k;
 
+  /* First convert directly into the destination buffer */
   memset (&st, 0, sizeof (st));
-  for (; slen && dlen >= 2 * MB_LEN_MAX; dest += k, dlen -= k, src++, slen--)
+  for (; slen && dlen >= MB_LEN_MAX; dest += k, dlen -= k, src++, slen--)
     if ((k = wcrtomb (dest, *src, &st)) == (size_t)(-1))
       break;
-  wcrtomb (dest, 0, &st); /* FIXME */
+
+  /* If this works, we can stop now */
+  if (dlen >= MB_LEN_MAX) {
+    wcrtomb (dest, 0, &st);
+    return;
+  }
+
+  /* Otherwise convert any remaining data into a local buffer */
+  {
+    char buf[3 * MB_LEN_MAX];
+    char *p = buf;
+
+    for (; slen && p - buf < dlen; p += k, src++, slen--)
+      if ((k = wcrtomb (p, *src, &st)) == (size_t)(-1))
+       break;
+    p += wcrtomb (p, 0, &st);
+
+    /* If it fits into the destination buffer, we can stop now */
+    if (p - buf <= dlen) {
+      memcpy (dest, buf, p - buf);
+      return;
+    }
+
+    /* Otherwise we truncate the string in an ugly fashion */
+    memcpy (dest, buf, dlen);
+    dest[dlen - 1] = '\0'; /* assume original dlen > 0 */
+  }
 }
 
 size_t my_mbstowcs (wchar_t **pwbuf, size_t *pwbuflen, size_t i, char *buf)