# HG changeset patch # User Bram Moolenaar # Date 1599915604 -7200 # Node ID b5abb88d5700b78297b5cc4e9a17b8ea74907f87 # Parent 0aeaeed4640d3b7eb4eb4ec7e659b1d9d7a15e21 patch 8.2.1666: the initial value of 'backupskip' can have duplicate items Commit: https://github.com/vim/vim/commit/b00ef0508b22905379953a164bdb4300015d3705 Author: Bram Moolenaar Date: Sat Sep 12 14:53:53 2020 +0200 patch 8.2.1666: the initial value of 'backupskip' can have duplicate items Problem: The initial value of 'backupskip' can have duplicate items. Solution: Remove duplicates, like when it is set later. (Tom Ryder, closes #6940) diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -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); @@ -668,6 +677,46 @@ set_string_default(char *name, char_u *v } /* + * 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 diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -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= diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1666, +/**/ 1665, /**/ 1664,