aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c71
1 files changed, 45 insertions, 26 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 235f7526c2..114a6f8a59 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -14426,17 +14426,10 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
}
// get input to the shell command (if any), and its length
- char_u buf[NUMBUFLEN];
- const char *input = NULL;
- size_t input_len = 0;
- if (argvars[1].v_type == VAR_LIST) {
- input = write_list_to_string(argvars[1].vval.v_list, &input_len);
- } else if (argvars[1].v_type != VAR_UNKNOWN) {
- if ((input = (char *) get_tv_string_buf_chk(&argvars[1], buf))) {
- input_len = strlen(input);
- } else {
- return; // Type error handled in get_tv_string_buf_chk().
- }
+ ssize_t input_len;
+ char *input = (char *) save_tv_as_string(&argvars[1], &input_len);
+ if (input_len == -1) {
+ return;
}
// get shell command to execute
@@ -14447,15 +14440,11 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
char *res = NULL;
int status = os_system(cmd, input, input_len, &res, &nread);
- if (argvars[1].v_type == VAR_LIST) {
- free(input);
- }
+ free(input);
set_vim_var_nr(VV_SHELL_ERROR, (long) status);
if (res == NULL) {
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
return;
}
@@ -15135,24 +15124,54 @@ static bool write_list(FILE *fd, list_T *list, bool binary)
return ret;
}
-/// Like write_list, but to a string with an out-parameter for the length and
-/// always assumes binary.
-static char *write_list_to_string(list_T *list, size_t *len)
- FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- // Calculate the resulting length.
+/// Saves a typval_T as a string.
+///
+/// For lists, replaces NLs with NUL and separates items with NLs.
+///
+/// @param[in] tv A value to store as a string.
+/// @param[out] len The length of the resulting string or -1 on error.
+/// @returns an allocated string if `tv` represents a VimL string, list, or
+/// number; NULL otherwise.
+static char_u *save_tv_as_string(typval_T *tv, ssize_t *len)
+ FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
+{
+ if (tv->v_type == VAR_UNKNOWN) {
+ *len = 0;
+ return NULL;
+ }
+
+ // For types other than list, let get_tv_string_buf_chk() get the value or
+ // print an error.
+ if (tv->v_type != VAR_LIST) {
+ char_u *ret = get_tv_string_chk(tv);
+ if (ret && (*len = STRLEN(ret))) {
+ ret = vim_strsave(ret);
+ } else {
+ ret = NULL;
+ }
+ if (tv->v_type != VAR_STRING) {
+ *len = -1;
+ }
+ return ret;
+ }
+
+ // Pre-calculate the resulting length.
*len = 0;
+ list_T *list = tv->vval.v_list;
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
*len += STRLEN(get_tv_string(&li->li_tv)) + 1;
}
- char *ret = xmallocz(*len);
- char *end = ret;
+ if (*len == 0) {
+ return NULL;
+ }
+
+ char_u *ret = xmalloc(*len);
+ char_u *end = ret;
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
- for (char *s = (char *) get_tv_string(&li->li_tv); *s != NUL; s++) {
+ for (char_u *s = get_tv_string(&li->li_tv); *s != NUL; s++) {
*end++ = (*s == '\n') ? NUL : *s;
}
-
if (li->li_next != NULL) {
*end++ = '\n';
}