eval: executable(), exepath() accept strings only

Cherry-pick f_executable(), f_exepath(), check_for_string() from patch 8.2.2117.
Rename check_for_string() to tv_check_for_string().
7bb4e74c38

Close https://github.com/neovim/neovim/issues/13485
This commit is contained in:
Jan Edmund Lazo 2020-12-08 20:19:08 -05:00
parent 062576f679
commit 5ccc79e880
No known key found for this signature in database
GPG Key ID: 64915E6E9F735B15
11 changed files with 55 additions and 12 deletions

View File

@ -95,7 +95,6 @@ PRAGMA_DIAG_POP
static char *e_listarg = N_("E686: Argument of %s must be a List");
static char *e_stringreq = N_("E928: String required");
static char *e_invalwindow = N_("E957: Invalid window number");
/// Dummy va_list for passing to vim_snprintf
@ -1877,10 +1876,12 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *name = tv_get_string(&argvars[0]);
if (tv_check_for_string(&argvars[0]) == FAIL) {
return;
}
// Check in $PATH and also check directly if there is a directory name
rettv->vval.v_number = os_can_exe(name, NULL, true);
rettv->vval.v_number = os_can_exe(tv_get_string(&argvars[0]), NULL, true);
}
typedef struct {
@ -1984,10 +1985,13 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "exepath()" function
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *arg = tv_get_string(&argvars[0]);
if (tv_check_for_string(&argvars[0]) == FAIL) {
return;
}
char *path = NULL;
(void)os_can_exe(arg, &path, true);
(void)os_can_exe(tv_get_string(&argvars[0]), &path, true);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)path;

View File

@ -2953,6 +2953,19 @@ float_T tv_get_float(const typval_T *const tv)
return 0;
}
// Give an error and return FAIL unless "tv" is a non-empty string.
int tv_check_for_string(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
if (tv->v_type != VAR_STRING
|| tv->vval.v_string == NULL
|| *tv->vval.v_string == NUL) {
EMSG(_(e_stringreq));
return FAIL;
}
return OK;
}
/// Get the string value of a "stringish" VimL object.
///
/// @param[in] tv Object to get value of.

View File

@ -935,6 +935,7 @@ EXTERN char_u e_readonly[] INIT(= N_(
"E45: 'readonly' option is set (add ! to override)"));
EXTERN char_u e_readonlyvar[] INIT(= N_(
"E46: Cannot change read-only variable \"%.*s\""));
EXTERN char_u e_stringreq[] INIT(= N_("E928: String required"));
EXTERN char_u e_dictreq[] INIT(= N_("E715: Dictionary required"));
EXTERN char_u e_toomanyarg[] INIT(= N_(
"E118: Too many arguments for function: %s"));

View File

@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local eq, clear, call, iswin, write_file, command =
helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file,
helpers.command
local exc_exec = helpers.exc_exec
local eval = helpers.eval
describe('executable()', function()
@ -12,6 +13,16 @@ describe('executable()', function()
eq(1, call('executable', exe))
end)
it('fails for invalid values', function()
for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
end
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
end
end)
it('returns 0 for non-existent files', function()
eq(0, call('executable', 'no_such_file_exists_209ufq23f'))
end)

View File

@ -1,14 +1,28 @@
local helpers = require('test.functional.helpers')(after_each)
local eq, clear, call, iswin =
helpers.eq, helpers.clear, helpers.call, helpers.iswin
local command = helpers.command
local exc_exec = helpers.exc_exec
describe('exepath() (Windows)', function()
if not iswin() then return end -- N/A for Unix.
describe('exepath()', function()
before_each(clear)
it('fails for invalid values', function()
for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
end
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
end
end)
if iswin() then
it('append extension if omitted', function()
local filename = 'cmd'
local pathext = '.exe'
clear({env={PATHEXT=pathext}})
eq(call('exepath', filename..pathext), call('exepath', filename))
end)
end
end)

View File

View File

View File

View File

View File

View File