]> 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)
committerKevin McCarthy <kevin@8t8.us>
Tue, 27 Dec 2016 23:23:19 +0000 (15:23 -0800)
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 ec04e2cab771d6c2f09bef90978f26848f3b072a..8b12d7f72d63c960ad5b0b04893846071d4fb1ff 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: \\(lq", 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 fc83b3dceceb01facb30b00bcd55b3d08b3f022a..60d74135a3c6634f8e01333a304dbacded983276 100644 (file)
--- a/init.c
+++ b/init.c
@@ -603,6 +603,59 @@ static void remove_from_list (LIST **l, const char *str)
   }
 }
 
+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 @@ 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)
@@ -1956,7 +2013,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)
       {
@@ -1965,6 +2023,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 */
@@ -2001,6 +2061,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);
        
@@ -2055,6 +2120,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);
@@ -2792,6 +2862,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 4578974f86704c380e0e9a45e78eb848d97da4a2..aacc492ef5839bdc81a0f646b8fe516313b19598 100644 (file)
--- a/init.h
+++ b/init.h
@@ -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)
 
diff --git a/mutt.h b/mutt.h
index 354b15bfd0808d1a0515271454de8fe2dc9f4254..4d80f34b97ad9331d44909477dbc06318e658f6e 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -1020,6 +1020,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"