# HG changeset patch # User vimboss # Date 1215164651 0 # Node ID 5bbc2d6658adb0dd3c67dd80c59f3a7ade3ba3d6 # Parent a0c70314350fde9e0948e598fe57dddc6192468e updated for version 7.2a-013 diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1856,7 +1856,8 @@ setreg( {n}, {v}[, {opt}]) Number set re settabwinvar( {tabnr}, {winnr}, {varname}, {val}) set {varname} in window {winnr} in tab page {tabnr} to {val} setwinvar( {nr}, {varname}, {val}) set {varname} in window {nr} to {val} -shellescape( {string}) String escape {string} for use as shell +shellescape( {string} [, {special}]) + String escape {string} for use as shell command argument simplify( {filename}) String simplify filename as much as possible sin( {expr}) Float sine of {expr} @@ -4018,10 +4019,10 @@ mkdir({name} [, {path} [, {prot}]]) < *mode()* mode([expr]) Return a string that indicates the current mode. - If [expr] is supplied and it evaluates to a non-zero number or - a non-empty string, then the full mode is returned, otherwise - only the first letter is returned. Note that " " and "0" are - also non-empty strings. + If [expr] is supplied and it evaluates to a non-zero Number or + a non-empty String (|non-zero-arg|), then the full mode is + returned, otherwise only the first letter is returned. Note + that " " and "0" are also non-empty strings. n Normal no Operator-pending @@ -4941,19 +4942,23 @@ setwinvar({nr}, {varname}, {val}) *set :call setwinvar(1, "&list", 0) :call setwinvar(2, "myvar", "foobar") -shellescape({string}) *shellescape()* +shellescape({string} [, {special}]) *shellescape()* Escape {string} for use as shell command argument. On MS-Windows and MS-DOS, when 'shellslash' is not set, it - will enclose {string} double quotes and double all double + will enclose {string} in double quotes and double all double quotes within {string}. For other systems, it will enclose {string} in single quotes and replace all "'" with "'\''". - Example: > - :echo shellescape('c:\program files\vim') -< results in: - "c:\program files\vim" ~ - Example usage: > - :call system("chmod +x -- " . shellescape(expand("%"))) + When the {special} argument is present and it's a non-zero + Number or a non-empty String (|non-zero-arg|), then special + items such as "%", "#" and "" will be preceded by a + backslash. This backslash will be removed again by the |:!| + command. + Example of use with a |:!| command: > + :exe '!dir ' . shellescape(expand(''), 1) +< This results in a directory listing for the file under the + cursor. Example of use with |system()|: > + :call system("chmod +w -- " . shellescape(expand("%"))) simplify({filename}) *simplify()* @@ -5333,13 +5338,14 @@ system({expr} [, {input}]) *system()* passed as stdin to the command. The string is written as-is, you need to take care of using the correct line separators yourself. Pipes are not used. - Note: newlines in {expr} may cause the command to fail. The - characters in 'shellquote' and 'shellxquote' may also cause - trouble. + Note: Use |shellescape()| to escape special characters in a + command argument. Newlines in {expr} may cause the command to + fail. The characters in 'shellquote' and 'shellxquote' may + also cause trouble. This is not to be used for interactive commands. + The result is a String. Example: > - - :let files = system("ls") + :let files = system("ls " . shellescape(expand('%:h'))) < To make the result more system-independent, the shell output is filtered to replace with for Macintosh, and @@ -5559,11 +5565,13 @@ visualmode([expr]) *visualmode()* Visual mode that was used. If Visual mode is active, use |mode()| to get the Visual mode (e.g., in a |:vmap|). - - If [expr] is supplied and it evaluates to a non-zero number or - a non-empty string, then the Visual mode will be cleared and + *non-zero-arg* + If [expr] is supplied and it evaluates to a non-zero Number or + a non-empty String, then the Visual mode will be cleared and the old value is returned. Note that " " and "0" are also - non-empty strings, thus cause the mode to be cleared. + non-empty strings, thus cause the mode to be cleared. A List, + Dictionary or Float is not a Number or String, thus does not + cause the mode to be cleared. *winbufnr()* winbufnr({nr}) The result is a Number, which is the number of the buffer @@ -6738,8 +6746,10 @@ 7. Commands *expression-commands* Be careful to correctly escape special characters in file names. The |fnameescape()| function can be used - for this. Example: > + for Vim commands, |shellescape()| for |:!| commands. + Examples: > :execute "e " . fnameescape(filename) + :execute "!ls " . shellescape(expand('%:h'), 1) < Note: The executed string may be any command-line, but you cannot start or end a "while", "for" or "if" diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -462,6 +462,7 @@ static char_u *deref_func_name __ARGS((c static int get_func_tv __ARGS((char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict)); static int call_func __ARGS((char_u *name, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict)); static void emsg_funcname __ARGS((char *ermsg, char_u *name)); +static int non_zero_arg __ARGS((typval_T *argvars)); #ifdef FEAT_FLOAT static void f_abs __ARGS((typval_T *argvars, typval_T *rettv)); @@ -7611,7 +7612,7 @@ static struct fst {"setreg", 2, 3, f_setreg}, {"settabwinvar", 4, 4, f_settabwinvar}, {"setwinvar", 3, 3, f_setwinvar}, - {"shellescape", 1, 1, f_shellescape}, + {"shellescape", 1, 2, f_shellescape}, {"simplify", 1, 1, f_simplify}, #ifdef FEAT_FLOAT {"sin", 1, 1, f_sin}, @@ -8094,6 +8095,20 @@ emsg_funcname(ermsg, name) vim_free(p); } +/* + * Return TRUE for a non-zero Number and a non-empty String. + */ + static int +non_zero_arg(argvars) + typval_T *argvars; +{ + return ((argvars[0].v_type == VAR_NUMBER + && argvars[0].vval.v_number != 0) + || (argvars[0].v_type == VAR_STRING + && argvars[0].vval.v_string != NULL + && *argvars[0].vval.v_string != NUL)); +} + /********************************************* * Implementation of the built-in functions */ @@ -13480,10 +13495,9 @@ f_mode(argvars, rettv) buf[1] = 'o'; } - /* A zero number or empty string argument: return only major mode. */ - if (!(argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number != 0) - && !(argvars[0].v_type == VAR_STRING - && *get_tv_string(&argvars[0]) != NUL)) + /* Clear out the minor mode when the argument is not a non-zero number or + * non-empty string. */ + if (!non_zero_arg(&argvars[0])) buf[1] = NUL; rettv->vval.v_string = vim_strsave(buf); @@ -15684,7 +15698,8 @@ f_shellescape(argvars, rettv) typval_T *argvars; typval_T *rettv; { - rettv->vval.v_string = vim_strsave_shellescape(get_tv_string(&argvars[0])); + rettv->vval.v_string = vim_strsave_shellescape( + get_tv_string(&argvars[0]), non_zero_arg(&argvars[1])); rettv->v_type = VAR_STRING; } @@ -17273,9 +17288,7 @@ f_visualmode(argvars, rettv) rettv->vval.v_string = vim_strsave(str); /* A non-zero number or non-empty string argument: reset mode. */ - if ((argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number != 0) - || (argvars[0].v_type == VAR_STRING - && *get_tv_string(&argvars[0]) != NUL)) + if (non_zero_arg(&argvars[0])) curbuf->b_visual_mode_eval = NUL; #else rettv->vval.v_number = 0; /* return anything, it won't work anyway */ diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7059,8 +7059,8 @@ ex_splitview(eap) # ifdef FEAT_QUICKFIX /* A ":split" in the quickfix window works like ":new". Don't want two - * quickfix windows. */ - if (bt_quickfix(curbuf)) + * quickfix windows. But it's OK when doing ":tab split". */ + if (bt_quickfix(curbuf) && cmdmod.tab == 0) { if (eap->cmdidx == CMD_split) eap->cmdidx = CMD_new; @@ -9321,6 +9321,58 @@ ex_tag_cmd(eap, name) } /* + * Check "str" for starting with a special cmdline variable. + * If found return one of the SPEC_ values and set "*usedlen" to the length of + * the variable. Otherwise return -1 and "*usedlen" is unchanged. + */ + int +find_cmdline_var(src, usedlen) + char_u *src; + int *usedlen; +{ + int len; + int i; + static char *(spec_str[]) = { + "%", +#define SPEC_PERC 0 + "#", +#define SPEC_HASH 1 + "", /* cursor word */ +#define SPEC_CWORD 2 + "", /* cursor WORD */ +#define SPEC_CCWORD 3 + "", /* cursor path name */ +#define SPEC_CFILE 4 + "", /* ":so" file name */ +#define SPEC_SFILE 5 +#ifdef FEAT_AUTOCMD + "", /* autocommand file name */ +# define SPEC_AFILE 6 + "", /* autocommand buffer number */ +# define SPEC_ABUF 7 + "", /* autocommand match name */ +# define SPEC_AMATCH 8 +#endif +#ifdef FEAT_CLIENTSERVER + "" +# define SPEC_CLIENT 9 +#endif + }; +#define SPEC_COUNT (sizeof(spec_str) / sizeof(char *)) + + for (i = 0; i < SPEC_COUNT; ++i) + { + len = (int)STRLEN(spec_str[i]); + if (STRNCMP(src, spec_str[i], len) == 0) + { + *usedlen = len; + return i; + } + } + return -1; +} + +/* * Evaluate cmdline variables. * * change '%' to curbuf->b_ffname @@ -9360,34 +9412,6 @@ eval_vars(src, srcstart, usedlen, lnump, #ifdef FEAT_MODIFY_FNAME int skip_mod = FALSE; #endif - static char *(spec_str[]) = - { - "%", -#define SPEC_PERC 0 - "#", -#define SPEC_HASH 1 - "", /* cursor word */ -#define SPEC_CWORD 2 - "", /* cursor WORD */ -#define SPEC_CCWORD 3 - "", /* cursor path name */ -#define SPEC_CFILE 4 - "", /* ":so" file name */ -#define SPEC_SFILE 5 -#ifdef FEAT_AUTOCMD - "", /* autocommand file name */ -# define SPEC_AFILE 6 - "", /* autocommand buffer number */ -# define SPEC_ABUF 7 - "", /* autocommand match name */ -# define SPEC_AMATCH 8 -#endif -#ifdef FEAT_CLIENTSERVER - "" -# define SPEC_CLIENT 9 -#endif - }; -#define SPEC_COUNT (sizeof(spec_str) / sizeof(char *)) #if defined(FEAT_AUTOCMD) || defined(FEAT_CLIENTSERVER) char_u strbuf[30]; @@ -9400,13 +9424,8 @@ eval_vars(src, srcstart, usedlen, lnump, /* * Check if there is something to do. */ - for (spec_idx = 0; spec_idx < SPEC_COUNT; ++spec_idx) - { - *usedlen = (int)STRLEN(spec_str[spec_idx]); - if (STRNCMP(src, spec_str[spec_idx], *usedlen) == 0) - break; - } - if (spec_idx == SPEC_COUNT) /* no match */ + spec_idx = find_cmdline_var(src, usedlen); + if (spec_idx < 0) /* no match */ { *usedlen = 1; return NULL; diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -1262,16 +1262,19 @@ vim_strsave_escaped_ext(string, esc_char * Escape "string" for use as a shell argument with system(). * This uses single quotes, except when we know we need to use double qoutes * (MS-DOS and MS-Windows without 'shellslash' set). + * Also replace "%", "#" and things like "" when "do_special" is TRUE. * Returns the result in allocated memory, NULL if we have run out. */ char_u * -vim_strsave_shellescape(string) +vim_strsave_shellescape(string, do_special) char_u *string; + int do_special; { unsigned length; char_u *p; char_u *d; char_u *escaped_string; + int l; /* First count the number of extra bytes required. */ length = (unsigned)STRLEN(string) + 3; /* two quotes and a trailing NUL */ @@ -1287,6 +1290,11 @@ vim_strsave_shellescape(string) # endif if (*p == '\'') length += 3; /* ' => '\'' */ + if (do_special && find_cmdline_var(p, &l) >= 0) + { + ++length; /* insert backslash */ + p += l - 1; + } } /* Allocate memory for the result and fill it. */ @@ -1320,13 +1328,19 @@ vim_strsave_shellescape(string) # endif if (*p == '\'') { - *d++='\''; - *d++='\\'; - *d++='\''; - *d++='\''; + *d++ = '\''; + *d++ = '\\'; + *d++ = '\''; + *d++ = '\''; ++p; continue; } + if (do_special && find_cmdline_var(p, &l) >= 0) + { + *d++ = '\\'; /* insert backslash */ + while (--l >= 0) /* copy the var */ + *d++ = *p++; + } MB_COPY_CHAR(p, d); } @@ -2776,7 +2790,7 @@ get_special_key_code(name) return 0; } -#ifdef FEAT_CMDL_COMPL +#if defined(FEAT_CMDL_COMPL) || defined(PROTO) char_u * get_key_name(i) int i; @@ -2787,7 +2801,7 @@ get_key_name(i) } #endif -#ifdef FEAT_MOUSE +#if defined(FEAT_MOUSE) || defined(PROTO) /* * Look up the given mouse code to return the relevant information in the other * arguments. Return which button is down or was released. diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -46,6 +46,7 @@ int vim_mkdir_emsg __ARGS((char_u *name, FILE *open_exfile __ARGS((char_u *fname, int forceit, char *mode)); void update_topline_cursor __ARGS((void)); void exec_normal_cmd __ARGS((char_u *cmd, int remap, int silent)); +int find_cmdline_var __ARGS((char_u *src, int *usedlen)); char_u *eval_vars __ARGS((char_u *src, char_u *srcstart, int *usedlen, linenr_T *lnump, char_u **errormsg, int *escaped)); char_u *expand_sfile __ARGS((char_u *arg)); int put_eol __ARGS((FILE *fd)); diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -29,7 +29,7 @@ char_u *vim_strsave __ARGS((char_u *stri char_u *vim_strnsave __ARGS((char_u *string, int len)); char_u *vim_strsave_escaped __ARGS((char_u *string, char_u *esc_chars)); char_u *vim_strsave_escaped_ext __ARGS((char_u *string, char_u *esc_chars, int cc, int bsl)); -char_u *vim_strsave_shellescape __ARGS((char_u *string)); +char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special)); char_u *vim_strsave_up __ARGS((char_u *string)); char_u *vim_strnsave_up __ARGS((char_u *string, int len)); void vim_strup __ARGS((char_u *p)); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -677,6 +677,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 13, +/**/ 12, /**/ 11,