changeset: 6894:1d054932abfb
user:      Kevin McCarthy <ke...@8t8.us>
date:      Tue Dec 27 15:23:19 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/1d054932abfb

Create mbchar_table type for multibyte character arrays. (see #3024)

This type is to allow multibyte characters in to_chars and
status_chars while preserving efficient indexing to each character.

The arrays are tokenized during initialization, and are re-tokenized
as the values are unset, reset, and set.

changeset: 6895:4cb0cd767af2
user:      Kevin McCarthy <ke...@8t8.us>
date:      Tue Dec 27 15:23:37 2016 -0800
link:      http://dev.mutt.org/hg/mutt/rev/4cb0cd767af2

Make to_chars and status_chars accept mulitibyte characters. (closes #3024)

Change Tochars and StChars to use the mbchars_table type introduced in
the last commit.

diffs (319 lines):

diff -r 1303567a6ad1 -r 4cb0cd767af2 doc/makedoc.c
--- a/doc/makedoc.c     Sun Dec 25 23:31:01 2016 +0100
+++ b/doc/makedoc.c     Tue Dec 27 15:23:37 2016 -0800
@@ -358,7 +358,8 @@
   DT_RX,
   DT_MAGIC,
   DT_SYN,
-  DT_ADDR
+  DT_ADDR,
+  DT_MBCHARTBL
 };
 
 struct 
@@ -379,6 +380,7 @@
   { "DT_MAGIC",        "folder magic" },
   { "DT_SYN",  NULL },
   { "DT_ADDR", "e-mail address" },
+  { "DT_MBCHARTBL", "string"   },
   { NULL, NULL }
 };
     
@@ -520,6 +522,7 @@
     case DT_RX:
     case DT_ADDR:
     case DT_PATH:
+    case DT_MBCHARTBL:
     {
       if (!strcmp (s, "0"))
        break;
@@ -658,7 +661,8 @@
     /* configuration file */
     case F_CONF:
     {
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH)
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH ||
+          type == DT_MBCHARTBL)
       {
        fprintf (out, "\n# set %s=\"", varname);
        conf_print_strval (val, out);
@@ -669,7 +673,8 @@
       
       fprintf (out, "\n#\n# Name: %s", varname);
       fprintf (out, "\n# Type: %s", type2human (type));
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH)
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH ||
+          type == DT_MBCHARTBL)
       {
        fputs ("\n# Default: \"", out);
        conf_print_strval (val, out);
@@ -688,7 +693,8 @@
       fprintf (out, "\n.TP\n.B %s\n", varname);
       fputs (".nf\n", out);
       fprintf (out, "Type: %s\n", type2human (type));
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH)
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH ||
+          type == DT_MBCHARTBL)
       {
        fputs ("Default: \\(lq", out);
        man_print_strval (val, out);
@@ -715,7 +721,8 @@
       fprintf (out, "</title>\n<literallayout>Type: %s", type2human (type));
 
       
-      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH)
+      if (type == DT_STR || type == DT_RX || type == DT_ADDR || type == 
DT_PATH ||
+          type == DT_MBCHARTBL)
       {
        if (val && *val)
        {
diff -r 1303567a6ad1 -r 4cb0cd767af2 globals.h
--- a/globals.h Sun Dec 25 23:31:01 2016 +0100
+++ b/globals.h Tue Dec 27 15:23:37 2016 -0800
@@ -144,10 +144,10 @@
 WHERE char *SslCACertFile INITVAL (NULL);
 #endif
 #endif
-WHERE char *StChars;
+WHERE mbchar_table *StChars;
 WHERE char *Status;
 WHERE char *Tempdir;
-WHERE char *Tochars;
+WHERE mbchar_table *Tochars;
 WHERE char *TrashPath;
 WHERE char *TSStatusFormat;
 WHERE char *TSIconFormat;
diff -r 1303567a6ad1 -r 4cb0cd767af2 hdrline.c
--- a/hdrline.c Sun Dec 25 23:31:01 2016 +0100
+++ b/hdrline.c Tue Dec 27 15:23:37 2016 -0800
@@ -620,9 +620,9 @@
       break;
 
     case 'T':
-      snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
+      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
       snprintf (dest, destlen, fmt,
-               (Tochars && ((i = mutt_user_is_recipient (hdr))) < mutt_strlen 
(Tochars)) ? Tochars[i] : ' ');
+               (Tochars && ((i = mutt_user_is_recipient (hdr))) < 
Tochars->len) ? Tochars->chars[i] : " ");
       break;
 
     case 'u':
@@ -668,13 +668,13 @@
         ch = 'K';
 
       snprintf (buf2, sizeof (buf2),
-               "%c%c%c", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' : 
+               "%c%c%s", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' :
                ((hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
                ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N')))),
                hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
-               hdr->tagged ? '*' :
-               (hdr->flagged ? '!' :
-                (Tochars && ((i = mutt_user_is_recipient (hdr)) < mutt_strlen 
(Tochars)) ? Tochars[i] : ' ')));
+               hdr->tagged ? "*" :
+               (hdr->flagged ? "!" :
+                (Tochars && ((i = mutt_user_is_recipient (hdr)) < 
Tochars->len) ? Tochars->chars[i] : " ")));
       mutt_format_s (dest, destlen, prefix, buf2);
       break;
 
diff -r 1303567a6ad1 -r 4cb0cd767af2 init.c
--- a/init.c    Sun Dec 25 23:31:01 2016 +0100
+++ b/init.c    Tue Dec 27 15:23:37 2016 -0800
@@ -603,6 +603,59 @@
   }
 }
 
+static void free_mbchar_table (mbchar_table **t)
+{
+  if (!t || !*t)
+    return;
+
+  FREE (&(*t)->chars);
+  FREE (&(*t)->segmented_str);
+  FREE (&(*t)->orig_str);
+  FREE (t);            /* __FREE_CHECKED__ */
+}
+
+static mbchar_table *parse_mbchar_table (const char *s)
+{
+  mbchar_table *t;
+  size_t slen, k;
+  mbstate_t mbstate;
+  char *d;
+
+  t = safe_calloc (1, sizeof (mbchar_table));
+  slen = mutt_strlen (s);
+  if (!slen)
+    return t;
+
+  t->orig_str = safe_strdup (s);
+  /* This could be more space efficient.  However, being used on tiny
+   * strings (Tochars and StChars), the overhead is not great. */
+  t->chars = safe_calloc (slen, sizeof (char *));
+  d = t->segmented_str = safe_calloc (slen * 2, sizeof (char));
+
+  memset (&mbstate, 0, sizeof (mbstate));
+  while (slen && (k = mbrtowc (NULL, s, slen, &mbstate)))
+  {
+    if (k == (size_t)(-1) || k == (size_t)(-2))
+    {
+      dprint (1, (debugfile,
+                  "parse_mbchar_table: mbrtowc returned %d converting %s in 
%s\n",
+                  (k == (size_t)(-1)) ? -1 : -2,
+                  s, t->orig_str));
+      if (k == (size_t)(-1))
+        memset (&mbstate, 0, sizeof (mbstate));
+      k = (k == (size_t)(-1)) ? 1 : slen;
+    }
+
+    slen -= k;
+    t->chars[t->len++] = d;
+    while (k--)
+      *d++ = *s++;
+    *d++ = '\0';
+  }
+
+  return t;
+}
+
 static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER 
*err)
 {
   do
@@ -1535,6 +1588,10 @@
     case DT_STR:
       mutt_str_replace ((char **) p->data, (char *) p->init); 
       break;
+    case DT_MBCHARTBL:
+      free_mbchar_table ((mbchar_table **)p->data);
+      *((mbchar_table **) p->data) = parse_mbchar_table ((char *) p->init);
+      break;
     case DT_PATH:
       FREE((char **) p->data);         /* __FREE_CHECKED__ */
       if (p->init)
@@ -1956,7 +2013,8 @@
     }
     else if (myvar || DTYPE (MuttVars[idx].type) == DT_STR ||
             DTYPE (MuttVars[idx].type) == DT_PATH ||
-            DTYPE (MuttVars[idx].type) == DT_ADDR)
+            DTYPE (MuttVars[idx].type) == DT_ADDR ||
+            DTYPE (MuttVars[idx].type) == DT_MBCHARTBL)
     {
       if (unset)
       {
@@ -1965,6 +2023,8 @@
           myvar_del (myvar);
        else if (DTYPE (MuttVars[idx].type) == DT_ADDR)
          rfc822_free_address ((ADDRESS **) MuttVars[idx].data);
+       else if (DTYPE (MuttVars[idx].type) == DT_MBCHARTBL)
+          free_mbchar_table ((mbchar_table **) MuttVars[idx].data);
        else
          /* MuttVars[idx].data is already 'char**' (or some 'void**') or... 
           * so cast to 'void*' is okay */
@@ -2001,6 +2061,11 @@
          mutt_pretty_mailbox (_tmp, sizeof (_tmp));
          val = _tmp;
        }
+       else if (DTYPE (MuttVars[idx].type) == DT_MBCHARTBL)
+        {
+          mbchar_table *mbt = (*((mbchar_table **) MuttVars[idx].data));
+          val = mbt ? NONULL (mbt->orig_str) : "";
+        }
        else
          val = *((char **) MuttVars[idx].data);
        
@@ -2055,6 +2120,11 @@
          if (mutt_strcmp (MuttVars[idx].option, "charset") == 0)
            mutt_set_charset (Charset);
         }
+        else if (DTYPE (MuttVars[idx].type) == DT_MBCHARTBL)
+        {
+          free_mbchar_table ((mbchar_table **) MuttVars[idx].data);
+          *((mbchar_table **) MuttVars[idx].data) = parse_mbchar_table 
(tmp->data);
+        }
         else
         {
          rfc822_free_address ((ADDRESS **) MuttVars[idx].data);
@@ -2792,6 +2862,11 @@
     if (DTYPE (MuttVars[idx].type) == DT_PATH)
       mutt_pretty_mailbox (tmp, sizeof (tmp));
   }
+  else if (DTYPE (MuttVars[idx].type) == DT_MBCHARTBL)
+  {
+    mbchar_table *mbt = (*((mbchar_table **) MuttVars[idx].data));
+    strfcpy (tmp, mbt ? NONULL (mbt->orig_str) : "", sizeof (tmp));
+  }
   else if (DTYPE (MuttVars[idx].type) == DT_ADDR)
   {
     rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) 
MuttVars[idx].data), 0);
diff -r 1303567a6ad1 -r 4cb0cd767af2 init.h
--- a/init.h    Sun Dec 25 23:31:01 2016 +0100
+++ b/init.h    Tue Dec 27 15:23:37 2016 -0800
@@ -38,6 +38,7 @@
 #define DT_MAGIC       8 /* mailbox type */
 #define DT_SYN         9 /* synonym for another variable */
 #define DT_ADDR               10 /* e-mail address */
+#define DT_MBCHARTBL   11 /* multibyte char table */
 
 #define DTYPE(x) ((x) & DT_MASK)
 
@@ -3385,7 +3386,7 @@
   ** required.)
   */
 #endif /* defined(USE_SSL) */
-  { "status_chars",    DT_STR,  R_BOTH, UL &StChars, UL "-*%A" },
+  { "status_chars",    DT_MBCHARTBL, R_BOTH, UL &StChars, UL "-*%A" },
   /*
   ** .pp
   ** Controls the characters used by the ``%r'' indicator in
@@ -3569,7 +3570,7 @@
   ** this variable is not set, the environment variable \fC$$$TMPDIR\fP is
   ** used.  If \fC$$$TMPDIR\fP is not set then ``\fC/tmp\fP'' is used.
   */
-  { "to_chars",                DT_STR,  R_BOTH, UL &Tochars, UL " +TCFL" },
+  { "to_chars",                DT_MBCHARTBL, R_BOTH, UL &Tochars, UL " +TCFL" 
},
   /*
   ** .pp
   ** Controls the character used to indicate mail addressed to you.  The
diff -r 1303567a6ad1 -r 4cb0cd767af2 mutt.h
--- a/mutt.h    Sun Dec 25 23:31:01 2016 +0100
+++ b/mutt.h    Tue Dec 27 15:23:37 2016 -0800
@@ -1020,6 +1020,17 @@
   regex_t minor_rx;
 } ATTACH_MATCH;
 
+/* multibyte character table.
+ * Allows for direct access to the individual multibyte characters in a
+ * string.  This is used for the Tochars and StChars option types. */
+typedef struct
+{
+  int len;               /* number of characters */
+  char **chars;          /* the array of multibyte character strings */
+  char *segmented_str;   /* each chars entry points inside this string */
+  char *orig_str;
+} mbchar_table;
+
 #define MUTT_PARTS_TOPLEVEL    (1<<0)  /* is the top-level part */
 
 #include "ascii.h"
diff -r 1303567a6ad1 -r 4cb0cd767af2 status.c
--- a/status.c  Sun Dec 25 23:31:01 2016 +0100
+++ b/status.c  Tue Dec 27 15:23:37 2016 -0800
@@ -228,14 +228,12 @@
            Context->deleted)) ? 1 : 0);
       }
       
-      if (!StChars)
+      if (!StChars || !StChars->len)
        buf[0] = 0;
-      else if (i >= mutt_strlen(StChars))
-       buf[0] = StChars[0];
+      else if (i >= StChars->len)
+        snprintf (buf, buflen, "%s", StChars->chars[0]);
       else
-       buf[0] = StChars[i];
-
-      buf[1] = 0;
+        snprintf (buf, buflen, "%s", StChars->chars[i]);
       break;
     }
       

Reply via email to