mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
Merge pull request #25398 from zeertzjq/vim-9.0.1946
vim-patch:9.0.{0607,1946,1947}: filename expansion using ** in bash may fail
This commit is contained in:
@@ -356,7 +356,9 @@ as a wildcard when "[" is in the 'isfname' option. A simple way to avoid this
|
|||||||
is to use "path\[[]abc]", this matches the file "path\[abc]".
|
is to use "path\[[]abc]", this matches the file "path\[abc]".
|
||||||
|
|
||||||
*starstar-wildcard*
|
*starstar-wildcard*
|
||||||
Expanding "**" is possible on Unix, Win32, macOS and a few other systems.
|
Expanding "**" is possible on Unix, Win32, macOS and a few other systems (but
|
||||||
|
it may depend on your 'shell' setting. It's known to work correctly for zsh; for
|
||||||
|
bash this requires at least bash version >= 4.X).
|
||||||
This allows searching a directory tree. This goes up to 100 directories deep.
|
This allows searching a directory tree. This goes up to 100 directories deep.
|
||||||
Note there are some commands where this works slightly differently, see
|
Note there are some commands where this works slightly differently, see
|
||||||
|file-searching|.
|
|file-searching|.
|
||||||
|
@@ -134,6 +134,8 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
|
#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
|
||||||
#define STYLE_PRINT 3 // use "print -N", for zsh
|
#define STYLE_PRINT 3 // use "print -N", for zsh
|
||||||
#define STYLE_BT 4 // `cmd` expansion, execute the pattern directly
|
#define STYLE_BT 4 // `cmd` expansion, execute the pattern directly
|
||||||
|
#define STYLE_GLOBSTAR 5 // use extended shell glob for bash (this uses extended
|
||||||
|
// globbing functionality with globstar, needs bash > 4)
|
||||||
int shell_style = STYLE_ECHO;
|
int shell_style = STYLE_ECHO;
|
||||||
int check_spaces;
|
int check_spaces;
|
||||||
static bool did_find_nul = false;
|
static bool did_find_nul = false;
|
||||||
@@ -141,6 +143,9 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
// vimglob() function to define for Posix shell
|
// vimglob() function to define for Posix shell
|
||||||
static char *sh_vimglob_func =
|
static char *sh_vimglob_func =
|
||||||
"vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
|
"vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
|
||||||
|
// vimglob() function with globstar setting enabled, only for bash >= 4.X
|
||||||
|
static char *sh_globstar_opt =
|
||||||
|
"[[ ${BASH_VERSINFO[0]} -ge 4 ]] && shopt -s globstar; ";
|
||||||
|
|
||||||
bool is_fish_shell =
|
bool is_fish_shell =
|
||||||
#if defined(UNIX)
|
#if defined(UNIX)
|
||||||
@@ -190,6 +195,8 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
// If we use *zsh, "print -N" will work better than "glob".
|
// If we use *zsh, "print -N" will work better than "glob".
|
||||||
// STYLE_VIMGLOB: NL separated
|
// STYLE_VIMGLOB: NL separated
|
||||||
// If we use *sh*, we define "vimglob()".
|
// If we use *sh*, we define "vimglob()".
|
||||||
|
// STYLE_GLOBSTAR: NL separated
|
||||||
|
// If we use *bash*, we define "vimglob() and enable globstar option".
|
||||||
// STYLE_ECHO: space separated.
|
// STYLE_ECHO: space separated.
|
||||||
// A shell we don't know, stay safe and use "echo".
|
// A shell we don't know, stay safe and use "echo".
|
||||||
if (num_pat == 1 && *pat[0] == '`'
|
if (num_pat == 1 && *pat[0] == '`'
|
||||||
@@ -203,10 +210,13 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
shell_style = STYLE_PRINT;
|
shell_style = STYLE_PRINT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shell_style == STYLE_ECHO
|
if (shell_style == STYLE_ECHO) {
|
||||||
&& strstr(path_tail(p_sh), "sh") != NULL) {
|
if (strstr(path_tail(p_sh), "bash") != NULL) {
|
||||||
|
shell_style = STYLE_GLOBSTAR;
|
||||||
|
} else if (strstr(path_tail(p_sh), "sh") != NULL) {
|
||||||
shell_style = STYLE_VIMGLOB;
|
shell_style = STYLE_VIMGLOB;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the length of the command. We need 2 extra bytes: for the
|
// Compute the length of the command. We need 2 extra bytes: for the
|
||||||
// optional '&' and for the NUL.
|
// optional '&' and for the NUL.
|
||||||
@@ -214,6 +224,8 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
len = strlen(tempname) + 29;
|
len = strlen(tempname) + 29;
|
||||||
if (shell_style == STYLE_VIMGLOB) {
|
if (shell_style == STYLE_VIMGLOB) {
|
||||||
len += strlen(sh_vimglob_func);
|
len += strlen(sh_vimglob_func);
|
||||||
|
} else if (shell_style == STYLE_GLOBSTAR) {
|
||||||
|
len += strlen(sh_vimglob_func) + strlen(sh_globstar_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num_pat; i++) {
|
for (i = 0; i < num_pat; i++) {
|
||||||
@@ -281,6 +293,9 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
STRCAT(command, "print -N >");
|
STRCAT(command, "print -N >");
|
||||||
} else if (shell_style == STYLE_VIMGLOB) {
|
} else if (shell_style == STYLE_VIMGLOB) {
|
||||||
STRCAT(command, sh_vimglob_func);
|
STRCAT(command, sh_vimglob_func);
|
||||||
|
} else if (shell_style == STYLE_GLOBSTAR) {
|
||||||
|
STRCAT(command, sh_globstar_opt);
|
||||||
|
STRCAT(command, sh_vimglob_func);
|
||||||
} else {
|
} else {
|
||||||
STRCAT(command, "echo >");
|
STRCAT(command, "echo >");
|
||||||
}
|
}
|
||||||
@@ -430,7 +445,9 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
p = skipwhite(p); // skip to next entry
|
p = skipwhite(p); // skip to next entry
|
||||||
}
|
}
|
||||||
// file names are separated with NL
|
// file names are separated with NL
|
||||||
} else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) {
|
} else if (shell_style == STYLE_BT
|
||||||
|
|| shell_style == STYLE_VIMGLOB
|
||||||
|
|| shell_style == STYLE_GLOBSTAR) {
|
||||||
buffer[len] = NUL; // make sure the buffer ends in NUL
|
buffer[len] = NUL; // make sure the buffer ends in NUL
|
||||||
p = buffer;
|
p = buffer;
|
||||||
for (i = 0; *p != NUL; i++) { // count number of entries
|
for (i = 0; *p != NUL; i++) { // count number of entries
|
||||||
@@ -496,7 +513,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
|
|||||||
(*file)[i] = p;
|
(*file)[i] = p;
|
||||||
// Space or NL separates
|
// Space or NL separates
|
||||||
if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
|
if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
|
||||||
|| shell_style == STYLE_VIMGLOB) {
|
|| shell_style == STYLE_VIMGLOB || shell_style == STYLE_GLOBSTAR) {
|
||||||
while (!(shell_style == STYLE_ECHO && *p == ' ')
|
while (!(shell_style == STYLE_ECHO && *p == ' ')
|
||||||
&& *p != '\n' && *p != NUL) {
|
&& *p != '\n' && *p != NUL) {
|
||||||
p++;
|
p++;
|
||||||
|
@@ -108,6 +108,22 @@ func CheckNotBSD()
|
|||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Command to check for not running on a MacOS
|
||||||
|
command CheckNotMac call CheckNotMac()
|
||||||
|
func CheckNotMac()
|
||||||
|
if has('mac')
|
||||||
|
throw 'Skipped: does not work on MacOS'
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Command to check for not running on a MacOS M1 system.
|
||||||
|
command CheckNotMacM1 call CheckNotMacM1()
|
||||||
|
func CheckNotMacM1()
|
||||||
|
if has('mac') && system('uname -a') =~ '\<arm64\>'
|
||||||
|
throw 'Skipped: does not work on MacOS M1'
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Command to check that making screendumps is supported.
|
" Command to check that making screendumps is supported.
|
||||||
" Caller must source screendump.vim
|
" Caller must source screendump.vim
|
||||||
command CheckScreendump call CheckScreendump()
|
command CheckScreendump call CheckScreendump()
|
||||||
|
@@ -3281,4 +3281,26 @@ func Test_fullcommand()
|
|||||||
call assert_equal('', fullcommand(10))
|
call assert_equal('', fullcommand(10))
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for glob() with shell special patterns
|
||||||
|
func Test_glob_extended_bash()
|
||||||
|
CheckExecutable bash
|
||||||
|
CheckNotMSWindows
|
||||||
|
CheckNotMac " The default version of bash is old on macOS.
|
||||||
|
|
||||||
|
let _shell = &shell
|
||||||
|
set shell=bash
|
||||||
|
|
||||||
|
call mkdir('Xtestglob/foo/bar/src', 'p')
|
||||||
|
call writefile([], 'Xtestglob/foo/bar/src/foo.sh')
|
||||||
|
call writefile([], 'Xtestglob/foo/bar/src/foo.h')
|
||||||
|
call writefile([], 'Xtestglob/foo/bar/src/foo.cpp')
|
||||||
|
|
||||||
|
" Sort output of glob() otherwise we end up with different
|
||||||
|
" ordering depending on whether file system is case-sensitive.
|
||||||
|
let expected = ['Xtestglob/foo/bar/src/foo.cpp', 'Xtestglob/foo/bar/src/foo.h']
|
||||||
|
call assert_equal(expected, sort(glob('Xtestglob/**/foo.{h,cpp}', 0, 1)))
|
||||||
|
call delete('Xtestglob', 'rf')
|
||||||
|
let &shell=_shell
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -379,7 +379,8 @@ endfunc
|
|||||||
" Test verbose message before echo command
|
" Test verbose message before echo command
|
||||||
func Test_echo_verbose_system()
|
func Test_echo_verbose_system()
|
||||||
CheckRunVimInTerminal
|
CheckRunVimInTerminal
|
||||||
CheckUnix
|
CheckUnix " needs the "seq" command
|
||||||
|
CheckNotMac " doesn't use /tmp
|
||||||
|
|
||||||
let buf = RunVimInTerminal('', {'rows': 10})
|
let buf = RunVimInTerminal('', {'rows': 10})
|
||||||
call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>")
|
call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>")
|
||||||
|
Reference in New Issue
Block a user