changeset 30403:42d592459521 v9.0.0537

patch 9.0.0537: the do_set() function is much too long Commit: https://github.com/vim/vim/commit/4740394f230dda09d6e9337465305741d8ee4fa3 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 21 21:12:53 2022 +0100 patch 9.0.0537: the do_set() function is much too long Problem: The do_set() function is much too long. Solution: Move setting of a string option to a separate function.
author Bram Moolenaar <Bram@vim.org>
date Wed, 21 Sep 2022 22:15:02 +0200
parents 7895185398c4
children 20bbd0c0761b
files src/option.c src/version.c
diffstat 2 files changed, 442 insertions(+), 435 deletions(-) [+]
line wrap: on
line diff
--- a/src/option.c
+++ b/src/option.c
@@ -1205,6 +1205,431 @@ ex_set(exarg_T *eap)
     }
 }
 
+typedef enum {
+    OP_NONE = 0,
+    OP_ADDING,		// "opt+=arg"
+    OP_PREPENDING,	// "opt^=arg"
+    OP_REMOVING,	// "opt-=arg"
+} set_op_T;
+
+/*
+ * Part of do_set() for string options.
+ * Returns FAIL on failure, do not process further options.
+ */
+    static int
+do_set_string(
+	int	    opt_idx,
+	int	    opt_flags,
+	char_u	    **arg,
+	int	    nextchar,
+	set_op_T    op_arg,
+	int	    flags,
+	int	    cp_val,
+	char_u	    *varp_arg,
+	char	    *errbuf,
+	int	    *value_checked,
+	char	    **errmsg)
+{
+    set_op_T    op = op_arg;
+    char_u	*varp = varp_arg;
+    char_u	*save_arg = NULL;
+    char_u	*s = NULL;
+    char_u	*oldval = NULL; // previous value if *varp
+    char_u	*newval;
+    char_u	*origval = NULL;
+    char_u	*origval_l = NULL;
+    char_u	*origval_g = NULL;
+#if defined(FEAT_EVAL)
+    char_u	*saved_origval = NULL;
+    char_u	*saved_origval_l = NULL;
+    char_u	*saved_origval_g = NULL;
+    char_u	*saved_newval = NULL;
+#endif
+    unsigned	newlen;
+    int		comma;
+    char_u	whichwrap[80];
+
+    // When using ":set opt=val" for a global option
+    // with a local value the local value will be
+    // reset, use the global value here.
+    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+	    && ((int)options[opt_idx].indir & PV_BOTH))
+	varp = options[opt_idx].var;
+
+    // The old value is kept until we are sure that the new value is valid.
+    oldval = *(char_u **)varp;
+
+    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+    {
+	origval_l = *(char_u **)get_varp_scope(
+			   &(options[opt_idx]), OPT_LOCAL);
+	origval_g = *(char_u **)get_varp_scope(
+			  &(options[opt_idx]), OPT_GLOBAL);
+
+	// A global-local string option might have an empty option as value to
+	// indicate that the global value should be used.
+	if (((int)options[opt_idx].indir & PV_BOTH)
+						  && origval_l == empty_option)
+	    origval_l = origval_g;
+    }
+
+    // When setting the local value of a global option, the old value may be
+    // the global value.
+    if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL))
+	origval = *(char_u **)get_varp(&options[opt_idx]);
+    else
+	origval = oldval;
+
+    if (nextchar == '&')	// set to default val
+    {
+	newval = options[opt_idx].def_val[((flags & P_VI_DEF) || cp_val)
+						   ? VI_DEFAULT : VIM_DEFAULT];
+	if ((char_u **)varp == &p_bg)
+	{
+	    // guess the value of 'background'
+#ifdef FEAT_GUI
+	    if (gui.in_use)
+		newval = gui_bg_default();
+	    else
+#endif
+		newval = term_bg_default();
+	}
+	else if ((char_u **)varp == &p_fencs && enc_utf8)
+	    newval = fencs_utf8_default;
+
+	// expand environment variables and ~ since the default value was
+	// already expanded, only required when an environment variable was set
+	// later
+	if (newval == NULL)
+	    newval = empty_option;
+	else
+	{
+	    s = option_expand(opt_idx, newval);
+	    if (s == NULL)
+		s = newval;
+	    newval = vim_strsave(s);
+	}
+    }
+    else if (nextchar == '<')	// set to global val
+    {
+	newval = vim_strsave(*(char_u **)get_varp_scope(
+					     &(options[opt_idx]), OPT_GLOBAL));
+    }
+    else
+    {
+	++*arg;	// jump to after the '=' or ':'
+
+	/*
+	 * Set 'keywordprg' to ":help" if an empty
+	 * value was passed to :set by the user.
+	 * Misuse errbuf[] for the resulting string.
+	 */
+	if (varp == (char_u *)&p_kp && (**arg == NUL || **arg == ' '))
+	{
+	    STRCPY(errbuf, ":help");
+	    save_arg = *arg;
+	    *arg = (char_u *)errbuf;
+	}
+	/*
+	 * Convert 'backspace' number to string, for
+	 * adding, prepending and removing string.
+	 */
+	else if (varp == (char_u *)&p_bs && VIM_ISDIGIT(**(char_u **)varp))
+	{
+	    int i = getdigits((char_u **)varp);
+
+	    switch (i)
+	    {
+		case 0:
+		    *(char_u **)varp = empty_option;
+		    break;
+		case 1:
+		    *(char_u **)varp = vim_strsave((char_u *)"indent,eol");
+		    break;
+		case 2:
+		    *(char_u **)varp = vim_strsave(
+						 (char_u *)"indent,eol,start");
+		    break;
+		case 3:
+		    *(char_u **)varp = vim_strsave(
+						(char_u *)"indent,eol,nostop");
+		    break;
+	    }
+	    vim_free(oldval);
+	    if (origval == oldval)
+		origval = *(char_u **)varp;
+	    if (origval_l == oldval)
+		origval_l = *(char_u **)varp;
+	    if (origval_g == oldval)
+		origval_g = *(char_u **)varp;
+	    oldval = *(char_u **)varp;
+	}
+	/*
+	 * Convert 'whichwrap' number to string, for backwards compatibility
+	 * with Vim 3.0.
+	 */
+	else if (varp == (char_u *)&p_ww && VIM_ISDIGIT(**arg))
+	{
+	    *whichwrap = NUL;
+	    int i = getdigits(arg);
+	    if (i & 1)
+		STRCAT(whichwrap, "b,");
+	    if (i & 2)
+		STRCAT(whichwrap, "s,");
+	    if (i & 4)
+		STRCAT(whichwrap, "h,l,");
+	    if (i & 8)
+		STRCAT(whichwrap, "<,>,");
+	    if (i & 16)
+		STRCAT(whichwrap, "[,],");
+	    if (*whichwrap != NUL)	// remove trailing ,
+		whichwrap[STRLEN(whichwrap) - 1] = NUL;
+	    save_arg = *arg;
+	    *arg = (char_u *)whichwrap;
+	}
+	/*
+	 * Remove '>' before 'dir' and 'bdir', for backwards compatibility with
+	 * version 3.0
+	 */
+	else if (  **arg == '>' && (varp == (char_u *)&p_dir
+						 || varp == (char_u *)&p_bdir))
+	    ++*arg;
+
+	/*
+	 * Copy the new string into allocated memory.
+	 * Can't use set_string_option_direct(), because we need to remove the
+	 * backslashes.
+	 */
+	// get a bit too much
+	newlen = (unsigned)STRLEN(*arg) + 1;
+	if (op != OP_NONE)
+	    newlen += (unsigned)STRLEN(origval) + 1;
+	newval = alloc(newlen);
+	if (newval == NULL)  // out of mem, don't change
+	    return FAIL;
+	s = newval;
+
+	/*
+	 * Copy the string, skip over escaped chars.
+	 * For MS-DOS and WIN32 backslashes before normal file name characters
+	 * are not removed, and keep backslash at start, for "\\machine\path",
+	 * but do remove it for "\\\\machine\\path".
+	 * The reverse is found in ExpandOldSetting().
+	 */
+	while (**arg && !VIM_ISWHITE(**arg))
+	{
+	    int i;
+
+	    if (**arg == '\\' && (*arg)[1] != NUL
+#ifdef BACKSLASH_IN_FILENAME
+		    && !((flags & P_EXPAND)
+			    && vim_isfilec((*arg)[1])
+			    && !VIM_ISWHITE((*arg)[1])
+			    && ((*arg)[1] != '\\'
+					|| (s == newval && (*arg)[2] != '\\')))
+#endif
+						)
+		++*arg;	// remove backslash
+	    if (has_mbyte && (i = (*mb_ptr2len)(*arg)) > 1)
+	    {
+		// copy multibyte char
+		mch_memmove(s, *arg, (size_t)i);
+		*arg += i;
+		s += i;
+	    }
+	    else
+		*s++ = *(*arg)++;
+	}
+	*s = NUL;
+
+	/*
+	 * Expand environment variables and ~.
+	 * Don't do it when adding without inserting a comma.
+	 */
+	if (op == OP_NONE || (flags & P_COMMA))
+	{
+	    s = option_expand(opt_idx, newval);
+	    if (s != NULL)
+	    {
+		vim_free(newval);
+		newlen = (unsigned)STRLEN(s) + 1;
+		if (op != OP_NONE)
+		    newlen += (unsigned)STRLEN(origval) + 1;
+		newval = alloc(newlen);
+		if (newval == NULL)
+		    return FAIL;
+		STRCPY(newval, s);
+	    }
+	}
+
+	// locate newval[] in origval[] when removing it
+	// and when adding to avoid duplicates
+	int len = 0;
+	if (op == OP_REMOVING || (flags & P_NODUP))
+	{
+	    len = (int)STRLEN(newval);
+	    s = find_dup_item(origval, newval, flags);
+
+	    // do not add if already there
+	    if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL)
+	    {
+		op = OP_NONE;
+		STRCPY(newval, origval);
+	    }
+
+	    // if no duplicate, move pointer to end of original value
+	    if (s == NULL)
+		s = origval + (int)STRLEN(origval);
+	}
+
+	// concatenate the two strings; add a ',' if needed
+	if (op == OP_ADDING || op == OP_PREPENDING)
+	{
+	    comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL);
+	    if (op == OP_ADDING)
+	    {
+		len = (int)STRLEN(origval);
+		// strip a trailing comma, would get 2
+		if (comma && len > 1
+			  && (flags & P_ONECOMMA) == P_ONECOMMA
+			  && origval[len - 1] == ','
+			  && origval[len - 2] != '\\')
+		    len--;
+		mch_memmove(newval + len + comma, newval, STRLEN(newval) + 1);
+		mch_memmove(newval, origval, (size_t)len);
+	    }
+	    else
+	    {
+		len = (int)STRLEN(newval);
+		STRMOVE(newval + len + comma, origval);
+	    }
+	    if (comma)
+		newval[len] = ',';
+	}
+
+	// Remove newval[] from origval[]. (Note: "len" has been set above and
+	// is used here).
+	if (op == OP_REMOVING)
+	{
+	    STRCPY(newval, origval);
+	    if (*s)
+	    {
+		// may need to remove a comma
+		if (flags & P_COMMA)
+		{
+		    if (s == origval)
+		    {
+			// include comma after string
+			if (s[len] == ',')
+			    ++len;
+		    }
+		    else
+		    {
+			// include comma before string
+			--s;
+			++len;
+		    }
+		}
+		STRMOVE(newval + (s - origval), s + len);
+	    }
+	}
+
+	if (flags & P_FLAGLIST)
+	{
+	    // Remove flags that appear twice.
+	    for (s = newval; *s;)
+	    {
+		// if options have P_FLAGLIST and P_ONECOMMA such as
+		// 'whichwrap'
+		if (flags & P_ONECOMMA)
+		{
+		    if (*s != ',' && *(s + 1) == ','
+					      && vim_strchr(s + 2, *s) != NULL)
+		    {
+			// Remove the duplicated value and the next comma.
+			STRMOVE(s, s + 2);
+			continue;
+		    }
+		}
+		else
+		{
+		    if ((!(flags & P_COMMA) || *s != ',')
+					      && vim_strchr(s + 1, *s) != NULL)
+		    {
+			STRMOVE(s, s + 1);
+			continue;
+		    }
+		}
+		++s;
+	    }
+	}
+
+	if (save_arg != NULL)   // number for 'whichwrap'
+	    *arg = save_arg;
+    }
+
+    /*
+     * Set the new value.
+     */
+    *(char_u **)(varp) = newval;
+
+#if defined(FEAT_EVAL)
+    if (!starting
+# ifdef FEAT_CRYPT
+	    && options[opt_idx].indir != PV_KEY
+# endif
+		      && origval != NULL && newval != NULL)
+    {
+	// origval may be freed by did_set_string_option(), make a copy.
+	saved_origval = vim_strsave(origval);
+	// newval (and varp) may become invalid if the buffer is closed by
+	// autocommands.
+	saved_newval = vim_strsave(newval);
+	if (origval_l != NULL)
+	    saved_origval_l = vim_strsave(origval_l);
+	if (origval_g != NULL)
+	    saved_origval_g = vim_strsave(origval_g);
+    }
+#endif
+
+    {
+	long_u	*p = insecure_flag(opt_idx, opt_flags);
+	int	secure_saved = secure;
+
+	// When an option is set in the sandbox, from a modeline or in secure
+	// mode, then deal with side effects in secure mode.  Also when the
+	// value was set with the P_INSECURE flag and is not completely
+	// replaced.
+	if ((opt_flags & OPT_MODELINE)
+#ifdef HAVE_SANDBOX
+	      || sandbox != 0
+#endif
+	      || (op != OP_NONE && (*p & P_INSECURE)))
+	    secure = 1;
+
+	// Handle side effects, and set the global value for ":set" on local
+	// options. Note: when setting 'syntax' or 'filetype' autocommands may
+	// be triggered that can cause havoc.
+	*errmsg = did_set_string_option(
+			opt_idx, (char_u **)varp, oldval, errbuf,
+			opt_flags, value_checked);
+
+	secure = secure_saved;
+    }
+
+#if defined(FEAT_EVAL)
+    if (*errmsg == NULL)
+	trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
+			       saved_origval_l, saved_origval_g, saved_newval);
+    vim_free(saved_origval);
+    vim_free(saved_origval_l);
+    vim_free(saved_origval_g);
+    vim_free(saved_newval);
+#endif
+
+    return *errmsg == NULL ? OK : FAIL;
+}
+
 /*
  * Parse 'arg' for option settings.
  *
@@ -1241,9 +1666,7 @@ do_set(
     long_u	flags;		    // flags for current option
     char_u	*varp = NULL;	    // pointer to variable for current option
     int		did_show = FALSE;   // already showed one value
-    int		adding;		    // "opt+=arg"
-    int		prepending;	    // "opt^=arg"
-    int		removing;	    // "opt-=arg"
+    set_op_T	op = 0;
     int		cp_val = 0;
     char_u	key_name[2];
 
@@ -1371,24 +1794,22 @@ do_set(
 		while (VIM_ISWHITE(arg[len]))
 		    ++len;
 
-	    adding = FALSE;
-	    prepending = FALSE;
-	    removing = FALSE;
+	    op = OP_NONE;
 	    if (arg[len] != NUL && arg[len + 1] == '=')
 	    {
 		if (arg[len] == '+')
 		{
-		    adding = TRUE;		// "+="
+		    op = OP_ADDING;		// "+="
 		    ++len;
 		}
 		else if (arg[len] == '^')
 		{
-		    prepending = TRUE;		// "^="
+		    op = OP_PREPENDING;		// "^="
 		    ++len;
 		}
 		else if (arg[len] == '-')
 		{
-		    removing = TRUE;		// "-="
+		    op = OP_REMOVING;		// "-="
 		    ++len;
 		}
 	    }
@@ -1564,7 +1985,6 @@ do_set(
 	    }
 	    else
 	    {
-		int value_is_replaced = !prepending && !adding && !removing;
 		int value_checked = FALSE;
 
 		if (flags & P_BOOL)		    // boolean
@@ -1686,440 +2106,25 @@ do_set(
 			    goto skip;
 			}
 
-			if (adding)
+			if (op == OP_ADDING)
 			    value = *(long *)varp + value;
-			if (prepending)
+			else if (op == OP_PREPENDING)
 			    value = *(long *)varp * value;
-			if (removing)
+			else if (op == OP_REMOVING)
 			    value = *(long *)varp - value;
 			errmsg = set_num_option(opt_idx, varp, value,
 					   errbuf, sizeof(errbuf), opt_flags);
 		    }
 		    else if (opt_idx >= 0)		    // string
 		    {
-			char_u	  *save_arg = NULL;
-			char_u	  *s = NULL;
-			char_u	  *oldval = NULL; // previous value if *varp
-			char_u	  *newval;
-			char_u	  *origval = NULL;
-			char_u	  *origval_l = NULL;
-			char_u	  *origval_g = NULL;
-#if defined(FEAT_EVAL)
-			char_u	  *saved_origval = NULL;
-			char_u	  *saved_origval_l = NULL;
-			char_u	  *saved_origval_g = NULL;
-			char_u	  *saved_newval = NULL;
-#endif
-			unsigned  newlen;
-			int	  comma;
-
-			// When using ":set opt=val" for a global option
-			// with a local value the local value will be
-			// reset, use the global value here.
-			if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
-				&& ((int)options[opt_idx].indir & PV_BOTH))
-			    varp = options[opt_idx].var;
-
-			// The old value is kept until we are sure that the
-			// new value is valid.
-			oldval = *(char_u **)varp;
-
-			if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
-			{
-			    origval_l = *(char_u **)get_varp_scope(
-					       &(options[opt_idx]), OPT_LOCAL);
-			    origval_g = *(char_u **)get_varp_scope(
-					      &(options[opt_idx]), OPT_GLOBAL);
-
-			    // A global-local string option might have an empty
-			    // option as value to indicate that the global
-			    // value should be used.
-			    if (((int)options[opt_idx].indir & PV_BOTH)
-						  && origval_l == empty_option)
-				origval_l = origval_g;
-			}
-
-			// When setting the local value of a global
-			// option, the old value may be the global value.
-			if (((int)options[opt_idx].indir & PV_BOTH)
-					       && (opt_flags & OPT_LOCAL))
-			    origval = *(char_u **)get_varp(
-						       &options[opt_idx]);
-			else
-			    origval = oldval;
-
-			if (nextchar == '&')	// set to default val
-			{
-			    newval = options[opt_idx].def_val[
-						((flags & P_VI_DEF) || cp_val)
-						 ?  VI_DEFAULT : VIM_DEFAULT];
-			    if ((char_u **)varp == &p_bg)
-			    {
-				// guess the value of 'background'
-#ifdef FEAT_GUI
-				if (gui.in_use)
-				    newval = gui_bg_default();
-				else
-#endif
-				    newval = term_bg_default();
-			    }
-			    else if ((char_u **)varp == &p_fencs && enc_utf8)
-				newval = fencs_utf8_default;
-
-			    // expand environment variables and ~ since the
-			    // default value was already expanded, only
-			    // required when an environment variable was set
-			    // later
-			    if (newval == NULL)
-				newval = empty_option;
-			    else
-			    {
-				s = option_expand(opt_idx, newval);
-				if (s == NULL)
-				    s = newval;
-				newval = vim_strsave(s);
-			    }
-			}
-			else if (nextchar == '<')	// set to global val
-			{
-			    newval = vim_strsave(*(char_u **)get_varp_scope(
-					     &(options[opt_idx]), OPT_GLOBAL));
-			}
-			else
+			if (do_set_string(opt_idx, opt_flags, &arg, nextchar,
+				       op, flags, cp_val, varp, errbuf,
+				       &value_checked, &errmsg) == FAIL)
 			{
-			    ++arg;	// jump to after the '=' or ':'
-
-			    /*
-			     * Set 'keywordprg' to ":help" if an empty
-			     * value was passed to :set by the user.
-			     * Misuse errbuf[] for the resulting string.
-			     */
-			    if (varp == (char_u *)&p_kp
-					      && (*arg == NUL || *arg == ' '))
-			    {
-				STRCPY(errbuf, ":help");
-				save_arg = arg;
-				arg = (char_u *)errbuf;
-			    }
-			    /*
-			     * Convert 'backspace' number to string, for
-			     * adding, prepending and removing string.
-			     */
-			    else if (varp == (char_u *)&p_bs
-					 && VIM_ISDIGIT(**(char_u **)varp))
-			    {
-				i = getdigits((char_u **)varp);
-				switch (i)
-				{
-				    case 0:
-					*(char_u **)varp = empty_option;
-					break;
-				    case 1:
-					*(char_u **)varp = vim_strsave(
-						      (char_u *)"indent,eol");
-					break;
-				    case 2:
-					*(char_u **)varp = vim_strsave(
-						(char_u *)"indent,eol,start");
-					break;
-				    case 3:
-					*(char_u **)varp = vim_strsave(
-						(char_u *)"indent,eol,nostop");
-					break;
-				}
-				vim_free(oldval);
-				if (origval == oldval)
-				    origval = *(char_u **)varp;
-				if (origval_l == oldval)
-				    origval_l = *(char_u **)varp;
-				if (origval_g == oldval)
-				    origval_g = *(char_u **)varp;
-				oldval = *(char_u **)varp;
-			    }
-			    /*
-			     * Convert 'whichwrap' number to string, for
-			     * backwards compatibility with Vim 3.0.
-			     * Misuse errbuf[] for the resulting string.
-			     */
-			    else if (varp == (char_u *)&p_ww
-							 && VIM_ISDIGIT(*arg))
-			    {
-				*errbuf = NUL;
-				i = getdigits(&arg);
-				if (i & 1)
-				    STRCAT(errbuf, "b,");
-				if (i & 2)
-				    STRCAT(errbuf, "s,");
-				if (i & 4)
-				    STRCAT(errbuf, "h,l,");
-				if (i & 8)
-				    STRCAT(errbuf, "<,>,");
-				if (i & 16)
-				    STRCAT(errbuf, "[,],");
-				if (*errbuf != NUL)	// remove trailing ,
-				    errbuf[STRLEN(errbuf) - 1] = NUL;
-				save_arg = arg;
-				arg = (char_u *)errbuf;
-			    }
-			    /*
-			     * Remove '>' before 'dir' and 'bdir', for
-			     * backwards compatibility with version 3.0
-			     */
-			    else if (  *arg == '>'
-				    && (varp == (char_u *)&p_dir
-					    || varp == (char_u *)&p_bdir))
-			    {
-				++arg;
-			    }
-
-			    /*
-			     * Copy the new string into allocated memory.
-			     * Can't use set_string_option_direct(), because
-			     * we need to remove the backslashes.
-			     */
-			    // get a bit too much
-			    newlen = (unsigned)STRLEN(arg) + 1;
-			    if (adding || prepending || removing)
-				newlen += (unsigned)STRLEN(origval) + 1;
-			    newval = alloc(newlen);
-			    if (newval == NULL)  // out of mem, don't change
-				break;
-			    s = newval;
-
-			    /*
-			     * Copy the string, skip over escaped chars.
-			     * For MS-DOS and WIN32 backslashes before normal
-			     * file name characters are not removed, and keep
-			     * backslash at start, for "\\machine\path", but
-			     * do remove it for "\\\\machine\\path".
-			     * The reverse is found in ExpandOldSetting().
-			     */
-			    while (*arg && !VIM_ISWHITE(*arg))
-			    {
-				if (*arg == '\\' && arg[1] != NUL
-#ifdef BACKSLASH_IN_FILENAME
-					&& !((flags & P_EXPAND)
-						&& vim_isfilec(arg[1])
-						&& !VIM_ISWHITE(arg[1])
-						&& (arg[1] != '\\'
-						    || (s == newval
-							&& arg[2] != '\\')))
-#endif
-								    )
-				    ++arg;	// remove backslash
-				if (has_mbyte
-					&& (i = (*mb_ptr2len)(arg)) > 1)
-				{
-				    // copy multibyte char
-				    mch_memmove(s, arg, (size_t)i);
-				    arg += i;
-				    s += i;
-				}
-				else
-				    *s++ = *arg++;
-			    }
-			    *s = NUL;
-
-			    /*
-			     * Expand environment variables and ~.
-			     * Don't do it when adding without inserting a
-			     * comma.
-			     */
-			    if (!(adding || prepending || removing)
-							 || (flags & P_COMMA))
-			    {
-				s = option_expand(opt_idx, newval);
-				if (s != NULL)
-				{
-				    vim_free(newval);
-				    newlen = (unsigned)STRLEN(s) + 1;
-				    if (adding || prepending || removing)
-					newlen += (unsigned)STRLEN(origval) + 1;
-				    newval = alloc(newlen);
-				    if (newval == NULL)
-					break;
-				    STRCPY(newval, s);
-				}
-			    }
-
-			    // locate newval[] in origval[] when removing it
-			    // and when adding to avoid duplicates
-			    i = 0;	// init for GCC
-			    if (removing || (flags & P_NODUP))
-			    {
-				i = (int)STRLEN(newval);
-				s = find_dup_item(origval, newval, flags);
-
-				// do not add if already there
-				if ((adding || prepending) && s != NULL)
-				{
-				    prepending = FALSE;
-				    adding = FALSE;
-				    STRCPY(newval, origval);
-				}
-
-				// if no duplicate, move pointer to end of
-				// original value
-				if (s == NULL)
-				    s = origval + (int)STRLEN(origval);
-			    }
-
-			    // concatenate the two strings; add a ',' if
-			    // needed
-			    if (adding || prepending)
-			    {
-				comma = ((flags & P_COMMA) && *origval != NUL
-							   && *newval != NUL);
-				if (adding)
-				{
-				    i = (int)STRLEN(origval);
-				    // strip a trailing comma, would get 2
-				    if (comma && i > 1
-					  && (flags & P_ONECOMMA) == P_ONECOMMA
-					  && origval[i - 1] == ','
-					  && origval[i - 2] != '\\')
-					i--;
-				    mch_memmove(newval + i + comma, newval,
-							  STRLEN(newval) + 1);
-				    mch_memmove(newval, origval, (size_t)i);
-				}
-				else
-				{
-				    i = (int)STRLEN(newval);
-				    STRMOVE(newval + i + comma, origval);
-				}
-				if (comma)
-				    newval[i] = ',';
-			    }
-
-			    // Remove newval[] from origval[]. (Note: "i" has
-			    // been set above and is used here).
-			    if (removing)
-			    {
-				STRCPY(newval, origval);
-				if (*s)
-				{
-				    // may need to remove a comma
-				    if (flags & P_COMMA)
-				    {
-					if (s == origval)
-					{
-					    // include comma after string
-					    if (s[i] == ',')
-						++i;
-					}
-					else
-					{
-					    // include comma before string
-					    --s;
-					    ++i;
-					}
-				    }
-				    STRMOVE(newval + (s - origval), s + i);
-				}
-			    }
-
-			    if (flags & P_FLAGLIST)
-			    {
-				// Remove flags that appear twice.
-				for (s = newval; *s;)
-				{
-				    // if options have P_FLAGLIST and
-				    // P_ONECOMMA such as 'whichwrap'
-				    if (flags & P_ONECOMMA)
-				    {
-					if (*s != ',' && *(s + 1) == ','
-					      && vim_strchr(s + 2, *s) != NULL)
-					{
-					    // Remove the duplicated value and
-					    // the next comma.
-					    STRMOVE(s, s + 2);
-					    continue;
-					}
-				    }
-				    else
-				    {
-					if ((!(flags & P_COMMA) || *s != ',')
-					      && vim_strchr(s + 1, *s) != NULL)
-					{
-					    STRMOVE(s, s + 1);
-					    continue;
-					}
-				    }
-				    ++s;
-				}
-			    }
-
-			    if (save_arg != NULL)   // number for 'whichwrap'
-				arg = save_arg;
+			    if (errmsg != NULL)
+				goto skip;
+			    break;
 			}
-
-			/*
-			 * Set the new value.
-			 */
-			*(char_u **)(varp) = newval;
-
-#if defined(FEAT_EVAL)
-			if (!starting
-# ifdef FEAT_CRYPT
-				&& options[opt_idx].indir != PV_KEY
-# endif
-					  && origval != NULL && newval != NULL)
-			{
-			    // origval may be freed by
-			    // did_set_string_option(), make a copy.
-			    saved_origval = vim_strsave(origval);
-			    // newval (and varp) may become invalid if the
-			    // buffer is closed by autocommands.
-			    saved_newval = vim_strsave(newval);
-			    if (origval_l != NULL)
-				saved_origval_l = vim_strsave(origval_l);
-			    if (origval_g != NULL)
-				saved_origval_g = vim_strsave(origval_g);
-			}
-#endif
-
-			{
-			    long_u *p = insecure_flag(opt_idx, opt_flags);
-			    int	    secure_saved = secure;
-
-			    // When an option is set in the sandbox, from a
-			    // modeline or in secure mode, then deal with side
-			    // effects in secure mode.  Also when the value was
-			    // set with the P_INSECURE flag and is not
-			    // completely replaced.
-			    if ((opt_flags & OPT_MODELINE)
-#ifdef HAVE_SANDBOX
-				  || sandbox != 0
-#endif
-				  || (!value_is_replaced && (*p & P_INSECURE)))
-				secure = 1;
-
-			    // Handle side effects, and set the global value
-			    // for ":set" on local options. Note: when setting
-			    // 'syntax' or 'filetype' autocommands may be
-			    // triggered that can cause havoc.
-			    errmsg = did_set_string_option(
-				    opt_idx, (char_u **)varp, oldval, errbuf,
-				    opt_flags, &value_checked);
-
-			    secure = secure_saved;
-			}
-
-#if defined(FEAT_EVAL)
-			if (errmsg == NULL)
-			    trigger_optionsset_string(
-				    opt_idx, opt_flags, saved_origval,
-				    saved_origval_l, saved_origval_g,
-				    saved_newval);
-			vim_free(saved_origval);
-			vim_free(saved_origval_l);
-			vim_free(saved_origval_g);
-			vim_free(saved_newval);
-#endif
-			// If error detected, print the error message.
-			if (errmsg != NULL)
-			    goto skip;
 		    }
 		    else	    // key code option
 		    {
@@ -2149,7 +2154,7 @@ do_set(
 
 		if (opt_idx >= 0)
 		    did_set_option(
-			 opt_idx, opt_flags, value_is_replaced, value_checked);
+			 opt_idx, opt_flags, op == OP_NONE, value_checked);
 	    }
 
 skip:
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    537,
+/**/
     536,
 /**/
     535,