To: vim_dev@googlegroups.com Subject: Patch 7.4.248 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.248 Problem: Cannot distinguish between NL and NUL in output of system(). Solution: Add systemlist(). (ZyX) Files: runtime/doc/eval.txt, src/eval.c, src/ex_cmds2.c, src/misc1.c, src/proto/misc1.pro *** ../vim-7.4.247/runtime/doc/eval.txt 2014-04-05 18:55:40.471154309 +0200 --- runtime/doc/eval.txt 2014-04-05 19:03:05.419155281 +0200 *************** *** 2001,2006 **** --- 2002,2008 ---- 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}]) *************** *** 5950,5956 **** valid positions. system({expr} [, {input}]) *system()* *E677* ! Get the output of the shell command {expr}. 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 --- 5964,5971 ---- valid positions. system({expr} [, {input}]) *system()* *E677* ! 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 *************** *** 5998,6003 **** --- 6013,6028 ---- 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. *** ../vim-7.4.247/src/eval.c 2014-04-05 18:55:40.479154309 +0200 --- src/eval.c 2014-04-05 19:42:37.675160463 +0200 *************** *** 726,731 **** --- 726,732 ---- 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,842 **** --- 838,844 ---- 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,8144 **** --- 8141,8147 ---- {"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,18244 **** #endif } - /* - * "system()" function - */ static void ! f_system(argvars, rettv) typval_T *argvars; typval_T *rettv; { char_u *res = NULL; char_u *p; --- 18235,18245 ---- #endif } 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,18254 **** char_u buf[NUMBUFLEN]; int err = FALSE; FILE *fd; if (check_restricted() || check_secure()) ! goto done; if (argvars[1].v_type != VAR_UNKNOWN) { --- 18247,18258 ---- 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 errret; if (argvars[1].v_type != VAR_UNKNOWN) { *************** *** 18259,18272 **** if ((infile = vim_tempname('i')) == NULL) { EMSG(_(e_notmp)); ! goto done; } fd = mch_fopen((char *)infile, WRITEBIN); if (fd == NULL) { EMSG2(_(e_notopen), infile); ! goto done; } if (argvars[1].v_type == VAR_LIST) { --- 18263,18276 ---- if ((infile = vim_tempname('i')) == NULL) { EMSG(_(e_notmp)); ! goto errret; } fd = mch_fopen((char *)infile, WRITEBIN); if (fd == NULL) { EMSG2(_(e_notopen), infile); ! goto errret; } if (argvars[1].v_type == VAR_LIST) { *************** *** 18279,18285 **** if (p == NULL) { fclose(fd); ! goto done; /* type error; errmsg already given */ } if (fwrite(p, STRLEN(p), 1, fd) != 1) err = TRUE; --- 18283,18289 ---- if (p == NULL) { fclose(fd); ! goto errret; /* type error; errmsg already given */ } if (fwrite(p, STRLEN(p), 1, fd) != 1) err = TRUE; *************** *** 18289,18340 **** if (err) { EMSG(_("E677: Error writing temp file")); ! goto done; } } ! res = get_cmd_output(get_tv_string(&argvars[0]), infile, ! SHELL_SILENT | SHELL_COOKED); ! ! #ifdef USE_CR ! /* 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: if (infile != NULL) { mch_remove(infile); vim_free(infile); } ! rettv->v_type = VAR_STRING; ! rettv->vval.v_string = res; } /* --- 18293,18420 ---- if (err) { EMSG(_("E677: Error writing temp file")); ! 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; ! } ! } ! #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 + rettv->vval.v_string = res; + res = NULL; + } ! errret: if (infile != NULL) { mch_remove(infile); vim_free(infile); } ! 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); } /* *** ../vim-7.4.247/src/ex_cmds2.c 2013-11-09 03:31:45.000000000 +0100 --- src/ex_cmds2.c 2014-04-05 19:20:25.023157552 +0200 *************** *** 4341,4347 **** /* 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); if (locale_a == NULL) return NULL; ga_init2(&locales_ga, sizeof(char_u *), 20); --- 4341,4347 ---- /* 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); if (locale_a == NULL) return NULL; ga_init2(&locales_ga, sizeof(char_u *), 20); *** ../vim-7.4.247/src/misc1.c 2014-04-01 21:00:45.436733663 +0200 --- src/misc1.c 2014-04-05 19:21:36.603157708 +0200 *************** *** 10665,10671 **** else #endif buffer = get_cmd_output(cmd, NULL, ! (flags & EW_SILENT) ? SHELL_SILENT : 0); vim_free(cmd); if (buffer == NULL) return 0; --- 10665,10671 ---- else #endif buffer = get_cmd_output(cmd, NULL, ! (flags & EW_SILENT) ? SHELL_SILENT : 0, NULL); vim_free(cmd); if (buffer == NULL) return 0; *************** *** 10765,10777 **** /* * Get the stdout of an external command. * Returns an allocated string, or NULL for error. */ char_u * ! get_cmd_output(cmd, infile, flags) char_u *cmd; char_u *infile; /* optional input file name */ int flags; /* can be SHELL_SILENT */ { char_u *tempname; char_u *command; --- 10765,10780 ---- /* * 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, 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,10847 **** vim_free(buffer); buffer = NULL; } ! else { /* Change NUL into SOH, otherwise the string is truncated. */ for (i = 0; i < len; ++i) --- 10844,10850 ---- vim_free(buffer); buffer = NULL; } ! else if (ret_len == NULL) { /* Change NUL into SOH, otherwise the string is truncated. */ for (i = 0; i < len; ++i) *************** *** 10850,10855 **** --- 10853,10860 ---- buffer[len] = NUL; /* make sure the buffer is terminated */ } + else + *ret_len = len; done: vim_free(tempname); *** ../vim-7.4.247/src/proto/misc1.pro 2013-11-06 04:01:31.000000000 +0100 --- src/proto/misc1.pro 2014-04-05 19:06:26.427155720 +0200 *************** *** 100,106 **** 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)); void FreeWild __ARGS((int count, char_u **files)); int goto_im __ARGS((void)); /* vim: set ft=c : */ --- 100,106 ---- 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, int *ret_len)); void FreeWild __ARGS((int count, char_u **files)); int goto_im __ARGS((void)); /* vim: set ft=c : */ *** ../vim-7.4.247/src/version.c 2014-04-05 18:55:40.479154309 +0200 --- src/version.c 2014-04-05 19:07:12.447155821 +0200 *************** *** 736,737 **** --- 736,739 ---- { /* Add new patch number below this line */ + /**/ + 248, /**/ -- Tips for aliens in New York: Land anywhere. Central Park, anywhere. No one will care or indeed even notice. -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy" /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///