]> granicus.if.org Git - vim/commitdiff
patch 9.0.1283: the code for setting options is too complicated v9.0.1283
authorYegappan Lakshmanan <yegappan@yahoo.com>
Sun, 5 Feb 2023 16:02:35 +0000 (16:02 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 5 Feb 2023 16:02:35 +0000 (16:02 +0000)
Problem:    The code for setting options is too complicated.
Solution:   Refactor the do_set() function. (Yegappan Lakshmanan, Lewis
            Russell, closes #11945)

src/option.c
src/version.c

index 1aed4e1a0d63223720b88026fb95bd50f1c32a86..f22f9f37efc21e34ec0f6a999db523ecb73c2df0 100644 (file)
@@ -1211,6 +1211,9 @@ ex_set(exarg_T *eap)
     }
 }
 
+/*
+ * :set operator types
+ */
 typedef enum {
     OP_NONE = 0,
     OP_ADDING,         // "opt+=arg"
@@ -1218,6 +1221,181 @@ typedef enum {
     OP_REMOVING,       // "opt-=arg"
 } set_op_T;
 
+typedef enum {
+    PREFIX_NO = 0,     // "no" prefix
+    PREFIX_NONE,       // no prefix
+    PREFIX_INV,                // "inv" prefix
+} set_prefix_T;
+
+/*
+ * Return the prefix type for the option name in *argp.
+ */
+    static set_prefix_T
+get_option_prefix(char_u **argp)
+{
+    int                prefix = PREFIX_NONE;
+    char_u     *arg = *argp;
+
+    if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
+    {
+       prefix = PREFIX_NO;
+       arg += 2;
+    }
+    else if (STRNCMP(arg, "inv", 3) == 0)
+    {
+       prefix = PREFIX_INV;
+       arg += 3;
+    }
+
+    *argp = arg;
+    return prefix;
+}
+
+/*
+ * Parse the option name in "arg" and return the option index in "*opt_idxp",
+ * and the option name length in "*lenp".  For a <t_xx> option, return the key
+ * number in "*keyp".
+ *
+ * Returns FAIL if an option starting with "<" doesn't end with a ">",
+ * otherwise returns OK.
+ */
+    static int
+parse_option_name(char_u *arg, int *opt_idxp, int *lenp, int *keyp)
+{
+    int        key = 0;
+    int        len;
+    int        opt_idx;
+
+    if (*arg == '<')
+    {
+       opt_idx = -1;
+       // look out for <t_>;>
+       if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
+           len = 5;
+       else
+       {
+           len = 1;
+           while (arg[len] != NUL && arg[len] != '>')
+               ++len;
+       }
+       if (arg[len] != '>')
+           return FAIL;
+
+       arg[len] = NUL;                     // put NUL after name
+       if (arg[1] == 't' && arg[2] == '_') // could be term code
+           opt_idx = findoption(arg + 1);
+       arg[len++] = '>';                   // restore '>'
+       if (opt_idx == -1)
+           key = find_key_option(arg + 1, TRUE);
+    }
+    else
+    {
+       int     nextchar;   // next non-white char after option name
+
+       len = 0;
+       /*
+        * The two characters after "t_" may not be alphanumeric.
+        */
+       if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+           len = 4;
+       else
+           while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
+               ++len;
+       nextchar = arg[len];
+       arg[len] = NUL;                     // put NUL after name
+       opt_idx = findoption(arg);
+       arg[len] = nextchar;                // restore nextchar
+       if (opt_idx == -1)
+           key = find_key_option(arg, FALSE);
+    }
+
+    *keyp = key;
+    *lenp = len;
+    *opt_idxp = opt_idx;
+
+    return OK;
+}
+
+/*
+ * Get the option operator (+=, ^=, -=).
+ */
+    static set_op_T
+get_opt_op(char_u *arg)
+{
+    set_op_T op = OP_NONE;
+
+    if (*arg != NUL && *(arg + 1) == '=')
+    {
+       if (*arg == '+')
+           op = OP_ADDING;             // "+="
+       else if (*arg == '^')
+           op = OP_PREPENDING;         // "^="
+       else if (*arg == '-')
+           op = OP_REMOVING;           // "-="
+    }
+
+    return op;
+}
+
+/*
+ * Validate whether the value of the option in "opt_idx" can be changed.
+ * Returns FAIL if the option can be skipped or cannot be changed. Returns OK
+ * if it can be changed.
+ */
+    static int
+validate_opt_idx(int opt_idx, int opt_flags, long_u flags, char **errmsg)
+{
+    // Skip all options that are not window-local (used when showing
+    // an already loaded buffer in a window).
+    if ((opt_flags & OPT_WINONLY)
+           && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
+       return FAIL;
+
+    // Skip all options that are window-local (used for :vimgrep).
+    if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
+           && options[opt_idx].var == VAR_WIN)
+       return FAIL;
+
+    // Disallow changing some options from modelines.
+    if (opt_flags & OPT_MODELINE)
+    {
+       if (flags & (P_SECURE | P_NO_ML))
+       {
+           *errmsg = e_not_allowed_in_modeline;
+           return FAIL;
+       }
+       if ((flags & P_MLE) && !p_mle)
+       {
+           *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
+           return FAIL;
+       }
+#ifdef FEAT_DIFF
+       // In diff mode some options are overruled.  This avoids that
+       // 'foldmethod' becomes "marker" instead of "diff" and that
+       // "wrap" gets set.
+       if (curwin->w_p_diff
+               && opt_idx >= 0  // shut up coverity warning
+               && (
+# ifdef FEAT_FOLDING
+                   options[opt_idx].indir == PV_FDM ||
+# endif
+                   options[opt_idx].indir == PV_WRAP))
+           return FAIL;
+#endif
+    }
+
+#ifdef HAVE_SANDBOX
+    // Disallow changing some options in the sandbox
+    if (sandbox != 0 && (flags & P_SECURE))
+    {
+       *errmsg = e_not_allowed_in_sandbox;
+       return FAIL;
+    }
+#endif
+
+    return OK;
+}
+
 /*
  * Part of do_set() for string options.
  * Returns FAIL on failure, do not process further options.
@@ -1636,95 +1814,301 @@ do_set_string(
     return *errmsg == NULL ? OK : FAIL;
 }
 
+/*
+ * Set a boolean option
+ */
+    static char *
+do_set_option_bool(
+    int                opt_idx,
+    int                opt_flags,
+    set_prefix_T prefix,
+    long_u     flags,
+    char_u     *varp,
+    int                nextchar,
+    int                afterchar,
+    int                cp_val)
+
+{
+    varnumber_T        value;
+
+    if (nextchar == '=' || nextchar == ':')
+       return e_invalid_argument;
+
+    /*
+     * ":set opt!": invert
+     * ":set opt&": reset to default value
+     * ":set opt<": reset to global value
+     */
+    if (nextchar == '!')
+       value = *(int *)(varp) ^ 1;
+    else if (nextchar == '&')
+       value = (int)(long)(long_i)options[opt_idx].def_val[
+           ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
+    else if (nextchar == '<')
+    {
+       // For 'autoread' -1 means to use global value.
+       if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL)
+           value = -1;
+       else
+           value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+    }
+    else
+    {
+       /*
+        * ":set invopt": invert
+        * ":set opt" or ":set noopt": set or reset
+        */
+       if (nextchar != NUL && !VIM_ISWHITE(afterchar))
+           return e_trailing_characters;
+       if (prefix == PREFIX_INV)
+           value = *(int *)(varp) ^ 1;
+       else
+           value = prefix == PREFIX_NO ? 0 : 1;
+    }
+
+    return set_bool_option(opt_idx, varp, (int)value, opt_flags);
+}
+
+/*
+ * Set a numeric option
+ */
+    static char *
+do_set_option_numeric(
+    int                opt_idx,
+    int                opt_flags,
+    char_u     **argp,
+    int                nextchar,
+    set_op_T   op,
+    long_u     flags,
+    int                cp_val,
+    char_u     *varp,
+    char       *errbuf,
+    size_t     errbuflen)
+{
+    char_u             *arg = *argp;
+    varnumber_T                value;
+    int                        i;
+    char               *errmsg = NULL;
+
+    /*
+     * Different ways to set a number option:
+     * &           set to default value
+     * <           set to global value
+     * <xx>        accept special key codes for 'wildchar'
+     * c           accept any non-digit for 'wildchar'
+     * [-]0-9   set number
+     * other    error
+     */
+    ++arg;
+    if (nextchar == '&')
+       value = (long)(long_i)options[opt_idx].def_val[
+           ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
+    else if (nextchar == '<')
+    {
+       // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
+       // use the global value.
+       if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL)
+           value = NO_LOCAL_UNDOLEVEL;
+       else
+           value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+    }
+    else if (((long *)varp == &p_wc || (long *)varp == &p_wcm)
+           && (*arg == '<'
+               || *arg == '^'
+               || (*arg != NUL
+                   && (!arg[1] || VIM_ISWHITE(arg[1]))
+                   && !VIM_ISDIGIT(*arg))))
+    {
+       value = string_to_key(arg, FALSE);
+       if (value == 0 && (long *)varp != &p_wcm)
+       {
+           errmsg = e_invalid_argument;
+           goto skip;
+       }
+    }
+    else if (*arg == '-' || VIM_ISDIGIT(*arg))
+    {
+       // Allow negative (for 'undolevels'), octal and hex numbers.
+       vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE);
+       if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
+       {
+           errmsg = e_number_required_after_equal;
+           goto skip;
+       }
+    }
+    else
+    {
+       errmsg = e_number_required_after_equal;
+       goto skip;
+    }
+
+    if (op == OP_ADDING)
+       value = *(long *)varp + value;
+    else if (op == OP_PREPENDING)
+       value = *(long *)varp * value;
+    else if (op == OP_REMOVING)
+       value = *(long *)varp - value;
+
+    errmsg = set_num_option(opt_idx, varp, value, errbuf, errbuflen,
+                                                               opt_flags);
+
+skip:
+    *argp = arg;
+    return errmsg;
+}
+
+/*
+ * Set a key code (t_xx) option
+ */
+    static char *
+do_set_option_keycode(char_u **argp, char_u *key_name, int nextchar)
+{
+    char_u     *arg = *argp;
+    char_u     *p;
+
+    if (nextchar == '&')
+    {
+       if (add_termcap_entry(key_name, TRUE) == FAIL)
+           return e_not_found_in_termcap;
+    }
+    else
+    {
+       ++arg; // jump to after the '=' or ':'
+       for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
+           if (*p == '\\' && p[1] != NUL)
+               ++p;
+       nextchar = *p;
+       *p = NUL;
+       add_termcode(key_name, arg, FALSE);
+       *p = nextchar;
+    }
+    if (full_screen)
+       ttest(FALSE);
+    redraw_all_later(UPD_CLEAR);
+
+    *argp = arg;
+    return NULL;
+}
+
 /*
  * Set an option to a new value.
- * Return NULL if OK, return an untranslated error message when something is
- * wrong.  "errbuf[errbuflen]" can be used to create the error message.
  */
     static char *
-do_set_option(
+do_set_option_value(
+    int                opt_idx,
     int                opt_flags,
     char_u     **argp,
-    char_u     *arg_start,
-    char_u     **startarg,
-    int                *did_show,
+    set_prefix_T prefix,
+    set_op_T   op,
+    long_u     flags,
+    char_u     *varp,
+    char_u     *key_name,
+    int                nextchar,
+    int                afterchar,
+    int                cp_val,
     int                *stopopteval,
     char       *errbuf,
     size_t     errbuflen)
 {
+    int                value_checked = FALSE;
     char       *errmsg = NULL;
-    int                prefix;     // 1: nothing, 0: "no", 2: "inv" in front of name
-    int                nextchar;   // next non-white char after option name
-    int                afterchar;  // character just after option name
     char_u     *arg = *argp;
-    int                key;
-    int                opt_idx;
-    int                len;
-    set_op_T   op = 0;
-    long_u     flags;              // flags for current option
-    char_u     *varp = NULL;       // pointer to variable for current option
-    char_u     key_name[2];
-    int                cp_val = 0;
-    varnumber_T        value;
-    int                i;
 
-    prefix = 1;
-    if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
+    if (flags & P_BOOL)
     {
-       prefix = 0;
-       arg += 2;
+       // boolean option
+       errmsg = do_set_option_bool(opt_idx, opt_flags, prefix, flags, varp,
+                                               nextchar, afterchar, cp_val);
+       if (errmsg != NULL)
+           goto skip;
     }
-    else if (STRNCMP(arg, "inv", 3) == 0)
+    else
     {
-       prefix = 2;
-       arg += 3;
-    }
+       // numeric or string option
+       if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
+               || prefix != PREFIX_NONE)
+       {
+           errmsg = e_invalid_argument;
+           goto skip;
+       }
 
-    // find end of name
-    key = 0;
-    if (*arg == '<')
-    {
-       opt_idx = -1;
-       // look out for <t_>;>
-       if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
-           len = 5;
-       else
+       if (flags & P_NUM)
        {
-           len = 1;
-           while (arg[len] != NUL && arg[len] != '>')
-               ++len;
+           // numeric option
+           errmsg = do_set_option_numeric(opt_idx, opt_flags, &arg, nextchar,
+                                               op, flags, cp_val, varp,
+                                               errbuf, errbuflen);
+           if (errmsg != NULL)
+               goto skip;
        }
-       if (arg[len] != '>')
+       else if (opt_idx >= 0)
        {
-           errmsg = e_invalid_argument;
-           goto skip;
+           // string option
+           if (do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags,
+                                   cp_val, varp, errbuf, &value_checked,
+                                   &errmsg) == FAIL)
+           {
+               if (errmsg != NULL)
+                   goto skip;
+               *stopopteval = TRUE;
+               goto skip;
+           }
        }
-       arg[len] = NUL;                     // put NUL after name
-       if (arg[1] == 't' && arg[2] == '_') // could be term code
-           opt_idx = findoption(arg + 1);
-       arg[len++] = '>';                   // restore '>'
-       if (opt_idx == -1)
-           key = find_key_option(arg + 1, TRUE);
-    }
-    else
-    {
-       len = 0;
-       /*
-        * The two characters after "t_" may not be alphanumeric.
-        */
-       if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
-           len = 4;
        else
-           while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
-               ++len;
-       nextchar = arg[len];
-       arg[len] = NUL;                     // put NUL after name
-       opt_idx = findoption(arg);
-       arg[len] = nextchar;                // restore nextchar
-       if (opt_idx == -1)
-           key = find_key_option(arg, FALSE);
+       {
+           // key code option
+           errmsg = do_set_option_keycode(&arg, key_name, nextchar);
+           if (errmsg != NULL)
+               goto skip;
+       }
     }
 
+    if (opt_idx >= 0)
+       did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
+
+skip:
+    *argp = arg;
+    return errmsg;
+}
+
+/*
+ * Set an option to a new value.
+ * Return NULL if OK, return an untranslated error message when something is
+ * wrong.  "errbuf[errbuflen]" can be used to create the error message.
+ */
+    static char *
+do_set_option(
+    int                opt_flags,
+    char_u     **argp,
+    char_u     *arg_start,
+    char_u     **startarg,
+    int                *did_show,
+    int                *stopopteval,
+    char       *errbuf,
+    size_t     errbuflen)
+{
+    int                opt_idx;
+    char_u     *arg;
+    set_prefix_T prefix;       // no prefix, "no" prefix or "inv" prefix
+    set_op_T   op;
+    long_u     flags;          // flags for current option
+    char_u     *varp;          // pointer to variable for current option
+    char_u     key_name[2];
+    int                nextchar;       // next non-white char after option name
+    int                afterchar;      // character just after option name
+    int                cp_val;
+    char       *errmsg = NULL;
+    int                key;
+    int                len;
+
+    prefix = get_option_prefix(argp);
+    arg = *argp;
+
+    // find end of name
+    key = 0;
+    if (parse_option_name(arg, &opt_idx, &len, &key) == FAIL)
+       return e_invalid_argument;
+
     // remember character after option name
     afterchar = arg[len];
 
@@ -1748,25 +2132,10 @@ do_set_option(
        while (VIM_ISWHITE(arg[len]))
            ++len;
 
-    op = OP_NONE;
-    if (arg[len] != NUL && arg[len + 1] == '=')
-    {
-       if (arg[len] == '+')
-       {
-           op = OP_ADDING;             // "+="
-           ++len;
-       }
-       else if (arg[len] == '^')
-       {
-           op = OP_PREPENDING;         // "^="
-           ++len;
-       }
-       else if (arg[len] == '-')
-       {
-           op = OP_REMOVING;           // "-="
-           ++len;
-       }
-    }
+    op = get_opt_op(arg + len);
+    if (op != OP_NONE)
+       len++;
+
     nextchar = arg[len];
 
     if (opt_idx == -1 && key == 0)     // found a mismatch: skip
@@ -1810,54 +2179,10 @@ do_set_option(
        }
     }
 
-    // Skip all options that are not window-local (used when showing
-    // an already loaded buffer in a window).
-    if ((opt_flags & OPT_WINONLY)
-           && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
-       goto skip;
-
-    // Skip all options that are window-local (used for :vimgrep).
-    if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
-           && options[opt_idx].var == VAR_WIN)
+    // Make sure the option value can be changed.
+    if (validate_opt_idx(opt_idx, opt_flags, flags, &errmsg) == FAIL)
        goto skip;
 
-    // Disallow changing some options from modelines.
-    if (opt_flags & OPT_MODELINE)
-    {
-       if (flags & (P_SECURE | P_NO_ML))
-       {
-           errmsg = e_not_allowed_in_modeline;
-           goto skip;
-       }
-       if ((flags & P_MLE) && !p_mle)
-       {
-           errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
-           goto skip;
-       }
-#ifdef FEAT_DIFF
-       // In diff mode some options are overruled.  This avoids that
-       // 'foldmethod' becomes "marker" instead of "diff" and that
-       // "wrap" gets set.
-       if (curwin->w_p_diff
-               && opt_idx >= 0  // shut up coverity warning
-               && (
-#ifdef FEAT_FOLDING
-                   options[opt_idx].indir == PV_FDM ||
-#endif
-                   options[opt_idx].indir == PV_WRAP))
-           goto skip;
-#endif
-    }
-
-#ifdef HAVE_SANDBOX
-    // Disallow changing some options in the sandbox
-    if (sandbox != 0 && (flags & P_SECURE))
-    {
-       errmsg = e_not_allowed_in_sandbox;
-       goto skip;
-    }
-#endif
-
     if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
     {
        arg += len;
@@ -1888,7 +2213,7 @@ do_set_option(
      * allows only one '=' character per "set" command line. grrr. (jw)
      */
     if (nextchar == '?'
-           || (prefix == 1
+           || (prefix == PREFIX_NONE
                && vim_strchr((char_u *)"=:&<", nextchar) == NULL
                && !(flags & P_BOOL)))
     {
@@ -1939,177 +2264,10 @@ do_set_option(
     }
     else
     {
-       int value_checked = FALSE;
-
-       if (flags & P_BOOL)                 // boolean
-       {
-           if (nextchar == '=' || nextchar == ':')
-           {
-               errmsg = e_invalid_argument;
-               goto skip;
-           }
-
-           /*
-            * ":set opt!": invert
-            * ":set opt&": reset to default value
-            * ":set opt<": reset to global value
-            */
-           if (nextchar == '!')
-               value = *(int *)(varp) ^ 1;
-           else if (nextchar == '&')
-               value = (int)(long)(long_i)options[opt_idx].def_val[
-                   ((flags & P_VI_DEF) || cp_val)
-                       ?  VI_DEFAULT : VIM_DEFAULT];
-           else if (nextchar == '<')
-           {
-               // For 'autoread' -1 means to use global value.
-               if ((int *)varp == &curbuf->b_p_ar
-                       && opt_flags == OPT_LOCAL)
-                   value = -1;
-               else
-                   value = *(int *)get_varp_scope(&(options[opt_idx]),
-                           OPT_GLOBAL);
-           }
-           else
-           {
-               /*
-                * ":set invopt": invert
-                * ":set opt" or ":set noopt": set or reset
-                */
-               if (nextchar != NUL && !VIM_ISWHITE(afterchar))
-               {
-                   errmsg = e_trailing_characters;
-                   goto skip;
-               }
-               if (prefix == 2)        // inv
-                   value = *(int *)(varp) ^ 1;
-               else
-                   value = prefix;
-           }
-
-           errmsg = set_bool_option(opt_idx, varp, (int)value,
-                   opt_flags);
-       }
-       else                                // numeric or string
-       {
-           if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
-                   || prefix != 1)
-           {
-               errmsg = e_invalid_argument;
-               goto skip;
-           }
-
-           if (flags & P_NUM)              // numeric
-           {
-               /*
-                * Different ways to set a number option:
-                * &        set to default value
-                * <        set to global value
-                * <xx>     accept special key codes for 'wildchar'
-                * c        accept any non-digit for 'wildchar'
-                * [-]0-9   set number
-                * other    error
-                */
-               ++arg;
-               if (nextchar == '&')
-                   value = (long)(long_i)options[opt_idx].def_val[
-                       ((flags & P_VI_DEF) || cp_val)
-                           ?  VI_DEFAULT : VIM_DEFAULT];
-               else if (nextchar == '<')
-               {
-                   // For 'undolevels' NO_LOCAL_UNDOLEVEL means to
-                   // use the global value.
-                   if ((long *)varp == &curbuf->b_p_ul
-                           && opt_flags == OPT_LOCAL)
-                       value = NO_LOCAL_UNDOLEVEL;
-                   else
-                       value = *(long *)get_varp_scope(
-                               &(options[opt_idx]), OPT_GLOBAL);
-               }
-               else if (((long *)varp == &p_wc
-                           || (long *)varp == &p_wcm)
-                       && (*arg == '<'
-                           || *arg == '^'
-                           || (*arg != NUL
-                               && (!arg[1] || VIM_ISWHITE(arg[1]))
-                               && !VIM_ISDIGIT(*arg))))
-               {
-                   value = string_to_key(arg, FALSE);
-                   if (value == 0 && (long *)varp != &p_wcm)
-                   {
-                       errmsg = e_invalid_argument;
-                       goto skip;
-                   }
-               }
-               else if (*arg == '-' || VIM_ISDIGIT(*arg))
-               {
-                   // Allow negative (for 'undolevels'), octal and
-                   // hex numbers.
-                   vim_str2nr(arg, NULL, &i, STR2NR_ALL,
-                           &value, NULL, 0, TRUE);
-                   if (i == 0 || (arg[i] != NUL
-                               && !VIM_ISWHITE(arg[i])))
-                   {
-                       errmsg = e_number_required_after_equal;
-                       goto skip;
-                   }
-               }
-               else
-               {
-                   errmsg = e_number_required_after_equal;
-                   goto skip;
-               }
-
-               if (op == OP_ADDING)
-                   value = *(long *)varp + value;
-               else if (op == OP_PREPENDING)
-                   value = *(long *)varp * value;
-               else if (op == OP_REMOVING)
-                   value = *(long *)varp - value;
-               errmsg = set_num_option(opt_idx, varp, value,
-                       errbuf, errbuflen, opt_flags);
-           }
-           else if (opt_idx >= 0)                  // string
-           {
-               if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
-                           op, flags, cp_val, varp, errbuf,
-                           &value_checked, &errmsg) == FAIL)
-               {
-                   if (errmsg != NULL)
-                       goto skip;
-                   *stopopteval = TRUE;
-                   goto skip;
-               }
-           }
-           else            // key code option
-           {
-               char_u      *p;
-
-               if (nextchar == '&')
-               {
-                   if (add_termcap_entry(key_name, TRUE) == FAIL)
-                       errmsg = e_not_found_in_termcap;
-               }
-               else
-               {
-                   ++arg; // jump to after the '=' or ':'
-                   for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
-                       if (*p == '\\' && p[1] != NUL)
-                           ++p;
-                   nextchar = *p;
-                   *p = NUL;
-                   add_termcode(key_name, arg, FALSE);
-                   *p = nextchar;
-               }
-               if (full_screen)
-                   ttest(FALSE);
-               redraw_all_later(UPD_CLEAR);
-           }
-       }
-
-       if (opt_idx >= 0)
-           did_set_option(
-                   opt_idx, opt_flags, op == OP_NONE, value_checked);
+       errmsg = do_set_option_value(opt_idx, opt_flags, &arg, prefix, op,
+                                       flags, varp, key_name, nextchar,
+                                       afterchar, cp_val, stopopteval, errbuf,
+                                       errbuflen);
     }
 
 skip:
index 2f5e3bffa57f438effc57c0cea9f0699a27288ec..fb8795b160bc8e465823781e9e23846eb209309c 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1283,
 /**/
     1282,
 /**/