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; }