Commit 3d18f19c authored by Kevin J. McCarthy's avatar Kevin J. McCarthy

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.
parent ddc6b385
......@@ -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)
{
......
......@@ -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);
......
......@@ -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)
......
......@@ -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"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment