| To: vim_dev@googlegroups.com |
| Subject: Patch 7.3.447 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.3.447 (after 7.3.446) |
| Problem: Win32: External commands with "start" do not work. |
| Solution: Unescape part of the command. (Yasuhiro Matsumoto) |
| Files: src/os_win32.c |
| |
| |
| |
| |
| |
| *** 259,264 **** |
| --- 259,287 ---- |
| } |
| |
| /* |
| + * Unescape characters in "p" that appear in "escaped". |
| + */ |
| + static void |
| + unescape_shellxquote(char_u *p, char_u *escaped) |
| + { |
| + int l = STRLEN(p); |
| + int n; |
| + |
| + while (*p != NUL) |
| + { |
| + if (*p == '^' && vim_strchr(escaped, p[1]) != NULL) |
| + mch_memmove(p, p + 1, l--); |
| + #ifdef FEAT_MBYTE |
| + n = (*mb_ptr2len)(p); |
| + #else |
| + n = 1; |
| + #endif |
| + p += n; |
| + l -= n; |
| + } |
| + } |
| + |
| + /* |
| * Load library "name". |
| */ |
| HINSTANCE |
| |
| *** 3559,3564 **** |
| --- 3582,3588 ---- |
| garray_T ga; |
| int delay = 1; |
| DWORD buffer_off = 0; /* valid bytes in buffer[] */ |
| + char *p = NULL; |
| |
| SECURITY_ATTRIBUTES saAttr; |
| |
| |
| *** 3599,3607 **** |
| if (options & SHELL_READ) |
| ga_init2(&ga, 1, BUFLEN); |
| |
| /* Now, run the command */ |
| CreateProcess(NULL, /* Executable name */ |
| ! cmd, /* Command to execute */ |
| NULL, /* Process security attributes */ |
| NULL, /* Thread security attributes */ |
| |
| --- 3623,3640 ---- |
| if (options & SHELL_READ) |
| ga_init2(&ga, 1, BUFLEN); |
| |
| + if (cmd != NULL) |
| + { |
| + p = (char *)vim_strsave((char_u *)cmd); |
| + if (p != NULL) |
| + unescape_shellxquote((char_u *)p, p_sxe); |
| + else |
| + p = cmd; |
| + } |
| + |
| /* Now, run the command */ |
| CreateProcess(NULL, /* Executable name */ |
| ! p, /* Command to execute */ |
| NULL, /* Process security attributes */ |
| NULL, /* Thread security attributes */ |
| |
| |
| *** 3616,3621 **** |
| --- 3649,3656 ---- |
| &si, /* Startup information */ |
| &pi); /* Process information */ |
| |
| + if (p != cmd) |
| + vim_free(p); |
| |
| /* Close our unused side of the pipes */ |
| CloseHandle(g_hChildStd_IN_Rd); |
| |
| *** 3898,4018 **** |
| else |
| { |
| /* we use "command" or "cmd" to start the shell; slow but easy */ |
| ! char_u *newcmd; |
| ! long_u cmdlen = ( |
| ! #ifdef FEAT_GUI_W32 |
| ! (allowPiping && !p_stmp ? 0 : STRLEN(vimrun_path)) + |
| ! #endif |
| ! STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10); |
| ! |
| ! newcmd = lalloc(cmdlen, TRUE); |
| ! if (newcmd != NULL) |
| ! { |
| ! char_u *cmdbase = cmd; |
| ! |
| ! /* Skip a leading ", ( and "(. */ |
| ! if (*cmdbase == '"' ) |
| ! ++cmdbase; |
| ! if (*cmdbase == '(') |
| ! ++cmdbase; |
| ! if ((STRNICMP(cmdbase, "start", 5) == 0) && vim_iswhite(cmdbase[5])) |
| ! { |
| ! STARTUPINFO si; |
| ! PROCESS_INFORMATION pi; |
| ! DWORD flags = CREATE_NEW_CONSOLE; |
| ! |
| ! si.cb = sizeof(si); |
| ! si.lpReserved = NULL; |
| ! si.lpDesktop = NULL; |
| ! si.lpTitle = NULL; |
| ! si.dwFlags = 0; |
| ! si.cbReserved2 = 0; |
| ! si.lpReserved2 = NULL; |
| ! |
| ! cmdbase = skipwhite(cmdbase + 5); |
| ! if ((STRNICMP(cmdbase, "/min", 4) == 0) |
| ! && vim_iswhite(cmdbase[4])) |
| ! { |
| ! cmdbase = skipwhite(cmdbase + 4); |
| ! si.dwFlags = STARTF_USESHOWWINDOW; |
| ! si.wShowWindow = SW_SHOWMINNOACTIVE; |
| ! } |
| ! else if ((STRNICMP(cmdbase, "/b", 2) == 0) |
| ! && vim_iswhite(cmdbase[2])) |
| ! { |
| ! cmdbase = skipwhite(cmdbase + 2); |
| ! flags = CREATE_NO_WINDOW; |
| ! si.dwFlags = STARTF_USESTDHANDLES; |
| ! si.hStdInput = CreateFile("\\\\.\\NUL", // File name |
| ! GENERIC_READ, // Access flags |
| ! 0, // Share flags |
| ! NULL, // Security att. |
| ! OPEN_EXISTING, // Open flags |
| ! FILE_ATTRIBUTE_NORMAL, // File att. |
| ! NULL); // Temp file |
| ! si.hStdOutput = si.hStdInput; |
| ! si.hStdError = si.hStdInput; |
| ! } |
| |
| ! /* When the command is in double quotes, but 'shellxquote' is |
| ! * empty, keep the double quotes around the command. |
| ! * Otherwise remove the double quotes, they aren't needed |
| ! * here, because we don't use a shell to run the command. */ |
| ! if (cmdbase > cmd) |
| ! { |
| ! if (STRNCMP(cmd, p_sxq, cmd - cmdbase) != 0) |
| ! { |
| ! STRCPY(newcmd, cmd); |
| ! } |
| ! else |
| ! { |
| ! char_u *p; |
| |
| ! STRCPY(newcmd, cmdbase); |
| ! /* Remove a trailing ", ) and )" if they have a match |
| ! * at the start of the command. */ |
| ! p = newcmd + STRLEN(newcmd); |
| ! if (p > newcmd && p[-1] == '"' && *cmd == '"') |
| ! *--p = NUL; |
| ! if (p > newcmd && p[-1] == ')' |
| ! && (*cmd =='(' || cmd[1] == '(')) |
| ! *--p = NUL; |
| ! } |
| ! } |
| |
| ! /* |
| ! * Now, start the command as a process, so that it doesn't |
| ! * inherit our handles which causes unpleasant dangling swap |
| ! * files if we exit before the spawned process |
| ! */ |
| ! if (CreateProcess(NULL, // Executable name |
| ! newcmd, // Command to execute |
| ! NULL, // Process security attributes |
| ! NULL, // Thread security attributes |
| ! FALSE, // Inherit handles |
| ! flags, // Creation flags |
| ! NULL, // Environment |
| ! NULL, // Current directory |
| ! &si, // Startup information |
| ! &pi)) // Process information |
| ! x = 0; |
| ! else |
| ! { |
| ! x = -1; |
| #ifdef FEAT_GUI_W32 |
| ! EMSG(_("E371: Command not found")); |
| #endif |
| - } |
| - if (si.hStdInput != NULL) |
| - { |
| - /* Close the handle to \\.\NUL */ |
| - CloseHandle(si.hStdInput); |
| - } |
| - /* Close the handles to the subprocess, so that it goes away */ |
| - CloseHandle(pi.hThread); |
| - CloseHandle(pi.hProcess); |
| } |
| ! else |
| { |
| #if defined(FEAT_GUI_W32) |
| if (need_vimrun_warning) |
| --- 3933,4048 ---- |
| else |
| { |
| /* we use "command" or "cmd" to start the shell; slow but easy */ |
| ! char_u *cmdbase = cmd; |
| |
| ! /* Skip a leading ", ( and "(. */ |
| ! if (*cmdbase == '"' ) |
| ! ++cmdbase; |
| ! if (*cmdbase == '(') |
| ! ++cmdbase; |
| ! |
| ! if ((STRNICMP(cmdbase, "start", 5) == 0) && vim_iswhite(cmdbase[5])) |
| ! { |
| ! STARTUPINFO si; |
| ! PROCESS_INFORMATION pi; |
| ! DWORD flags = CREATE_NEW_CONSOLE; |
| ! char_u *p; |
| ! |
| ! si.cb = sizeof(si); |
| ! si.lpReserved = NULL; |
| ! si.lpDesktop = NULL; |
| ! si.lpTitle = NULL; |
| ! si.dwFlags = 0; |
| ! si.cbReserved2 = 0; |
| ! si.lpReserved2 = NULL; |
| ! |
| ! cmdbase = skipwhite(cmdbase + 5); |
| ! if ((STRNICMP(cmdbase, "/min", 4) == 0) |
| ! && vim_iswhite(cmdbase[4])) |
| ! { |
| ! cmdbase = skipwhite(cmdbase + 4); |
| ! si.dwFlags = STARTF_USESHOWWINDOW; |
| ! si.wShowWindow = SW_SHOWMINNOACTIVE; |
| ! } |
| ! else if ((STRNICMP(cmdbase, "/b", 2) == 0) |
| ! && vim_iswhite(cmdbase[2])) |
| ! { |
| ! cmdbase = skipwhite(cmdbase + 2); |
| ! flags = CREATE_NO_WINDOW; |
| ! si.dwFlags = STARTF_USESTDHANDLES; |
| ! si.hStdInput = CreateFile("\\\\.\\NUL", // File name |
| ! GENERIC_READ, // Access flags |
| ! 0, // Share flags |
| ! NULL, // Security att. |
| ! OPEN_EXISTING, // Open flags |
| ! FILE_ATTRIBUTE_NORMAL, // File att. |
| ! NULL); // Temp file |
| ! si.hStdOutput = si.hStdInput; |
| ! si.hStdError = si.hStdInput; |
| ! } |
| ! |
| ! /* Remove a trailing ", ) and )" if they have a match |
| ! * at the start of the command. */ |
| ! if (cmdbase > cmd) |
| ! { |
| ! p = cmdbase + STRLEN(cmdbase); |
| ! if (p > cmdbase && p[-1] == '"' && *cmd == '"') |
| ! *--p = NUL; |
| ! if (p > cmdbase && p[-1] == ')' |
| ! && (*cmd =='(' || cmd[1] == '(')) |
| ! *--p = NUL; |
| ! } |
| |
| ! /* |
| ! * Unescape characters in shellxescape. This is workaround for |
| ! * /b option. Only redirect character should be unescaped. |
| ! */ |
| ! unescape_shellxquote(cmdbase, |
| ! (flags & CREATE_NEW_CONSOLE) ? p_sxe : "<>"); |
| |
| ! /* |
| ! * Now, start the command as a process, so that it doesn't |
| ! * inherit our handles which causes unpleasant dangling swap |
| ! * files if we exit before the spawned process |
| ! */ |
| ! if (CreateProcess(NULL, // Executable name |
| ! cmdbase, // Command to execute |
| ! NULL, // Process security attributes |
| ! NULL, // Thread security attributes |
| ! FALSE, // Inherit handles |
| ! flags, // Creation flags |
| ! NULL, // Environment |
| ! NULL, // Current directory |
| ! &si, // Startup information |
| ! &pi)) // Process information |
| ! x = 0; |
| ! else |
| ! { |
| ! x = -1; |
| #ifdef FEAT_GUI_W32 |
| ! EMSG(_("E371: Command not found")); |
| #endif |
| } |
| ! if (si.hStdInput != NULL) |
| ! { |
| ! /* Close the handle to \\.\NUL */ |
| ! CloseHandle(si.hStdInput); |
| ! } |
| ! /* Close the handles to the subprocess, so that it goes away */ |
| ! CloseHandle(pi.hThread); |
| ! CloseHandle(pi.hProcess); |
| ! } |
| ! else |
| ! { |
| ! char_u *newcmd; |
| ! long_u cmdlen = ( |
| ! #ifdef FEAT_GUI_W32 |
| ! (allowPiping && !p_stmp ? 0 : STRLEN(vimrun_path)) + |
| ! #endif |
| ! STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10); |
| ! |
| ! newcmd = lalloc(cmdlen, TRUE); |
| ! if (newcmd != NULL) |
| { |
| #if defined(FEAT_GUI_W32) |
| if (need_vimrun_warning) |
| |
| *** 4038,4045 **** |
| vim_snprintf((char *)newcmd, cmdlen, "%s %s %s", |
| p_sh, p_shcf, cmd); |
| x = mch_system((char *)newcmd, options); |
| } |
| - vim_free(newcmd); |
| } |
| } |
| |
| --- 4068,4075 ---- |
| vim_snprintf((char *)newcmd, cmdlen, "%s %s %s", |
| p_sh, p_shcf, cmd); |
| x = mch_system((char *)newcmd, options); |
| + vim_free(newcmd); |
| } |
| } |
| } |
| |
| |
| |
| |
| *** 716,717 **** |
| --- 716,719 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 447, |
| /**/ |
| |
| -- |
| From "know your smileys": |
| :----} You lie like Pinocchio |
| |
| /// 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 /// |