]> granicus.if.org Git - neomutt/commitdiff
Create mbchar_table type for multibyte character arrays. (see #3024)
authorKevin McCarthy <kevin@8t8.us>
Tue, 27 Dec 2016 23:23:19 +0000 (15:23 -0800)
committerRichard Russon <rich@flatcap.org>
Fri, 30 Dec 2016 20:05:36 +0000 (20:05 +0000)
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.

doc/makedoc.c
init.c
init.h
mutt.h

index bcc727142590c5141d2cd4ec1148c5bad0808064..8ad4519d267b8c6cb4ad69c01a8843f84fa2107a 100644 (file)
@@ -358,7 +358,8 @@ enum
   DT_RX,
   DT_MAGIC,
   DT_SYN,
-  DT_ADDR
+  DT_ADDR,
+  DT_MBCHARTBL
 };
 
 struct 
@@ -379,6 +380,7 @@ types[] =
   { "DT_MAGIC",        "folder magic" },
   { "DT_SYN",  NULL },
   { "DT_ADDR", "e-mail address" },
+  { "DT_MBCHARTBL", "string"   },
   { NULL, NULL }
 };
     
@@ -520,6 +522,7 @@ static void pretty_default (char *t, size_t l, const char *s, int type)
     case DT_RX:
     case DT_ADDR:
     case DT_PATH:
+    case DT_MBCHARTBL:
     {
       if (!strcmp (s, "0"))
        break;
@@ -658,7 +661,8 @@ static void print_confline (const char *varname, int type, const char *val, FILE
     /* 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 @@ static void print_confline (const char *varname, int type, const char *val, FILE
       
       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 @@ static void print_confline (const char *varname, int type, const char *val, FILE
       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: \"", out);
        man_print_strval (val, out);
@@ -715,7 +721,8 @@ static void print_confline (const char *varname, int type, const char *val, FILE
       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 --git a/init.c b/init.c
index e3e33f80e1ba2c7ef827ae0bf8b92de63660797c..8618343499cb12420f20ec8962536ed5c1425a2f 100644 (file)
--- a/init.c
+++ b/init.c
@@ -731,6 +731,59 @@ static int parse_ifdef (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
   return 0;
 }
 
+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
@@ -1663,6 +1716,10 @@ static void mutt_restore_default (struct option_t *p)
     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)
@@ -2090,7 +2147,8 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
     }
     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)
       {
@@ -2099,6 +2157,8 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
           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 */
@@ -2135,6 +2195,11 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
          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);
        
@@ -2189,6 +2254,11 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
          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);
@@ -3128,6 +3198,11 @@ static int var_to_string (int idx, char* val, size_t len)
     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 --git a/init.h b/init.h
index add06ad8fbf1f0378e12acf46cfa0d20b7d428d5..6c39ac80006002466c118da1c9a84ebcd3117d98 100644 (file)
--- a/init.h
+++ b/init.h
@@ -38,7 +38,8 @@
 #define DT_MAGIC       8 /* mailbox type */
 #define DT_SYN         9 /* synonym for another variable */
 #define DT_ADDR                10 /* e-mail address */
-#define DT_HCACHE      11 /* header cache backend */
+#define DT_MBCHARTBL   11 /* multibyte char table */
+#define DT_HCACHE      12 /* header cache backend */
 
 #define DTYPE(x) ((x) & DT_MASK)
 
diff --git a/mutt.h b/mutt.h
index 1d693e0c79a5b4ee4450c04f8a722960d83a5b99..6e44a4cf3e51d19bde63ede2824f0424eed06ef9 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -1106,6 +1106,17 @@ typedef struct
   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"