Patch 9.0.0537
Problem:    The do_set() function is much too long.
Solution:   Move setting of a string option to a separate function.
Files:      src/option.c


*** ../vim-9.0.0536/src/option.c        2022-09-12 13:35:06.514946763 +0100
--- src/option.c        2022-09-21 21:10:26.865408272 +0100
***************
*** 1205,1210 ****
--- 1205,1635 ----
      }
  }
  
+ 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,1249 ****
      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"
      int               cp_val = 0;
      char_u    key_name[2];
  
--- 1666,1672 ----
      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
!     set_op_T  op = 0;
      int               cp_val = 0;
      char_u    key_name[2];
  
***************
*** 1371,1394 ****
                while (VIM_ISWHITE(arg[len]))
                    ++len;
  
!           adding = FALSE;
!           prepending = FALSE;
!           removing = FALSE;
            if (arg[len] != NUL && arg[len + 1] == '=')
            {
                if (arg[len] == '+')
                {
!                   adding = TRUE;              // "+="
                    ++len;
                }
                else if (arg[len] == '^')
                {
!                   prepending = TRUE;          // "^="
                    ++len;
                }
                else if (arg[len] == '-')
                {
!                   removing = TRUE;            // "-="
                    ++len;
                }
            }
--- 1794,1815 ----
                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;
                }
            }
***************
*** 1564,1570 ****
            }
            else
            {
-               int value_is_replaced = !prepending && !adding && !removing;
                int value_checked = FALSE;
  
                if (flags & P_BOOL)                 // boolean
--- 1985,1990 ----
***************
*** 1686,2125 ****
                            goto skip;
                        }
  
!                       if (adding)
                            value = *(long *)varp + value;
!                       if (prepending)
                            value = *(long *)varp * value;
!                       if (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
!                       {
!                           ++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;
!                       }
! 
!                       /*
!                        * 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
                    {
--- 2106,2130 ----
                            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, sizeof(errbuf), 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;
!                           break;
                        }
                    }
                    else            // key code option
                    {
***************
*** 2149,2155 ****
  
                if (opt_idx >= 0)
                    did_set_option(
!                        opt_idx, opt_flags, value_is_replaced, value_checked);
            }
  
  skip:
--- 2154,2160 ----
  
                if (opt_idx >= 0)
                    did_set_option(
!                        opt_idx, opt_flags, op == OP_NONE, value_checked);
            }
  
  skip:
*** ../vim-9.0.0536/src/version.c       2022-09-21 19:41:52.172533866 +0100
--- src/version.c       2022-09-21 20:20:35.973014671 +0100
***************
*** 701,702 ****
--- 701,704 ----
  {   /* Add new patch number below this line */
+ /**/
+     537,
  /**/

-- 
I'm writing a book.  I've got the page numbers done.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220921201326.CAF571C0EC3%40moolenaar.net.

Raspunde prin e-mail lui