<<< Date Index >>>     <<< Thread Index >>>

[PATCH] Make mutt_FormatString multibyte aware



For the %> and %| expandos in format strings, mutt used 'ch = *src++' to
extract the pad character which works for single-byte locales only.
We now use a multibyte aware get_mbchar() to extract it.
---
 Note that this a rather crude hack using a static get_mbchar() routine
 in muttlib.c which likely could be of some valid use in other places,
 too. Also note that I don't have much experience with the multibyte
 string functions, so please test heavily and use with care. At least it
 appears to work... :)

 For example, we can use %>U+2014 in $status_format to get a horizontal
 bar without gaps, I didn't test any other format strings.

 muttlib.c |   45 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/muttlib.c b/muttlib.c
index 32495f3..a405d30 100644
--- a/muttlib.c
+++ b/muttlib.c
@@ -985,6 +985,33 @@ void mutt_safe_path (char *s, size_t l, ADDRESS *a)
       *p = '_';
 }
 
+/* extract first (possibly multibyte) character from src into dst;
+ * return number of bytes char consists of */
+static int get_mbchar (char *dst, const char* src)
+{
+  mbstate_t st;
+  wchar_t wc;
+  int i;
+  char *p = (char *) src;
+
+  memset (&st, 0, sizeof (st));
+  memset (&wc, 0, sizeof (wc));
+
+  i = mbrtowc (&wc, p, MB_LEN_MAX, &st);
+  if (i == (size_t)(-1) || i == (size_t)(-2) || i == 0)
+    goto bail;
+  p += i;
+  i = wctomb (dst, wc);
+  if (i == (size_t)(-1) || i == 0)
+    goto bail;
+
+  return p - src;
+
+bail:
+  /* in case of conversion error: take first byte from src */
+  *dst = *src;
+  return 1;
+}
 
 void mutt_FormatString (char *dest,            /* output buffer */
                        size_t destlen,         /* output buffer len */
@@ -1000,6 +1027,7 @@ void mutt_FormatString (char *dest,               /* 
output buffer */
   FILE *filter;
   int n;
   char *recycler;
+  char pad[MB_LEN_MAX] = "";
 
   prefix[0] = '\0';
   destlen--; /* save room for the terminal \0 */
@@ -1191,7 +1219,8 @@ void mutt_FormatString (char *dest,               /* 
output buffer */
       if (ch == '>')
       {
        /* right justify to EOL */
-       ch = *src++; /* pad char */
+       size_t padlen = get_mbchar (pad, src);  /* pad char */
+       src += padlen;
        /* calculate space left on line.  if we've already written more data
           than will fit on the line, ignore the rest of the line */
        count = (COLS < destlen ? COLS : destlen);
@@ -1203,9 +1232,10 @@ void mutt_FormatString (char *dest,              /* 
output buffer */
          wid = mutt_strwidth (buf);
          if (count > wid)
          {
+           int i;
            count -= wid; /* how many chars to pad */
-           memset (wptr, ch, count);
-           wptr += count;
+           for (i = 0; i < count; i++, wptr += padlen)
+             memcpy (wptr, pad, padlen);
            wlen += count;
            col += count;
          }
@@ -1221,14 +1251,17 @@ void mutt_FormatString (char *dest,             /* 
output buffer */
       else if (ch == '|')
       {
        /* pad to EOL */
-       ch = *src++;
+       size_t padlen = get_mbchar (pad, src); /* pad char */
+       src += padlen;
+
        if (destlen > COLS)
          destlen = COLS;
        if (destlen > wlen)
        {
+         int i;
          count = destlen - wlen;
-         memset (wptr, ch, count);
-         wptr += count;
+         for (i = 0; i < count; i++, wptr += padlen)
+           memcpy (wptr, pad, padlen);
        }
        break; /* skip rest of input */
       }
-- 
1.5.0.4.1009.g31b4