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*/
signature.asc
Description: PGP signature