+/* protos for config type handles: convert value to string */
+static void bool_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void num_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void str_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void quad_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void sort_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void rx_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void magic_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+static void addr_to_string (char* dst, ssize_t dstlen, struct option_t* option);
+
+/* protos for config type handles: convert to value from string */
+static int bool_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int num_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int str_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int path_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int quad_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int sort_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int rx_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int magic_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+static int addr_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+
+static struct {
+ unsigned short type;
+ void (*opt_tostr) (char* dst, ssize_t dstlen, struct option_t* option);
+ int (*opt_fromstr) (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen);
+} FuncTable[] = {
+ { 0, NULL, NULL }, /* there's no DT_ type with 0 */
+ { DT_BOOL, bool_to_string, bool_from_string },
+ { DT_NUM, num_to_string, num_from_string },
+ { DT_STR, str_to_string, str_from_string },
+ { DT_PATH, str_to_string, path_from_string },
+ { DT_QUAD, quad_to_string, quad_from_string },
+ { DT_SORT, sort_to_string, sort_from_string },
+ { DT_RX, rx_to_string, rx_from_string },
+ { DT_MAGIC, magic_to_string, magic_from_string },
+ /* synonyms should be resolved already so we don't need this
+ * but must define it as DT_ is used for indexing */
+ { DT_SYN, NULL, NULL },
+ { DT_ADDR, addr_to_string, addr_from_string },
+};
+
+static void bool_to_string (char* dst, ssize_t dstlen,
+ struct option_t* option) {
+ snprintf (dst, dstlen, "%s=%s", option->option,
+ option (option->data) ? "yes" : "no");
+}
+
+static int bool_from_string (struct option_t* dst, const char* val,
+ char* errbuf __attribute__ ((unused)),
+ ssize_t errlen __attribute__ ((unused))) {
+ int flag = -1;
+
+ if (!dst)
+ return (0);
+ if (ascii_strncasecmp (val, "yes", 3) == 0)
+ flag = 1;
+ else if (ascii_strncasecmp (val, "no", 2) == 0)
+ flag = 0;
+
+ if (flag < 0)
+ return (0);
+ if (flag)
+ set_option (dst->data);
+ else
+ unset_option (dst->data);
+ return (1);
+}
+
+static void num_to_string (char* dst, ssize_t dstlen,
+ struct option_t* option) {
+ /* XXX puke */
+ const char* fmt = (m_strcmp(option->option, "umask") == 0) ?
+ "%s=%04o" : "%s=%d";
+ snprintf (dst, dstlen, fmt, option->option,
+ *((short*) option->data));
+}
+
+static int num_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen) {
+ int num = 0, old = 0;
+ char* t = NULL;
+
+ if (!dst)
+ return (0);
+
+ num = strtol (val, &t, 0);
+
+ if (m_strisempty(val) || *t || (short) num != num) {
+ if (errbuf) {
+ snprintf (errbuf, errlen, _("'%s' is invalid for $%s"),
+ val, dst->option);
+ }
+ return (0);
+ }
+
+ /* just temporarily accept new val so that check_special for
+ * $history already has it when doing history's init() */
+ old = *((short*) dst->data);
+ *((short*) dst->data) = (short) num;
+
+ if (!check_special (dst->option, (unsigned long) num, errbuf, errlen)) {
+ *((short*) dst->data) = old;
+ return (0);
+ }
+
+ return (1);
+}
+
+static void str_to_string (char* dst, ssize_t dstlen,
+ struct option_t* option) {
+ snprintf (dst, dstlen, "%s=\"%s\"", option->option,
+ NONULL (*((char**) option->data)));
+}
+
+static int path_from_string (struct option_t* dst, const char* val,
+ char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
+ char path[_POSIX_PATH_MAX];
+
+ if (!dst)
+ return (0);
+
+ if (m_strisempty(val)) {
+ p_delete((char**) dst->data);
+ return (1);
+ }
+
+ path[0] = '\0';
+ m_strcpy(path, sizeof(path), val);
+ mutt_expand_path (path, sizeof(path));
+ m_strreplace((char **) dst->data, path);
+ return (1);
+}
+
+static int str_from_string (struct option_t* dst, const char* val,
+ char* errbuf, ssize_t errlen) {
+ if (!dst)
+ return (0);
+
+ if (!check_special (dst->option, (unsigned long) val, errbuf, errlen))
+ return (0);
+
+ m_strreplace((char**) dst->data, val);
+ return (1);
+}
+
+static void quad_to_string (char* dst, ssize_t dstlen,
+ struct option_t* option) {
+ const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
+ snprintf (dst, dstlen, "%s=%s", option->option,
+ vals[quadoption (option->data)]);
+}
+
+static int quad_from_string (struct option_t* dst, const char* val,
+ char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
+ int flag = -1;
+
+ if (!dst)
+ return (0);
+ if (ascii_strncasecmp (val, "yes", 3) == 0)
+ flag = M_YES;
+ else if (ascii_strncasecmp (val, "no", 2) == 0)
+ flag = M_NO;
+ else if (ascii_strncasecmp (val, "ask-yes", 7) == 0)
+ flag = M_ASKYES;
+ else if (ascii_strncasecmp (val, "ask-no", 6) == 0)
+ flag = M_ASKNO;
+
+ if (flag < 0)
+ return (0);
+
+ set_quadoption (dst->data, flag);
+ return (1);
+}
+
+static void sort_to_string (char* dst, ssize_t dstlen,
+ struct option_t* option) {
+ const struct mapping_t *map = get_sortmap (option);
+ const char *p = NULL;
+
+ if (!map) {
+ snprintf (dst, sizeof(dst), "%s=unknown", option->option);
+ return;
+ }
+
+ p = mutt_getnamebyvalue(*((short *)option->data) & SORT_MASK, map);
+
+ snprintf (dst, dstlen, "%s=%s%s%s", option->option,
+ (*((short *) option->data) & SORT_REVERSE) ?
+ "reverse-" : "",
+ (*((short *) option->data) & SORT_LAST) ? "last-" :
+ "", NONULL (p));