# HG changeset patch # User Bram Moolenaar # Date 1393195153 -3600 # Node ID 40f18a1c1592c8b4047f6f2a413557f48a99c55f # Parent 41fa1a18bc2eadcc4b701997c3337c1d3840aaab updated for version 7.4.191 Problem: Escaping a file name for shell commands can't be done without a function. Solution: Add the :S file name modifier. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -5428,6 +5428,7 @@ shellescape({string} [, {special}]) *s < This results in a directory listing for the file under the cursor. Example of use with |system()|: > :call system("chmod +w -- " . shellescape(expand("%"))) +< See also |::S|. shiftwidth() *shiftwidth()* @@ -5910,14 +5911,16 @@ 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: 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. + Note: Use |shellescape()| or |::S| with |expand()| or + |fnamemodify()| 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 " . shellescape(expand('%:h'))) + :let files = system('ls ' . expand('%:h:S')) < To make the result more system-independent, the shell output is filtered to replace with for Macintosh, and diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4757,8 +4757,9 @@ A jump table for the options with a shor global or local to buffer |global-local| {not in Vi} Program to use for the ":make" command. See |:make_makeprg|. - This option may contain '%' and '#' characters, which are expanded to - the current and alternate file name. |:_%| |:_#| + This option may contain '%' and '#' characters (see |:_%| and |:_#|), + which are expanded to the current and alternate file name. Use |::S| + to escape file names in case they contain special characters. Environment variables are expanded |:set_env|. See |option-backslash| about including spaces and backslashes. Note that a '|' must be escaped twice: once for ":set" and once for diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -838,7 +838,7 @@ Unfortunately, there is no standard way The alltests.py script seems to be used quite often, that's all. Useful values for the 'makeprg' options therefore are: setlocal makeprg=./alltests.py " Run a testsuite - setlocal makeprg=python % " Run a single testcase + setlocal makeprg=python\ %:S " Run a single testcase Also see http://vim.sourceforge.net/tip_view.php?tip_id=280. @@ -1332,7 +1332,7 @@ or: > Here is an alternative from Michael F. Lamb for Unix that filters the errors first: > :setl errorformat=%Z%f:%l:\ %m,%A%p^,%-G%*[^sl]%.%# - :setl makeprg=javac\ %\ 2>&1\ \\\|\ vim-javac-filter + :setl makeprg=javac\ %:S\ 2>&1\ \\\|\ vim-javac-filter You need to put the following in "vim-javac-filter" somewhere in your path (e.g., in ~/bin) and make it executable: > diff --git a/runtime/doc/usr_30.txt b/runtime/doc/usr_30.txt --- a/runtime/doc/usr_30.txt +++ b/runtime/doc/usr_30.txt @@ -128,7 +128,7 @@ be escaped with a backslash. Example: > You can include special Vim keywords in the command specification. The % character expands to the name of the current file. So if you execute the command: > - :set makeprg=make\ % + :set makeprg=make\ %:S When you are editing main.c, then ":make" executes the following command: > @@ -137,7 +137,7 @@ When you are editing main.c, then ":make This is not too useful, so you will refine the command a little and use the :r (root) modifier: > - :set makeprg=make\ %:r.o + :set makeprg=make\ %:r:S.o Now the command executed is as follows: > diff --git a/runtime/doc/usr_40.txt b/runtime/doc/usr_40.txt --- a/runtime/doc/usr_40.txt +++ b/runtime/doc/usr_40.txt @@ -209,7 +209,7 @@ The ":map" command can be followed by an separates the two commands. This also means that a | character can't be used inside a map command. To include one, use (five characters). Example: > - :map :write !checkin % + :map :write !checkin %:S The same problem applies to the ":unmap" command, with the addition that you have to watch out for trailing white space. These two commands are different: diff --git a/runtime/doc/usr_42.txt b/runtime/doc/usr_42.txt --- a/runtime/doc/usr_42.txt +++ b/runtime/doc/usr_42.txt @@ -311,7 +311,7 @@ redefine what these items do (after the item with a bitmap. For example, define a new toolbar item with: > :tmenu ToolBar.Compile Compile the current file - :amenu ToolBar.Compile :!cc % -o %:r + :amenu ToolBar.Compile :!cc %:S -o %:r:S Now you need to create the icon. For MS-Windows it must be in bitmap format, with the name "Compile.bmp". For Unix XPM format is used, the file name is diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt --- a/runtime/doc/vi_diff.txt +++ b/runtime/doc/vi_diff.txt @@ -540,7 +540,7 @@ character (and shows it immediately). Added :wnext command. Same as ":write" followed by ":next". The ":w!" command always writes, also when the file is write protected. In Vi -you would have to do ":!chmod +w %" and ":set noro". +you would have to do ":!chmod +w %:S" and ":set noro". When 'tildeop' has been set, "~" is an operator (must be followed by a movement command). diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -16950,7 +16950,7 @@ f_shellescape(argvars, rettv) typval_T *rettv; { rettv->vval.v_string = vim_strsave_shellescape( - get_tv_string(&argvars[0]), non_zero_arg(&argvars[1])); + get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE); rettv->v_type = VAR_STRING; } @@ -24355,6 +24355,17 @@ repeat: } } + if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') + { + p = vim_strsave_shellescape(*fnamep, FALSE, FALSE); + if (p == NULL) + return -1; + vim_free(*bufp); + *bufp = *fnamep = p; + *fnamelen = (int)STRLEN(p); + *usedlen += 2; + } + return valid; } diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -1369,12 +1369,14 @@ csh_like_shell() * Escape a newline, depending on the 'shell' option. * When "do_special" is TRUE also replace "!", "%", "#" and things starting * with "<" like "". + * When "do_newline" is FALSE do not escape newline unless it is csh shell. * Returns the result in allocated memory, NULL if we have run out. */ char_u * -vim_strsave_shellescape(string, do_special) +vim_strsave_shellescape(string, do_special, do_newline) char_u *string; int do_special; + int do_newline; { unsigned length; char_u *p; @@ -1403,7 +1405,8 @@ vim_strsave_shellescape(string, do_speci # endif if (*p == '\'') length += 3; /* ' => '\'' */ - if (*p == '\n' || (*p == '!' && (csh_like || do_special))) + if ((*p == '\n' && (csh_like || do_newline)) + || (*p == '!' && (csh_like || do_special))) { ++length; /* insert backslash */ if (csh_like && do_special) @@ -1454,7 +1457,8 @@ vim_strsave_shellescape(string, do_speci ++p; continue; } - if (*p == '\n' || (*p == '!' && (csh_like || do_special))) + if ((*p == '\n' && (csh_like || do_newline)) + || (*p == '!' && (csh_like || do_special))) { *d++ = '\\'; if (csh_like && do_special) diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -5790,7 +5790,7 @@ nv_ident(cap) { /* Escape the argument properly for a shell command */ ptr = vim_strnsave(ptr, n); - p = vim_strsave_shellescape(ptr, TRUE); + p = vim_strsave_shellescape(ptr, TRUE, TRUE); vim_free(ptr); if (p == NULL) { diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -32,7 +32,7 @@ char_u *vim_strnsave __ARGS((char_u *str 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)); int csh_like_shell __ARGS((void)); -char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special)); +char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special, int do_newline)); 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/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak --- a/src/testdir/Make_amiga.mak +++ b/src/testdir/Make_amiga.mak @@ -35,7 +35,7 @@ SCRIPTS = test1.out test3.out test4.out test89.out test90.out test91.out test92.out test93.out \ test94.out test95.out test96.out test97.out test98.out \ test99.out test100.out test101.out test102.out test103.out \ - test104.out + test104.out test105.out .SUFFIXES: .in .out @@ -156,3 +156,4 @@ test101.out: test101.in test102.out: test102.in test103.out: test103.in test104.out: test104.in +test105.out: test105.in diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak --- a/src/testdir/Make_dos.mak +++ b/src/testdir/Make_dos.mak @@ -33,7 +33,8 @@ SCRIPTS = test3.out test4.out test5.out test84.out test85.out test86.out test87.out test88.out \ test89.out test90.out test91.out test92.out test93.out \ test94.out test95.out test96.out test98.out test99.out \ - test100.out test101.out test102.out test103.out test104.out + test100.out test101.out test102.out test103.out test104.out \ + test105.out SCRIPTS32 = test50.out test70.out diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -53,7 +53,8 @@ SCRIPTS = test3.out test4.out test5.out test84.out test85.out test86.out test87.out test88.out \ test89.out test90.out test91.out test92.out test93.out \ test94.out test95.out test96.out test98.out test99.out \ - test100.out test101.out test102.out test103.out test104.out + test100.out test101.out test102.out test103.out test104.out \ + test105.out SCRIPTS32 = test50.out test70.out diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak --- a/src/testdir/Make_os2.mak +++ b/src/testdir/Make_os2.mak @@ -35,7 +35,8 @@ SCRIPTS = test1.out test3.out test4.out test81.out test82.out test83.out test84.out test88.out \ test89.out test90.out test91.out test92.out test93.out \ test94.out test95.out test96.out test98.out test99.out \ - test100.out test101.out test102.out test103.out test104.out + test100.out test101.out test102.out test103.out test104.out \ + test105.out .SUFFIXES: .in .out diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -4,7 +4,7 @@ # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # -# Last change: 2013 Nov 21 +# Last change: 2014 Feb 23 # # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64. # Edit the lines in the Configuration section below to select. @@ -79,7 +79,8 @@ SCRIPT = test1.out test2.out test3.out test82.out test83.out test84.out test88.out test89.out \ test90.out test91.out test92.out test93.out test94.out \ test95.out test96.out test97.out test98.out test99.out \ - test100.out test101.out test102.out test103.out test104.out + test100.out test101.out test102.out test103.out test104.out \ + test105.out # Known problems: # Test 30: a problem around mac format - unknown reason diff --git a/src/testdir/Makefile b/src/testdir/Makefile --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -31,7 +31,7 @@ SCRIPTS = test1.out test2.out test3.out test89.out test90.out test91.out test92.out test93.out \ test94.out test95.out test96.out test97.out test98.out \ test99.out test100.out test101.out test102.out test103.out \ - test104.out + test104.out test105.out SCRIPTS_GUI = test16.out diff --git a/src/testdir/test105.in b/src/testdir/test105.in new file mode 100644 --- /dev/null +++ b/src/testdir/test105.in @@ -0,0 +1,45 @@ +Test filename modifiers vim: set ft=vim : + +STARTTEST +:source small.vim +:%delete _ +:set shell=sh +:set shellslash +:let tab="\t" +:command -nargs=1 Put :let expr= | $put =expr.tab.strtrans(string(eval(expr))) +:let $HOME=fnamemodify('.', ':p:h:h:h') +:Put fnamemodify('.', ':p' )[-1:] +:Put fnamemodify('.', ':p:h' )[-1:] +:Put fnamemodify('test.out', ':p' )[-1:] +:Put fnamemodify('test.out', ':.' ) +:Put fnamemodify('../testdir/a', ':.' ) +:Put fnamemodify('test.out', ':~' ) +:Put fnamemodify('../testdir/a', ':~' ) +:Put fnamemodify('../testdir/a', ':t' ) +:Put fnamemodify('.', ':p:t' ) +:Put fnamemodify('test.out', ':p:t' ) +:Put fnamemodify('test.out', ':p:e' ) +:Put fnamemodify('test.out', ':p:t:e' ) +:Put fnamemodify('abc.fb2.tar.gz', ':r' ) +:Put fnamemodify('abc.fb2.tar.gz', ':r:r' ) +:Put fnamemodify('abc.fb2.tar.gz', ':r:r:r' ) +:Put substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/testdir/.*\)', '\1', '') +:Put fnamemodify('abc.fb2.tar.gz', ':e' ) +:Put fnamemodify('abc.fb2.tar.gz', ':e:e' ) +:Put fnamemodify('abc.fb2.tar.gz', ':e:e:e' ) +:Put fnamemodify('abc.fb2.tar.gz', ':e:e:e:e') +:Put fnamemodify('abc.fb2.tar.gz', ':e:e:r' ) +:Put fnamemodify('abc def', ':S' ) +:Put fnamemodify('abc" "def', ':S' ) +:Put fnamemodify('abc"%"def', ':S' ) +:Put fnamemodify('abc'' ''def', ':S' ) +:Put fnamemodify('abc''%''def', ':S' ) +:Put fnamemodify("abc\ndef", ':S' ) +:set shell=tcsh +:Put fnamemodify("abc\ndef", ':S' ) +:$put ='vim: ts=8' +:1 delete _ +:w! test.out +:qa! +ENDTEST + diff --git a/src/testdir/test105.ok b/src/testdir/test105.ok new file mode 100644 --- /dev/null +++ b/src/testdir/test105.ok @@ -0,0 +1,29 @@ +fnamemodify('.', ':p' )[-1:] '/' +fnamemodify('.', ':p:h' )[-1:] 'r' +fnamemodify('test.out', ':p' )[-1:] 't' +fnamemodify('test.out', ':.' ) 'test.out' +fnamemodify('../testdir/a', ':.' ) 'a' +fnamemodify('test.out', ':~' ) '~/src/testdir/test.out' +fnamemodify('../testdir/a', ':~' ) '~/src/testdir/a' +fnamemodify('../testdir/a', ':t' ) 'a' +fnamemodify('.', ':p:t' ) '' +fnamemodify('test.out', ':p:t' ) 'test.out' +fnamemodify('test.out', ':p:e' ) 'out' +fnamemodify('test.out', ':p:t:e' ) 'out' +fnamemodify('abc.fb2.tar.gz', ':r' ) 'abc.fb2.tar' +fnamemodify('abc.fb2.tar.gz', ':r:r' ) 'abc.fb2' +fnamemodify('abc.fb2.tar.gz', ':r:r:r' ) 'abc' +substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/testdir/.*\)', '\1', '') 'src/testdir/abc.fb2' +fnamemodify('abc.fb2.tar.gz', ':e' ) 'gz' +fnamemodify('abc.fb2.tar.gz', ':e:e' ) 'tar.gz' +fnamemodify('abc.fb2.tar.gz', ':e:e:e' ) 'fb2.tar.gz' +fnamemodify('abc.fb2.tar.gz', ':e:e:e:e') 'fb2.tar.gz' +fnamemodify('abc.fb2.tar.gz', ':e:e:r' ) 'tar' +fnamemodify('abc def', ':S' ) '''abc def''' +fnamemodify('abc" "def', ':S' ) '''abc" "def''' +fnamemodify('abc"%"def', ':S' ) '''abc"%"def''' +fnamemodify('abc'' ''def', ':S' ) '''abc''\'''' ''\''''def''' +fnamemodify('abc''%''def', ':S' ) '''abc''\''''%''\''''def''' +fnamemodify("abc\ndef", ':S' ) '''abc^@def''' +fnamemodify("abc\ndef", ':S' ) '''abc\^@def''' +vim: ts=8 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 191, +/**/ 190, /**/ 189,