vim-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 vim/vim#6940)
b00ef0508b
This commit is contained in:
Jan Edmund Lazo
2021-03-27 08:45:28 -04:00
parent 6da06bc249
commit 9118bf191e
2 changed files with 89 additions and 35 deletions

View File

@@ -379,8 +379,8 @@ void set_init_1(bool clean_arg)
# else # else
static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"}; static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
# endif # endif
int len;
garray_T ga; garray_T ga;
opt_idx = findoption("backupskip");
ga_init(&ga, 1, 100); ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) { for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
@@ -401,15 +401,23 @@ void set_init_1(bool clean_arg)
} }
if (p != NULL && *p != NUL) { if (p != NULL && *p != NUL) {
// First time count the NUL, otherwise count the ','. // First time count the NUL, otherwise count the ','.
len = (int)strlen(p) + 3; const size_t len = strlen(p) + 3;
ga_grow(&ga, len); char *item = xmalloc(len);
if (!GA_EMPTY(&ga)) { xstrlcpy(item, p, len);
STRCAT(ga.ga_data, ","); add_pathsep(item);
xstrlcat(item, "*", len);
if (find_dup_item(ga.ga_data, (char_u *)item, options[opt_idx].flags)
== NULL) {
ga_grow(&ga, (int)len);
if (!GA_EMPTY(&ga)) {
STRCAT(ga.ga_data, ",");
}
STRCAT(ga.ga_data, p);
add_pathsep(ga.ga_data);
STRCAT(ga.ga_data, "*");
ga.ga_len += (int)len;
} }
STRCAT(ga.ga_data, p); xfree(item);
add_pathsep(ga.ga_data);
STRCAT(ga.ga_data, "*");
ga.ga_len += len;
} }
if(mustfree) { if(mustfree) {
xfree(p); xfree(p);
@@ -713,6 +721,38 @@ static void set_string_default(const char *name, char *val, bool allocated)
} }
} }
// 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, const char_u *newval,
uint32_t flags)
FUNC_ATTR_NONNULL_ARG(2)
{
int bs = 0;
if (origval == NULL) {
return NULL;
}
const size_t newlen = STRLEN(newval);
for (char_u *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. /// Set the Vi-default value of a number option.
/// Used for 'lines' and 'columns'. /// Used for 'lines' and 'columns'.
void set_number_default(char *name, long val) void set_number_default(char *name, long val)
@@ -1285,9 +1325,7 @@ int do_set(
char *saved_newval = NULL; char *saved_newval = NULL;
unsigned newlen; unsigned newlen;
int comma; int comma;
int bs; bool new_value_alloced = false; // new string option was allocated
int new_value_alloced; /* new string option
was allocated */
/* When using ":set opt=val" for a global option /* When using ":set opt=val" for a global option
* with a local value the local value will be * with a local value the local value will be
@@ -1486,34 +1524,20 @@ int do_set(
i = 0; // init for GCC i = 0; // init for GCC
if (removing || (flags & P_NODUP)) { if (removing || (flags & P_NODUP)) {
i = (int)STRLEN(newval); i = (int)STRLEN(newval);
bs = 0; s = find_dup_item(origval, newval, flags);
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;
}
}
// do not add if already there // do not add if already there
if ((adding || prepending) && *s) { if ((adding || prepending) && s != NULL) {
prepending = false; prepending = false;
adding = false; adding = false;
STRCPY(newval, origval); 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 /* concatenate the two strings; add a ',' if
@@ -2310,7 +2334,7 @@ static char_u *
did_set_string_option( did_set_string_option(
int opt_idx, // index in options[] table int opt_idx, // index in options[] table
char_u **varp, // pointer to the option variable char_u **varp, // pointer to the option variable
int new_value_alloced, // new value was allocated bool new_value_alloced, // new value was allocated
char_u *oldval, // previous value of the option char_u *oldval, // previous value of the option
char_u *errbuf, // buffer for errors, or NULL char_u *errbuf, // buffer for errors, or NULL
size_t errbuflen, // length of errors buffer size_t errbuflen, // length of errors buffer

View File

@@ -448,6 +448,36 @@ func Test_backupskip()
endif endif
endfor 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 cmd = GetVimProg() . ' -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) " Duplicates should be filtered out (option has P_NODUP)
let backupskip = &backupskip let backupskip = &backupskip
set backupskip= set backupskip=