]> granicus.if.org Git - vim/commitdiff
patch 8.1.2115: MS-Windows: shell commands fail if &shell contains a space v8.1.2115
authorBram Moolenaar <Bram@vim.org>
Sat, 5 Oct 2019 10:09:32 +0000 (12:09 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 5 Oct 2019 10:09:32 +0000 (12:09 +0200)
Problem:    MS-Windows: shell commands fail if &shell contains a space.
Solution:   Use quotes instead of escaping. (closes #4920)

src/option.c
src/os_win32.c
src/testdir/test_startup.vim
src/testdir/test_system.vim
src/version.c
src/vimrun.c

index 3d408143e94dd1373ef769d4aafa951a84f07797..75ff3cdb2959aa397a68c48d949d91b9dfccddfd 100644 (file)
@@ -102,7 +102,26 @@ set_init_1(int clean_arg)
            || ((p = (char_u *)default_shell()) != NULL && *p != NUL)
 #endif
            )
+#if defined(MSWIN)
+    {
+       // For MS-Windows put the path in quotes instead of escaping spaces.
+       char_u      *cmd;
+       size_t      len;
+
+       if (vim_strchr(p, ' ') != NULL)
+       {
+           len = STRLEN(p) + 3;  // two quotes and a trailing NUL
+           cmd = alloc(len);
+           vim_snprintf((char *)cmd, len, "\"%s\"", p);
+           set_string_default("sh", cmd);
+           vim_free(cmd);
+       }
+       else
+           set_string_default("sh", p);
+    }
+#else
        set_string_default_esc("sh", p, TRUE);
+#endif
 
 #ifdef FEAT_WILDIGN
     /*
index 26005b24fc31c9cb14c228390d07bd9ac377f826..ce035570db8af6055152ad6384685fd5e37afde0 100644 (file)
@@ -4490,8 +4490,25 @@ mch_system_c(char *cmd, int options UNUSED)
 {
     int                ret;
     WCHAR      *wcmd;
+    char_u     *buf;
+    size_t     len;
+
+    // If the command starts and ends with double quotes, enclose the command
+    // in parentheses.
+    len = STRLEN(cmd);
+    if (len >= 2 && cmd[0] == '"' && cmd[len - 1] == '"')
+    {
+       len += 3;
+       buf = alloc(len);
+       if (buf == NULL)
+           return -1;
+       vim_snprintf((char *)buf, len, "(%s)", cmd);
+       wcmd = enc_to_utf16(buf, NULL);
+       free(buf);
+    }
+    else
+       wcmd = enc_to_utf16((char_u *)cmd, NULL);
 
-    wcmd = enc_to_utf16((char_u *)cmd, NULL);
     if (wcmd == NULL)
        return -1;
 
index ceee044ca35fc656f8571e39bb02ae74c24f87d8..f10eabb798698fb333eafc10bcb15d5ede1310a2 100644 (file)
@@ -574,11 +574,17 @@ func Test_set_shell()
     quit!
   [CODE]
 
-  let $SHELL = '/bin/with space/sh'
+  if has('win32')
+    let $SHELL = 'C:\with space\cmd.exe'
+    let expected = '"C:\with space\cmd.exe"'
+  else
+    let $SHELL = '/bin/with space/sh'
+    let expected = '/bin/with\ space/sh'
+  endif
+
   if RunVimPiped([], after, '', '')
     let lines = readfile('Xtestout')
-    " MS-Windows adds a space after the word
-    call assert_equal('/bin/with\ space/sh', lines[0])
+    call assert_equal(expected, lines[0])
   endif
   call delete('Xtestout')
 endfunc
index dfe36837236c698d3d3ea98a421b80ba09e86638..eabccfb371e0df26dd639df0c422cf71bbf94f02 100644 (file)
@@ -1,6 +1,7 @@
 " Tests for system() and systemlist()
 
 source shared.vim
+source check.vim
 
 func Test_System()
   if !has('win32')
@@ -112,3 +113,53 @@ func Test_system_exmode()
   let a = system(GetVimCommand() . cmd)
   call assert_notequal(0, v:shell_error)
 endfunc
+
+func Test_system_with_shell_quote()
+  CheckMSWindows
+
+  call mkdir('Xdir with spaces', 'p')
+  call system('copy "%COMSPEC%" "Xdir with spaces\cmd.exe"')
+
+  let shell_save = &shell
+  let shellxquote_save = &shellxquote
+  try
+    " Set 'shell' always needs noshellslash.
+    let shellslash_save = &shellslash
+    set noshellslash
+    let shell_tests = [
+          \ expand('$COMSPEC'),
+          \ '"' . fnamemodify('Xdir with spaces\cmd.exe', ':p') . '"',
+          \]
+    let &shellslash = shellslash_save
+
+    let sxq_tests = ['', '(', '"']
+
+    " Matrix tests: 'shell' * 'shellxquote'
+    for shell in shell_tests
+      let &shell = shell
+      for sxq in sxq_tests
+        let &shellxquote = sxq
+
+        let msg = printf('shell=%s shellxquote=%s', &shell, &shellxquote)
+
+        try
+          let out = 'echo 123'->system()
+        catch
+          call assert_report(printf('%s: %s', msg, v:exception))
+          continue
+        endtry
+
+        " On Windows we may get a trailing space and CR.
+        if out != "123 \n"
+          call assert_equal("123\n", out, msg)
+        endif
+
+      endfor
+    endfor
+
+  finally
+    let &shell = shell_save
+    let &shellxquote = shellxquote_save
+    call delete('Xdir with spaces', 'rf')
+  endtry
+endfunc
index 0673d7e7873137791d45a6d246f34fe2c9daffb5..b1bccb4f6b15b64ce126318c4217aa3fc2df25c8 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2115,
 /**/
     2114,
 /**/
index ece20f83926e36e7871701f3ffbec814e6f341bb..26c4aa4c6406a1760dbcfdb218842f10061d2fd6 100644 (file)
@@ -27,6 +27,8 @@
 main(void)
 {
     const wchar_t   *p;
+    wchar_t        *cmd;
+    size_t         cmdlen;
     int                    retval;
     int                    inquote = 0;
     int                    silent = 0;
@@ -63,16 +65,36 @@ main(void)
            ++p;
     }
 
-    /* Print the command, including quotes and redirection. */
+    // Print the command, including quotes and redirection.
     hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
     WriteConsoleW(hstdout, p, wcslen(p), &written, NULL);
     WriteConsoleW(hstdout, L"\r\n", 2, &written, NULL);
 
+    // If the command starts and ends with double quotes,
+    // Enclose the command in parentheses.
+    cmd = NULL;
+    cmdlen = wcslen(p);
+    if (cmdlen >= 2 && p[0] == L'"' && p[cmdlen - 1] == L'"')
+    {
+       cmdlen += 3;
+       cmd = (wchar_t *)malloc(cmdlen * sizeof(wchar_t));
+       if (cmd == NULL)
+       {
+           perror("vimrun malloc(): ");
+           return -1;
+       }
+       _snwprintf(cmd, cmdlen, L"(%s)", p);
+       p = cmd;
+    }
+
     /*
      * Do it!
      */
     retval = _wsystem(p);
 
+    if (cmd)
+       free(cmd);
+
     if (retval == -1)
        perror("vimrun system(): ");
     else if (retval != 0)