]> granicus.if.org Git - vim/commitdiff
patch 8.2.1666: the initial value of 'backupskip' can have duplicate items v8.2.1666
authorBram Moolenaar <Bram@vim.org>
Sat, 12 Sep 2020 12:53:53 +0000 (14:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 12 Sep 2020 12:53:53 +0000 (14:53 +0200)
Problem:    The initial value of 'backupskip' can have duplicate items.
Solution:   Remove duplicates, like when it is set later. (Tom Ryder,
            closes #6940)

src/option.c
src/testdir/test_options.vim
src/version.c

index 648f22db32d48efcf4cae6aed78954745823841e..6ebc2bd9b5efd268ecafe9df1146e57d08dfc89b 100644 (file)
@@ -37,6 +37,7 @@
 
 static void set_options_default(int opt_flags);
 static void set_string_default_esc(char *name, char_u *val, int escape);
+static char_u *find_dup_item(char_u *origval, char_u *newval, long_u flags);
 static char_u *option_expand(int opt_idx, char_u *val);
 static void didset_options(void);
 static void didset_options2(void);
@@ -139,6 +140,9 @@ set_init_1(int clean_arg)
        int             len;
        garray_T        ga;
        int             mustfree;
+       char_u          *item;
+
+       opt_idx = findoption((char_u *)"backupskip");
 
        ga_init2(&ga, 1, 100);
        for (n = 0; n < (long)(sizeof(names) / sizeof(char *)); ++n)
@@ -158,15 +162,20 @@ set_init_1(int clean_arg)
            {
                // First time count the NUL, otherwise count the ','.
                len = (int)STRLEN(p) + 3;
-               if (ga_grow(&ga, len) == OK)
+               item = alloc(len);
+               STRCPY(item, p);
+               add_pathsep(item);
+               STRCAT(item, "*");
+               if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
+                                                                       == NULL
+                       && ga_grow(&ga, len) == OK)
                {
                    if (ga.ga_len > 0)
                        STRCAT(ga.ga_data, ",");
-                   STRCAT(ga.ga_data, p);
-                   add_pathsep(ga.ga_data);
-                   STRCAT(ga.ga_data, "*");
+                   STRCAT(ga.ga_data, item);
                    ga.ga_len += len;
                }
+               vim_free(item);
            }
            if (mustfree)
                vim_free(p);
@@ -667,6 +676,46 @@ set_string_default(char *name, char_u *val)
     set_string_default_esc(name, val, FALSE);
 }
 
+/*
+ * For an option value that contains comma separated items, find "newval" in
+ * "origval".  Return NULL if not found.
+ */
+    static char_u *
+find_dup_item(char_u *origval, char_u *newval, long_u flags)
+{
+    int            bs;
+    size_t  newlen;
+    char_u  *s;
+
+    if (origval == NULL)
+       return NULL;
+
+    newlen = STRLEN(newval);
+    for (s = origval; *s != NUL; ++s)
+    {
+       if ((!(flags & P_COMMA)
+                   || s == origval
+                   || (s[-1] == ',' && !(bs & 1)))
+               && STRNCMP(s, newval, newlen) == 0
+               && (!(flags & P_COMMA)
+                   || s[newlen] == ','
+                   || s[newlen] == NUL))
+           return s;
+       // Count backslashes.  Only a comma with an even number of backslashes
+       // or a single backslash preceded by a comma before it is recognized as
+       // a separator.
+       if ((s > origval + 1
+                   && s[-1] == '\\'
+                   && s[-2] != ',')
+               || (s == origval + 1
+                   && s[-1] == '\\'))
+           ++bs;
+       else
+           bs = 0;
+    }
+    return NULL;
+}
+
 /*
  * Set the Vi-default value of a number option.
  * Used for 'lines' and 'columns'.
@@ -1572,7 +1621,6 @@ do_set(
 #endif
                        unsigned  newlen;
                        int       comma;
-                       int       bs;
                        int       new_value_alloced;    // new string option
                                                        // was allocated
 
@@ -1811,39 +1859,20 @@ do_set(
                            if (removing || (flags & P_NODUP))
                            {
                                i = (int)STRLEN(newval);
-                               bs = 0;
-                               for (s = origval; *s; ++s)
-                               {
-                                   if ((!(flags & P_COMMA)
-                                               || s == origval
-                                               || (s[-1] == ',' && !(bs & 1)))
-                                           && STRNCMP(s, newval, i) == 0
-                                           && (!(flags & P_COMMA)
-                                               || s[i] == ','
-                                               || s[i] == NUL))
-                                       break;
-                                   // Count backslashes.  Only a comma with an
-                                   // even number of backslashes or a single
-                                   // backslash preceded by a comma before it
-                                   // is recognized as a separator
-                                   if ((s > origval + 1
-                                               && s[-1] == '\\'
-                                               && s[-2] != ',')
-                                           || (s == origval + 1
-                                               && s[-1] == '\\'))
-
-                                       ++bs;
-                                   else
-                                       bs = 0;
-                               }
+                               s = find_dup_item(origval, newval, flags);
 
                                // do not add if already there
-                               if ((adding || prepending) && *s)
+                               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
index c5e5ab47c4adfe3389ee32158f7b39f7b9cf1c86..ec40ccc5fbb2546260cf8c338cd02b027cd8ca24 100644 (file)
@@ -1,5 +1,6 @@
 " Test for options
 
+source shared.vim
 source check.vim
 source view_util.vim
 
@@ -587,6 +588,35 @@ func Test_backupskip()
     endif
   endfor
 
+  " Duplicates from environment variables should be filtered out (option has
+  " P_NODUP).  Run this in a separate instance and write v:errors in a file,
+  " so that we see what happens on startup.
+  let after =<< trim [CODE]
+      let bsklist = split(&backupskip, ',')
+      call assert_equal(uniq(copy(bsklist)), bsklist)
+      call writefile(['errors:'] + v:errors, 'Xtestout')
+      qall
+  [CODE]
+  call writefile(after, 'Xafter')
+  let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
+
+  let saveenv = {}
+  for var in ['TMPDIR', 'TMP', 'TEMP']
+    let saveenv[var] = getenv(var)
+    call setenv(var, '/duplicate/path')
+  endfor
+
+  exe 'silent !' . cmd
+  call assert_equal(['errors:'], readfile('Xtestout'))
+
+  " restore environment variables
+  for var in ['TMPDIR', 'TMP', 'TEMP']
+    call setenv(var, saveenv[var])
+  endfor
+
+  call delete('Xtestout')
+  call delete('Xafter')
+
   " Duplicates should be filtered out (option has P_NODUP)
   let backupskip = &backupskip
   set backupskip=
index e0afdf8352b532ec71671a987787dd6d8875ee14..596f38d7ef593f94395b0e0c0aec81c510a4c135 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1666,
 /**/
     1665,
 /**/