Patch 7.3.443 Problem: MS-Windows: 'shcf' and 'shellxquote' defaults are not very good. Solution: Make a better guess when 'shell' is set to "cmd.exe". (Ben Fritz) Files: src/option.c, runtime/doc/options.txt
#if defined(MSDOS) || defined(WIN3264) || defined(OS2) /* ! * Set 'shellcmdflag and 'shellquote' depending on the 'shell' option. * This is done after other initializations, where 'shell' might have been * set, but only if they have not been set before. Default for p_shcf is * "/c", for p_shq is "". For "sh" like shells it is changed here to --- 3883,3890 ----
#if defined(MSDOS) || defined(WIN3264) || defined(OS2) /* ! * Set 'shellcmdflag', 'shellxquote', and 'shellquote' depending on the ! * 'shell' option. * This is done after other initializations, where 'shell' might have been * set, but only if they have not been set before. Default for p_shcf is * "/c", for p_shq is "". For "sh" like shells it is changed here to *************** *** 3920,3925 **** --- 3921,3962 ---- # endif # endif } + else if (strstr((char *)gettail(p_sh), "cmd.exe") != NULL) + { + int idx3; + + /* + * cmd.exe on Windows will strip the first and last double quote given + * on the command line, e.g. most of the time things like: + * cmd /c "my path/to/echo" "my args to echo" + * become: + * my path/to/echo" "my args to echo + * when executed. + * + * To avoid this, use the /s argument in addition to /c to force the + * stripping behavior, and also set shellxquote to automatically + * surround the entire command in quotes (which get stripped as + * noted). + */ + + /* Set shellxquote default to add the quotes to be stripped. */ + idx3 = findoption((char_u *)"sxq"); + if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET)) + { + p_sxq = (char_u *)"\""; + options[idx3].def_val[VI_DEFAULT] = p_sxq; + } + + /* Set shellcmdflag default to always strip the quotes, note the order + * between /s and /c is important or cmd.exe will treat the /s as part + * of the command to be executed. */ + idx3 = findoption((char_u *)"shcf"); + if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET)) + { + p_shcf = (char_u *)"/s /c"; + options[idx3].def_val[VI_DEFAULT] = p_shcf; + } + } #endif
*'shellcmdflag'* *'shcf'* ! 'shellcmdflag' 'shcf' string (default: "-c", MS-DOS and Win32, when 'shell' ! does not contain "sh" somewhere: "/c") global {not in Vi} Flag passed to the shell to execute "!" and ":!" commands; e.g., "bash.exe -c ls" or "command.com /c dir". For the MS-DOS-like systems, the default is set according to the value of 'shell', to reduce the need to set this option by the user. It's not used for ! OS/2 (EMX figures this out itself). See |option-backslash| about ! including spaces and backslashes. See |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons.
--- 5899,5919 ---- security reasons.
*'shellcmdflag'* *'shcf'* ! 'shellcmdflag' 'shcf' string (default: "-c"; ! Win32, when 'shell' is cmd.exe: "/s /c"; ! MS-DOS and Win32, when 'shell' neither is ! cmd.exe nor contains "sh" somewhere: "/c") global {not in Vi} Flag passed to the shell to execute "!" and ":!" commands; e.g., "bash.exe -c ls" or "command.com /c dir". For the MS-DOS-like systems, the default is set according to the value of 'shell', to reduce the need to set this option by the user. It's not used for ! OS/2 (EMX figures this out itself). ! On Unix it can have more than one flag. Each white space separated ! part is passed as an argument to the shell command. ! See |option-backslash| about including spaces and backslashes. ! Also see |dos-shell| for MS-DOS and MS-Windows. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons.
*************** *** 5910,5918 **** For Unix the default it "| tee". The stdout of the compiler is saved in a file and echoed to the screen. If the 'shell' option is "csh" or "tcsh" after initializations, the default becomes "|& tee". If the ! 'shell' option is "sh", "ksh", "zsh" or "bash" the default becomes ! "2>&1| tee". This means that stderr is also included. Before using ! the 'shell' option a path is removed, thus "/bin/sh" uses "sh". The initialization of this option is done after reading the ".vimrc" and the other initializations, so that when the 'shell' option is set there, the 'shellpipe' option changes automatically, unless it was --- 5934,5943 ---- For Unix the default it "| tee". The stdout of the compiler is saved in a file and echoed to the screen. If the 'shell' option is "csh" or "tcsh" after initializations, the default becomes "|& tee". If the ! 'shell' option is "sh", "ksh", "mksh", "pdksh", "zsh" or "bash" the ! default becomes "2>&1| tee". This means that stderr is also included. ! Before using the 'shell' option a path is removed, thus "/bin/sh" uses ! "sh". The initialization of this option is done after reading the ".vimrc" and the other initializations, so that when the 'shell' option is set there, the 'shellpipe' option changes automatically, unless it was *************** *** 6017,6024 ****
*'shellxquote'* *'sxq'* 'shellxquote' 'sxq' string (default: ""; ! for Win32, when 'shell' contains "sh" ! somewhere: "\"" for Unix, when using system(): "\"") global {not in Vi} --- 6043,6050 ----
*'shellxquote'* *'sxq'* 'shellxquote' 'sxq' string (default: ""; ! for Win32, when 'shell' is cmd.exe or ! contains "sh" somewhere: "\"" for Unix, when using system(): "\"") global {not in Vi} *************** *** 6026,6036 **** the "!" and ":!" commands. Includes the redirection. See 'shellquote' to exclude the redirection. It's probably not useful to set both options. ! This is an empty string by default. Known to be useful for ! third-party shells when using the Win32 version, such as the MKS Korn ! Shell or bash, where it should be "\"". The default is adjusted ! according the value of 'shell', to reduce the need to set this option ! by the user. See |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons.
--- 6052,6063 ---- the "!" and ":!" commands. Includes the redirection. See 'shellquote' to exclude the redirection. It's probably not useful to set both options. ! This is an empty string by default on most systems, but is known to be ! useful for on Win32 version, either for cmd.exe which automatically ! strips off the first and last quote on a command, or 3rd-party shells ! such as the MKS Korn Shell or bash, where it should be "\"". The ! default is adjusted according the value of 'shell', to reduce the need ! to set this option by the user. See |dos-shell|. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons.
*** ../vim-7.3.442/src/version.c 2012-02-12 20:13:55.000000000 +0100 --- src/version.c 2012-02-12 23:18:40.000000000 +0100 *************** *** 716,717 **** --- 716,719 ---- { /* Add new patch number below this line */ + /**/ + 443, /**/
This is the opposite of what the patch was fixing. What system is this on?
What were the option values before and after the patch?
Does it work OK without the /s argument?
-- hundred-and-one symptoms of being an internet addict: 51. You put a pillow case over your laptop so your lover doesn't see it while you are pretending to catch your breath.
This is actually correct, it just looks weird. The /s /c is supposed
to strip off the first and last " character before expanding, so the
command which actually gets executed is still:
The default values in the patch first turn it into:
""C:\Program Files\abc.exe" "some arg with spaces""
which cmd.exe /s /c treats as:
"C:\Program Files\abc.exe" "some arg with spaces"
as intended.
See cmd.exe /?
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic
is
used to process quote (") characters:
1. If all of the following conditions are met, then quote
characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()@^|
- there are one or more whitespace characters between the
the two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line,
preserving
any text after the last quote character.
> If /C or /K is specified, then the remainder of the command line after
> the switch is processed as a command line, where the following logic
> is
> used to process quote (") characters:
> 1. If all of the following conditions are met, then quote
> characters
> on the command line are preserved:
> - no /S switch
> - exactly two quote characters
> - no special characters between the two quote characters,
> where special is one of: &<>()@^|
> - there are one or more whitespace characters between the
> the two quote characters
> - the string between the two quote characters is the name
> of an executable file.
> 2. Otherwise, old behavior is to see if the first character is
> a quote character and if so, strip the leading character and
> remove the last quote character on the command line,
> preserving
> any text after the last quote character.- Hide quoted text -
It appears that cmd.exe is NOT behaving as documented.
C:\WINDOWS\system32\cmd.exe /s /c "echo "A&B""
A
'B""' is not recognized as an internal or external command,
operable program or batch file.
shell returned 1
Hit any key to close this window...
According to the cmd.exe help, a command with the /s flag given
explicitly does NOT fall in the first category. It falls into the
second, "otherwise..." category. However, it is being treated as the
first category, first executing "echo "A and then executing B"".
Experimenting on the cmd.exe window confirms:
U:\>cmd /c echo A & pause
A
Press any key to continue . . .
U:\>cmd /c "echo A & pause"
A
Press any key to continue . . .
U:\>cmd /c echo "A & pause"
"A & pause"
U:\>cmd /s /c echo "A & pause"
"A & pause"
U:\>cmd /s /c "echo "A & pause""
A
'pause""' is not recognized as an internal or external command,
operable program or batch file.
Fantastic. I wonder whether the "special characters" text in the
cmd.exe help is to blame.
Note, this works:
:!echo "A^&B"
U:\>cmd /s /c "echo "A ^& pause""
"A & pause"
(in cmd.exe, the escape character is ^ for some crazy reason or
another)
Maybe Vim can automatically add this ^ character somehow? This seems
like a job for shellescape().
As far as the patch is concerned, I still think it the right thing to
do. But we must ask, which is more likely to occur in a call to an
external program? The '&' character in an argument, or space
characters in the command path and argument?
On Feb 13, 10:01 am, Ben Fritz <fritzophre...@gmail.com> wrote:
> Maybe Vim can automatically add this ^ character somehow? This seems
> like a job for shellescape().
> As far as the patch is concerned, I still think it the right thing to
> do. But we must ask, which is more likely to occur in a call to an
> external program? The '&' character in an argument, or space
> characters in the command path and argument?- Hide quoted text -
Note in the original example:
let command = 'openssl dgst -binary -sha1 -hmac "A&B" < c:/temp/
foo.tmp'
let ret = system(command)
If this had been something like:
let command = '"C:\Program Files\OSSL\openssl" dgst -binary -sha1 -
hmac "A & B"'
let ret = system(command)
Then there is currently NO setting of shellxquote and shellcmdflag
that should work.
Does anybody see a problem with adding quoting of & with ^ in
shellescape? Some experimentation concerns me that things will break
if the user explicitly sets shellxquote back to empty, but if we
always use shellxquote=\" it will probably be OK:
> On Feb 13, 10:01 am, Ben Fritz <fritzophre...@gmail.com> wrote:
> > Maybe Vim can automatically add this ^ character somehow? This seems
> > like a job for shellescape().
> > As far as the patch is concerned, I still think it the right thing to
> > do. But we must ask, which is more likely to occur in a call to an
> > external program? The '&' character in an argument, or space
> > characters in the command path and argument?- Hide quoted text -
> Note in the original example:
> let command = 'openssl dgst -binary -sha1 -hmac "A&B" < c:/temp/
> foo.tmp'
> let ret = system(command)
> If this had been something like:
> let command = '"C:\Program Files\OSSL\openssl" dgst -binary -sha1 -
> hmac "A & B"'
> let ret = system(command)
> Then there is currently NO setting of shellxquote and shellcmdflag
> that should work.
> Does anybody see a problem with adding quoting of & with ^ in
> shellescape? Some experimentation concerns me that things will break
> if the user explicitly sets shellxquote back to empty, but if we
> always use shellxquote=\" it will probably be OK:
On Feb 13, 10:23 am, RoDo <royad...@gmail.com> wrote:
> Never know ^ before.
> But pipe work without ^.
> It's weird.
> Also set shellxquote=\" breaks gvim -d.
> The diff mode command should be changed too.
I've been using these values for shellxquote and shellcmdflag for a
long time now, and use vimdiff all the time. What's your diffexpr set
to, and from where? For a while there was one in vimrc_example.vim
which actually surrounded the entire command in quotes just like
shellcmdflag=\" does, which obviously caused problems when both were
done, but it seems to have been removed.
You are right.
I total forget about this.
I have a copy from vimrc_example which diffexpr set to MyDiff
function.
Remove it solve the problem. Thank you.
It's time to clean my _vimrc.
It's big and totally mess up.
On Feb 14, 12:33 am, Ben Fritz <fritzophre...@gmail.com> wrote:
> On Feb 13, 10:23 am, RoDo <royad...@gmail.com> wrote:
> > Never know ^ before.
> > But pipe work without ^.
> > It's weird.
> > Also set shellxquote=\" breaks gvim -d.
> > The diff mode command should be changed too.
> I've been using these values for shellxquote and shellcmdflag for a
> long time now, and use vimdiff all the time. What's your diffexpr set
> to, and from where? For a while there was one in vimrc_example.vim
> which actually surrounded the entire command in quotes just like
> shellcmdflag=\" does, which obviously caused problems when both were
> done, but it seems to have been removed.
> Patch 7.3.443 > Problem: MS-Windows: 'shcf' and 'shellxquote' defaults are not very good. > Solution: Make a better guess when 'shell' is set to "cmd.exe". (Ben Fritz) > Files: src/option.c, runtime/doc/options.txt
cmd.exe's quotes handling is broken, Vim cannot fix it. (just my opinion)
On Feb 13, 12:14 pm, Andy Wokula <anw...@yahoo.de> wrote:
> Am 12.02.2012 23:23, schrieb Bram Moolenaar:
> > Patch 7.3.443
> > Problem: MS-Windows: 'shcf' and 'shellxquote' defaults are not very good.
> > Solution: Make a better guess when 'shell' is set to "cmd.exe". (Ben Fritz)
> > Files: src/option.c, runtime/doc/options.txt
> cmd.exe's quotes handling is broken, Vim cannot fix it.
> (just my opinion)
Ugh, apparently so. I thought the documentation of cmd.exe was clear
enough to prevent this sort of thing, but that's apparently irrelevant
because cmd.exe doesn't follow it.
> C:\>("C:\Program Files\abc.exe" "some arg with spaces")
> If it works ok, a note in the help would be sufficient ...
An interesting idea, using parenthesis. The page you reference says
the parentheses are used "to group or nest multiple commands", so it's
not really the intended purpose, but perhaps it will work.
Also from the page you reference:
"The ampersand (&), pipe (|), and parentheses ( ) are special
characters that must be preceded by the escape character (^) or
quotation marks when you pass them as arguments."
Plugin authors should be correct in passing "A&B" to an external
command, without quoting. cmd.exe is doing the incorrect thing here, I
think. I think it best to try to get the command to work in the most
common cases.
So we have:
shellxquote=\" and shellcmdflag=/s\ /c (new default) breaks passing
arguments with & (and possibly |) unless the user knows to escape them
with ^.
shellxquote= and shellcmdflag=/c (previous default) breaks using
programs with a space in the path and a space in the argument, unless
the user knows to surround with parentheses (or quotes like
shellxquote does).
I'm not sure which use is more common. Either way, I agree adding a
help note may allow users and plugin authors to work around the issue.
Obviously the new value breaks backwards compatibility with plugins
which currently pass '&' inside arguments to external programs, even
if they have correctly quoted it. But, I've seen a few plugins in the
past (including, if I recall correctly, Taglist, and also
http://www.vim.org/scripts/script.php?script_id=2378) which fell
victim to the problem fixed by this patch.
It does look like using parentheses should allow the & character to be
used properly inside quoted arguments without escaping, also if the
paths or argument contains spaces.
I wonder how the shell redirection might play into using parentheses.
shellxquote includes the stuff added for redirection, whereas user-
added parentheses will not.
Ben Fritz wrote: > On Feb 13, 12:14 pm, Andy Wokula <anw...@yahoo.de> wrote: > > Am 12.02.2012 23:23, schrieb Bram Moolenaar:
> > > Patch 7.3.443 > > > Problem: MS-Windows: 'shcf' and 'shellxquote' defaults are not very good. > > > Solution: Make a better guess when 'shell' is set to "cmd.exe". (Ben Fritz) > > > Files: src/option.c, runtime/doc/options.txt
> > cmd.exe's quotes handling is broken, Vim cannot fix it. > > (just my opinion)
> Ugh, apparently so. I thought the documentation of cmd.exe was clear > enough to prevent this sort of thing, but that's apparently irrelevant > because cmd.exe doesn't follow it.
Never trust Microsoft documentation, always verify it actually works that way. And then try it on different systems, they usually only think of the latest. I would like to support back to Windows XP.
> > I just found it, not sure how well that works.
> > C:\>("C:\Program Files\abc.exe" "some arg with spaces")
> > If it works ok, a note in the help would be sufficient ...
> An interesting idea, using parenthesis. The page you reference says > the parentheses are used "to group or nest multiple commands", so it's > not really the intended purpose, but perhaps it will work.
> Also from the page you reference:
> "The ampersand (&), pipe (|), and parentheses ( ) are special > characters that must be preceded by the escape character (^) or > quotation marks when you pass them as arguments."
> Plugin authors should be correct in passing "A&B" to an external > command, without quoting. cmd.exe is doing the incorrect thing here, I > think. I think it best to try to get the command to work in the most > common cases.
> So we have:
> shellxquote=\" and shellcmdflag=/s\ /c (new default) breaks passing > arguments with & (and possibly |) unless the user knows to escape them > with ^. > shellxquote= and shellcmdflag=/c (previous default) breaks using > programs with a space in the path and a space in the argument, unless > the user knows to surround with parentheses (or quotes like > shellxquote does).
> I'm not sure which use is more common. Either way, I agree adding a > help note may allow users and plugin authors to work around the issue. > Obviously the new value breaks backwards compatibility with plugins > which currently pass '&' inside arguments to external programs, even > if they have correctly quoted it. But, I've seen a few plugins in the > past (including, if I recall correctly, Taglist, and also > http://www.vim.org/scripts/script.php?script_id=2378) which fell > victim to the problem fixed by this patch.
> It does look like using parentheses should allow the & character to be > used properly inside quoted arguments without escaping, also if the > paths or argument contains spaces.
> I wonder how the shell redirection might play into using parentheses. > shellxquote includes the stuff added for redirection, whereas user- > added parentheses will not.
If we set shellxquote to '(', we could use the closing ')' automatically. Does that solve most problems? Please try it out with the examples previously given.
I do hope we can find a solution that doesn't break any existing scripts.
A command may intentionally use & and | to separate commands. Always escaping them will break this intentional use.
Unless we can find a solution soon, I think I'll revert that patch.
-- hundred-and-one symptoms of being an internet addict: 55. You ask your doctor to implant a gig in your brain.