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 parsed into pieces during initialization, and are
reparsed as the values are unset, reset, and set.

-- 
Kevin J. McCarthy
GPG Fingerprint: 8975 A9B3 3AA3 7910 385C  5308 ADEF 7684 8031 6BDA
# HG changeset patch
# User Kevin McCarthy <ke...@8t8.us>
# Date 1481685423 28800
#      Tue Dec 13 19:17:03 2016 -0800
# Node ID eb09bb75f18345bf9550c25cf32041343df486fe
# Parent  b112fd7061fb896ba9584e487896756a4f96e90b
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 parsed into pieces during initialization, and are
reparsed as the values are unset, reset, and set.

diff --git a/doc/makedoc.c b/doc/makedoc.c
--- a/doc/makedoc.c
+++ b/doc/makedoc.c
@@ -353,17 +353,18 @@
   DT_NUM,
   DT_STR,
   DT_PATH,
   DT_QUAD,
   DT_SORT,
   DT_RX,
   DT_MAGIC,
   DT_SYN,
-  DT_ADDR
+  DT_ADDR,
+  DT_MBCHARTBL
 };
 
 struct 
 {
   char *machine;
   char *human;
 }
 types[] = 
@@ -374,16 +375,17 @@
   { "DT_STR",  "string"        },
   { "DT_PATH", "path"          },
   { "DT_QUAD", "quadoption"    },
   { "DT_SORT", "sort order"    },
   { "DT_RX",   "regular expression" },
   { "DT_MAGIC",        "folder magic" },
   { "DT_SYN",  NULL },
   { "DT_ADDR", "e-mail address" },
+  { "DT_MBCHARTBL", "string"   },
   { NULL, NULL }
 };
     
 
 static int buff2type (const char *s)
 {
   int type;
   
@@ -515,16 +517,17 @@
       strncpy (t, s + 5, l);
       for (; *t; t++) *t = tolower ((unsigned char) *t);
       break;
     }
     case DT_STR:
     case DT_RX:
     case DT_ADDR:
     case DT_PATH:
+    case DT_MBCHARTBL:
     {
       if (!strcmp (s, "0"))
        break;
       /* fallthrough */
     }
     default:
     {
       strncpy (t, s, l);
@@ -653,28 +656,30 @@
 {
   if (type == DT_SYN) return;
   
   switch (OutputFormat)
   {
     /* 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);
        fputs ("\"", out);
       }
       else if (type != DT_SYN)
        fprintf (out, "\n# set %s=%s", varname, val);
       
       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);
        fputs ("\"", out);
       }
       else
        fprintf (out, "\n# Default: %s", val);
 
@@ -683,17 +688,18 @@
     }
 
     /* manual page */
     case F_MAN:
     {
       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);
        fputs ("\\(rq\n", out);
       }
       else {
        fputs ("Default: ", out);
        man_print_strval (val, out);
@@ -710,17 +716,18 @@
     {
       fputs ("\n<sect2 id=\"", out);
       sgml_id_fputs(varname, out);
       fputs ("\">\n<title>", out);
       sgml_fputs (varname, out);
       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)
        {
          fputs ("\nDefault: <quote><literal>", out);
          sgml_print_strval (val, out);
          fputs ("</literal></quote>", out);
        }
        else
diff --git a/init.c b/init.c
--- a/init.c
+++ b/init.c
@@ -598,16 +598,69 @@
       {
        last = p;
        p = p->next;
       }
     }
   }
 }
 
+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 (char *s)
+{
+  mbchar_table *t;
+  size_t slen, k;
+  mbstate_t mbstate;
+  wchar_t wc;
+  char *d;
+
+  t = safe_calloc (1, sizeof (mbchar_table));
+  slen = mutt_strlen (s);
+  if (!slen)
+    return t;
+
+  t->orig_str = safe_strdup (s);
+  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 (&wc, s, slen, &mbstate);
+    if (k == 0 || k == (size_t)(-2))
+      break;
+    if (k == (size_t)(-1))
+    {
+      memset (&mbstate, 0, sizeof (mbstate));
+      k = 1;
+    }
+
+    t->chars[t->len++] = d;
+    while (k > 0)
+    {
+      *d++ = *s++;
+      k--;
+      slen--;
+    }
+    *d++ = '\0';
+  }
+
+  return t;
+}
+
 static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER 
*err)
 {
   do
   {
     mutt_extract_token (buf, s, 0);
 
     /* don't add "*" to the unignore list */
     if (strcmp (buf->data, "*")) 
@@ -1530,16 +1583,20 @@
 
 static void mutt_restore_default (struct option_t *p)
 {
   switch (p->type & DT_MASK)
   {
     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)
       {
        char path[_POSIX_PATH_MAX];
        strfcpy (path, (char *) p->init, sizeof (path));
        mutt_expand_path (path, sizeof (path));
        *((char **) p->data) = safe_strdup (path);
@@ -1951,25 +2008,28 @@
        unset_option (MuttVars[idx].data);
       else if (inv)
        toggle_option (MuttVars[idx].data);
       else
        set_option (MuttVars[idx].data);
     }
     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)
       {
        CHECK_PAGER;
         if (myvar)
           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 */
          FREE ((void *) MuttVars[idx].data);           /* __FREE_CHECKED__ */
       }
       else if (query || *s->dptr != '=')
       {
        char _tmp[LONG_STRING];
@@ -1996,16 +2056,21 @@
        }
        else if (DTYPE (MuttVars[idx].type) == DT_PATH)
        {
          _tmp[0] = '\0';
          strfcpy (_tmp, NONULL(*((char **) MuttVars[idx].data)), sizeof 
(_tmp));
          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);
        
        /* user requested the value of this variable */
        pretty_var (err->data, err->dsize, MuttVars[idx].option, NONULL(val));
        break;
       }
       else
@@ -2050,16 +2115,21 @@
            return (-1);
          }
 
          FREE ((void *) MuttVars[idx].data);           /* __FREE_CHECKED__ */
          *((char **) MuttVars[idx].data) = safe_strdup (tmp->data);
          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);
          *((ADDRESS **) MuttVars[idx].data) = rfc822_parse_adrlist (NULL, 
tmp->data);
         }
       }
     }
     else if (DTYPE(MuttVars[idx].type) == DT_RX)
@@ -2787,16 +2857,21 @@
   if ((DTYPE(MuttVars[idx].type) == DT_STR) ||
       (DTYPE(MuttVars[idx].type) == DT_PATH) ||
       (DTYPE(MuttVars[idx].type) == DT_RX))
   {
     strfcpy (tmp, NONULL (*((char **) MuttVars[idx].data)), sizeof (tmp));
     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);
   }
   else if (DTYPE (MuttVars[idx].type) == DT_QUAD)
     strfcpy (tmp, vals[quadoption (MuttVars[idx].data)], sizeof (tmp));
   else if (DTYPE (MuttVars[idx].type) == DT_NUM)
   {
diff --git a/init.h b/init.h
--- a/init.h
+++ b/init.h
@@ -33,16 +33,17 @@
 #define DT_STR         3 /* a string */
 #define DT_PATH                4 /* a pathname */
 #define DT_QUAD                5 /* quad-option (yes/no/ask-yes/ask-no) */
 #define DT_SORT                6 /* sorting methods */
 #define DT_RX          7 /* regular expressions */
 #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)
 
 /* subtypes */
 #define DT_SUBTYPE_MASK        0xff0
 #define DT_SORT_ALIAS  0x10
 #define DT_SORT_BROWSER 0x20
 #define DT_SORT_KEYS   0x40
diff --git a/mutt.h b/mutt.h
--- a/mutt.h
+++ b/mutt.h
@@ -1015,16 +1015,25 @@
 typedef struct
 {
   char   *major;
   int     major_int;
   char   *minor;
   regex_t minor_rx;
 } ATTACH_MATCH;
 
+/* for Tochars and StChars option types */
+typedef struct
+{
+  int len;
+  char **chars;
+  char *segmented_str;
+  char *orig_str;
+} mbchar_table;
+
 #define MUTT_PARTS_TOPLEVEL    (1<<0)  /* is the top-level part */
 
 #include "ascii.h"
 #include "protos.h"
 #include "lib.h"
 #include "globals.h"
 
 #endif /*MUTT_H*/

Attachment: signature.asc
Description: PGP signature

Reply via email to