# HG changeset patch # User Bram Moolenaar # Date 1396719880 -7200 # Node ID e5f1f2ea0b4a4834791924880f78272ef52eb087 # Parent 0c34ebb94be0044e8500e07f3bd3da2c883ccdba updated for version 7.4.248 Problem: Cannot distinguish between NL and NUL in output of system(). Solution: Add systemlist(). (ZyX) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2002,6 +2002,7 @@ synIDtrans( {synID}) Number translated synconcealed( {lnum}, {col}) List info about concealing synstack( {lnum}, {col}) List stack of syntax IDs at {lnum} and {col} system( {expr} [, {input}]) String output of shell command/filter {expr} +systemlist( {expr} [, {input}]) List output of shell command/filter {expr} tabpagebuflist( [{arg}]) List list of buffer numbers in tab page tabpagenr( [{arg}]) Number number of current or last tab page tabpagewinnr( {tabarg}[, {arg}]) @@ -5963,7 +5964,8 @@ synstack({lnum}, {col}) *synstack()* valid positions. system({expr} [, {input}]) *system()* *E677* - Get the output of the shell command {expr}. + Get the output of the shell command {expr} as a string. See + |systemlist()| to get the output as a List. When {input} is given and is a string this string is written to a file and passed as stdin to the command. The string is @@ -6011,6 +6013,16 @@ system({expr} [, {input}]) *system()* Use |:checktime| to force a check. +systemlist({expr} [, {input}]) *systemlist()* + Same as |system()|, but returns a |List| with lines (parts of + output separated by NL) with NULs transformed into NLs. Output + is the same as |readfile()| will output with {binary} argument + set to "b". + + Returns an empty string on error, so be careful not to run + into |E706|. + + tabpagebuflist([{arg}]) *tabpagebuflist()* The result is a |List|, where each item is the number of the buffer associated with each window in the current tab page. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -726,6 +726,7 @@ static void f_synIDtrans __ARGS((typval_ static void f_synstack __ARGS((typval_T *argvars, typval_T *rettv)); static void f_synconcealed __ARGS((typval_T *argvars, typval_T *rettv)); static void f_system __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_systemlist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_tabpagebuflist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_tabpagenr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_tabpagewinnr __ARGS((typval_T *argvars, typval_T *rettv)); @@ -837,6 +838,7 @@ static int searchpair_cmn __ARGS((typval static int search_cmn __ARGS((typval_T *argvars, pos_T *match_pos, int *flagsp)); static void setwinvar __ARGS((typval_T *argvars, typval_T *rettv, int off)); static int write_list __ARGS((FILE *fd, list_T *list, int binary)); +static void get_cmd_output_as_rettv __ARGS((typval_T *argvars, typval_T *rettv, int retlist)); #ifdef EBCDIC @@ -8139,6 +8141,7 @@ static struct fst {"synconcealed", 2, 2, f_synconcealed}, {"synstack", 2, 2, f_synstack}, {"system", 1, 2, f_system}, + {"systemlist", 1, 2, f_systemlist}, {"tabpagebuflist", 0, 1, f_tabpagebuflist}, {"tabpagenr", 0, 1, f_tabpagenr}, {"tabpagewinnr", 1, 2, f_tabpagewinnr}, @@ -18232,13 +18235,11 @@ f_synstack(argvars, rettv) #endif } -/* - * "system()" function - */ - static void -f_system(argvars, rettv) - typval_T *argvars; - typval_T *rettv; + static void +get_cmd_output_as_rettv(argvars, rettv, retlist) + typval_T *argvars; + typval_T *rettv; + int retlist; { char_u *res = NULL; char_u *p; @@ -18246,9 +18247,12 @@ f_system(argvars, rettv) char_u buf[NUMBUFLEN]; int err = FALSE; FILE *fd; - + list_T *list = NULL; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; if (check_restricted() || check_secure()) - goto done; + goto errret; if (argvars[1].v_type != VAR_UNKNOWN) { @@ -18259,14 +18263,14 @@ f_system(argvars, rettv) if ((infile = vim_tempname('i')) == NULL) { EMSG(_(e_notmp)); - goto done; + goto errret; } fd = mch_fopen((char *)infile, WRITEBIN); if (fd == NULL) { EMSG2(_(e_notopen), infile); - goto done; + goto errret; } if (argvars[1].v_type == VAR_LIST) { @@ -18279,7 +18283,7 @@ f_system(argvars, rettv) if (p == NULL) { fclose(fd); - goto done; /* type error; errmsg already given */ + goto errret; /* type error; errmsg already given */ } if (fwrite(p, STRLEN(p), 1, fd) != 1) err = TRUE; @@ -18289,52 +18293,128 @@ f_system(argvars, rettv) if (err) { EMSG(_("E677: Error writing temp file")); - goto done; - } - } - - res = get_cmd_output(get_tv_string(&argvars[0]), infile, - SHELL_SILENT | SHELL_COOKED); - + goto errret; + } + } + + if (retlist) + { + int len; + listitem_T *li; + char_u *s = NULL; + char_u *start; + char_u *end; + char_u *p; + int i; + + res = get_cmd_output(get_tv_string(&argvars[0]), infile, + SHELL_SILENT | SHELL_COOKED, &len); + if (res == NULL) + goto errret; + + list = list_alloc(); + if (list == NULL) + goto errret; + + for (i = 0; i < len; ++i) + { + start = res + i; + for (end = start; i < len && *end != NL; ++end) + ++i; + + s = vim_strnsave(start, (int)(end - start)); + if (s == NULL) + goto errret; + + for (p = s, end = s + (end - start); p < end; ++p) + if (*p == NUL) + *p = NL; + + li = listitem_alloc(); + if (li == NULL) + { + vim_free(s); + goto errret; + } + li->li_tv.v_type = VAR_STRING; + li->li_tv.vval.v_string = s; + list_append(list, li); + } + + rettv->v_type = VAR_LIST; + rettv->vval.v_list = list; + list = NULL; + } + else + { + res = get_cmd_output(get_tv_string(&argvars[0]), infile, + SHELL_SILENT | SHELL_COOKED, NULL); #ifdef USE_CR - /* translate into */ - if (res != NULL) - { - char_u *s; - - for (s = res; *s; ++s) - { - if (*s == CAR) - *s = NL; - } - } + /* translate into */ + if (res != NULL) + { + char_u *s; + + for (s = res; *s; ++s) + { + if (*s == CAR) + *s = NL; + } + } #else # ifdef USE_CRNL - /* translate into */ - if (res != NULL) - { - char_u *s, *d; - - d = res; - for (s = res; *s; ++s) - { - if (s[0] == CAR && s[1] == NL) - ++s; - *d++ = *s; - } - *d = NUL; - } -# endif -#endif - -done: + /* translate into */ + if (res != NULL) + { + char_u *s, *d; + + d = res; + for (s = res; *s; ++s) + { + if (s[0] == CAR && s[1] == NL) + ++s; + *d++ = *s; + } + *d = NUL; + } +# endif +#endif + rettv->vval.v_string = res; + res = NULL; + } + +errret: if (infile != NULL) { mch_remove(infile); vim_free(infile); } - rettv->v_type = VAR_STRING; - rettv->vval.v_string = res; + if (res != NULL) + vim_free(res); + if (list != NULL) + list_free(list, TRUE); +} + +/* + * "system()" function + */ + static void +f_system(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + get_cmd_output_as_rettv(argvars, rettv, FALSE); +} + +/* + * "systemlist()" function + */ + static void +f_systemlist(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + get_cmd_output_as_rettv(argvars, rettv, TRUE); } /* diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -4341,7 +4341,7 @@ find_locales() /* Find all available locales by running command "locale -a". If this * doesn't work we won't have completion. */ char_u *locale_a = get_cmd_output((char_u *)"locale -a", - NULL, SHELL_SILENT); + NULL, SHELL_SILENT, NULL); if (locale_a == NULL) return NULL; ga_init2(&locales_ga, sizeof(char_u *), 20); diff --git a/src/misc1.c b/src/misc1.c --- a/src/misc1.c +++ b/src/misc1.c @@ -10665,7 +10665,7 @@ expand_backtick(gap, pat, flags) else #endif buffer = get_cmd_output(cmd, NULL, - (flags & EW_SILENT) ? SHELL_SILENT : 0); + (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL); vim_free(cmd); if (buffer == NULL) return 0; @@ -10765,13 +10765,16 @@ addfile(gap, f, flags) /* * Get the stdout of an external command. + * If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not + * NULL store the length there. * Returns an allocated string, or NULL for error. */ char_u * -get_cmd_output(cmd, infile, flags) +get_cmd_output(cmd, infile, flags, ret_len) char_u *cmd; char_u *infile; /* optional input file name */ int flags; /* can be SHELL_SILENT */ + int *ret_len; { char_u *tempname; char_u *command; @@ -10841,7 +10844,7 @@ get_cmd_output(cmd, infile, flags) vim_free(buffer); buffer = NULL; } - else + else if (ret_len == NULL) { /* Change NUL into SOH, otherwise the string is truncated. */ for (i = 0; i < len; ++i) @@ -10850,6 +10853,8 @@ get_cmd_output(cmd, infile, flags) buffer[len] = NUL; /* make sure the buffer is terminated */ } + else + *ret_len = len; done: vim_free(tempname); diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -100,7 +100,7 @@ int unix_expandpath __ARGS((garray_T *ga void remove_duplicates __ARGS((garray_T *gap)); int gen_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)); void addfile __ARGS((garray_T *gap, char_u *f, int flags)); -char_u *get_cmd_output __ARGS((char_u *cmd, char_u *infile, int flags)); +char_u *get_cmd_output __ARGS((char_u *cmd, char_u *infile, int flags, int *ret_len)); void FreeWild __ARGS((int count, char_u **files)); int goto_im __ARGS((void)); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -735,6 +735,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 248, +/**/ 247, /**/ 246,