aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c94
-rw-r--r--src/nvim/ex_docmd.c20
-rw-r--r--src/nvim/os/shell.c51
3 files changed, 94 insertions, 71 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ea5dbc8a3f..df301f4266 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -10779,35 +10779,54 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1;
}
-static char **list_to_argv(list_T *args)
+static char **tv_to_argv(typval_T *cmd_tv, char **cmd)
{
- for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- if (arg->li_tv.v_type != VAR_STRING) {
- EMSG(_(e_invarg));
- return NULL;
+ if (cmd_tv->v_type == VAR_STRING) {
+ char *cmd_str = (char *)get_tv_string(cmd_tv);
+ if (cmd) {
+ *cmd = cmd_str;
}
+ return shell_build_argv(cmd_str, NULL);
+ }
+
+ if (cmd_tv->v_type != VAR_LIST) {
+ EMSG2(_(e_invarg2), "expected String or List");
+ return NULL;
}
- int argc = args->lv_len;
+ list_T *argl = cmd_tv->vval.v_list;
+ int argc = argl->lv_len;
if (!argc) {
EMSG(_("Argument vector must have at least one item"));
return NULL;
}
- assert(args->lv_first);
+ assert(argl->lv_first);
- const char_u *exe = get_tv_string(&args->lv_first->li_tv);
- if (!os_can_exe(exe, NULL)) {
+ const char_u *exe = get_tv_string_chk(&argl->lv_first->li_tv);
+ if (!exe || !os_can_exe(exe, NULL)) {
// String is not executable
- EMSG2(e_jobexe, exe);
+ if (exe) {
+ EMSG2(e_jobexe, exe);
+ }
return NULL;
}
+
+ if (cmd) {
+ *cmd = (char *)exe;
+ }
// Build the argument vector
int i = 0;
char **argv = xcalloc(argc + 1, sizeof(char *));
- for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- argv[i++] = xstrdup((char *) get_tv_string(&arg->li_tv));
+ for (listitem_T *arg = argl->lv_first; arg != NULL; arg = arg->li_next) {
+ char *a = (char *)get_tv_string_chk(&arg->li_tv);
+ if (!a) {
+ // Did emsg in get_tv_string; just deallocate argv.
+ shell_free_argv(argv);
+ return NULL;
+ }
+ argv[i++] = xstrdup(a);
}
return argv;
@@ -10823,16 +10842,16 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
return;
}
- if (argvars[0].v_type != VAR_LIST
- || (argvars[1].v_type != VAR_DICT && argvars[1].v_type != VAR_UNKNOWN)) {
- // Wrong argument types
- EMSG(_(e_invarg));
- return;
+ char **argv = tv_to_argv(&argvars[0], NULL);
+ if (!argv) {
+ return; // Did error message in tv_to_argv.
}
- char **argv = list_to_argv(argvars[0].vval.v_list);
- if (!argv) {
- return; // Did error message in list_to_argv.
+ if (argvars[1].v_type != VAR_DICT && argvars[1].v_type != VAR_UNKNOWN) {
+ // Wrong argument types
+ EMSG2(_(e_invarg2), "expected dictionary");
+ shell_free_argv(argv);
+ return;
}
dict_T *job_opts = NULL;
@@ -10840,6 +10859,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
+ shell_free_argv(argv);
return;
}
}
@@ -14935,12 +14955,16 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
}
// get shell command to execute
- const char *cmd = (char *) get_tv_string(&argvars[0]);
+ char **argv = tv_to_argv(&argvars[0], NULL);
+ if (!argv) {
+ xfree(input);
+ return; // Already did emsg.
+ }
// execute the command
size_t nread = 0;
char *res = NULL;
- int status = os_system(cmd, input, input_len, &res, &nread);
+ int status = os_system(argv, input, input_len, &res, &nread);
xfree(input);
@@ -15163,16 +15187,17 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
return;
}
- if (argvars[0].v_type != VAR_LIST
- || (argvars[1].v_type != VAR_DICT && argvars[1].v_type != VAR_UNKNOWN)) {
- // Wrong argument types
- EMSG(_(e_invarg));
- return;
+ char *cmd;
+ char **argv = tv_to_argv(&argvars[0], &cmd);
+ if (!argv) {
+ return; // Did error message in tv_to_argv.
}
- char **argv = list_to_argv(argvars[0].vval.v_list);
- if (!argv) {
- return; // Did error message in list_to_argv.
+ if (argvars[1].v_type != VAR_DICT && argvars[1].v_type != VAR_UNKNOWN) {
+ // Wrong argument type
+ EMSG2(_(e_invarg2), "expected dictionary");
+ shell_free_argv(argv);
+ return;
}
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
@@ -15180,6 +15205,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
+ shell_free_argv(argv);
return;
}
}
@@ -15192,6 +15218,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
opts.term_name = xstrdup("xterm-256color");
Job *job = common_job_start(opts, rettv);
if (!job) {
+ shell_free_argv(argv);
return;
}
TerminalJobData *data = opts.data;
@@ -15212,10 +15239,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
// Get the desired name of the buffer.
char *name = job_opts ?
- (char *)get_dict_string(job_opts, (char_u *)"name", false) : NULL;
- if (!name) {
- name = argv[0];
- }
+ (char *)get_dict_string(job_opts, (char_u *)"name", false) : cmd;
char buf[1024];
// format the title with the pid to conform with the term:// URI
snprintf(buf, sizeof(buf), "term://%s//%d:%s", cwd, pid, name);
@@ -15233,6 +15257,8 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
Terminal *term = terminal_open(topts);
data->term = term;
data->refcount++;
+
+ return;
}
/*
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 656311ae14..9ff19521b6 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -9410,23 +9410,19 @@ static void ex_folddo(exarg_T *eap)
static void ex_terminal(exarg_T *eap)
{
- char *name = NULL;
- char cmd[512];
- if (strcmp((char *)eap->arg, "") == 0) {
- snprintf(cmd, sizeof(cmd), "['%s']", (char *)p_sh);
- name = (char *)p_sh;
- } else {
- // Escape quotes and slashes so they get sent literally.
+ // We will call termopen() with ['shell'] if not given a {cmd}.
+ char *name = (char *)p_sh;
+ char *lquote = "['";
+ char *rquote = "']";
+ if (*eap->arg != NUL) {
name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
- snprintf(cmd, sizeof(cmd), "['%s','%s',\"%s\"]",
- (char *)p_sh, (char *)p_shcf, name);
+ lquote = rquote = "\"";
}
char ex_cmd[512];
snprintf(ex_cmd, sizeof(ex_cmd),
- ":enew%s | call termopen(%s, {'name':\"%s\"}) | startinsert",
- eap->forceit==TRUE ? "!" : "", cmd, name);
-
+ ":enew%s | call termopen(%s%s%s) | startinsert",
+ eap->forceit==TRUE ? "!" : "", lquote, name, rquote);
do_cmdline_cmd((uint8_t *)ex_cmd);
if (name != (char *)p_sh) {
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 4f5928ba8a..5859254c1b 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -119,14 +119,14 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
}
size_t nread;
- int status = shell((const char *)cmd,
- (const char *)extra_args,
- input.data,
- input.len,
- output_ptr,
- &nread,
- emsg_silent,
- forward_output);
+
+ int status = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args),
+ input.data,
+ input.len,
+ output_ptr,
+ &nread,
+ emsg_silent,
+ forward_output);
xfree(input.data);
@@ -152,9 +152,11 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
/// example:
/// char *output = NULL;
/// size_t nread = 0;
-/// int status = os_sytem("ls -la", NULL, 0, &output, &nread);
+/// char *argv[] = {"ls", "-la", NULL};
+/// int status = os_sytem(argv, NULL, 0, &output, &nread);
///
-/// @param cmd The full commandline to be passed to the shell
+/// @param argv The commandline arguments to be passed to the shell. `argv`
+/// will be consumed.
/// @param input The input to the shell (NULL for no input), passed to the
/// stdin of the resulting process.
/// @param len The length of the input buffer (not used if `input` == NULL)
@@ -166,23 +168,22 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
/// returned buffer is not NULL)
/// @return the return code of the process, -1 if the process couldn't be
/// started properly
-int os_system(const char *cmd,
+int os_system(char **argv,
const char *input,
size_t len,
char **output,
size_t *nread) FUNC_ATTR_NONNULL_ARG(1)
{
- return shell(cmd, NULL, input, len, output, nread, true, false);
+ return do_os_system(argv, input, len, output, nread, true, false);
}
-static int shell(const char *cmd,
- const char *extra_args,
- const char *input,
- size_t len,
- char **output,
- size_t *nread,
- bool silent,
- bool forward_output)
+static int do_os_system(char **argv,
+ const char *input,
+ size_t len,
+ char **output,
+ size_t *nread,
+ bool silent,
+ bool forward_output)
{
// the output buffer
DynamicBuffer buf = DYNAMIC_BUFFER_INIT;
@@ -197,7 +198,9 @@ static int shell(const char *cmd,
data_cb = NULL;
}
- char **argv = shell_build_argv(cmd, extra_args);
+ // Copy the program name in case we need to report an error.
+ char prog[MAXPATHL];
+ xstrlcpy(prog, argv[0], MAXPATHL);
int status;
JobOptions opts = JOB_OPTIONS_INIT;
@@ -211,11 +214,9 @@ static int shell(const char *cmd,
if (status <= 0) {
// Failed, probably due to `sh` not being executable
- ELOG("Couldn't start job, command: '%s', error code: '%d'",
- (cmd ? cmd : (char *)p_sh), status);
if (!silent) {
- MSG_PUTS(_("\nCannot execute shell "));
- msg_outtrans(p_sh);
+ MSG_PUTS(_("\nCannot execute "));
+ msg_outtrans((char_u *)prog);
msg_putchar('\n');
}
return -1;