comparison src/os_win32.c @ 3361:6a03b0ea2e12 v7.3.447

updated for version 7.3.447 Problem: Win32: External commands with "start" do not work. Solution: Unescape part of the command. (Yasuhiro Matsumoto)
author Bram Moolenaar <bram@vim.org>
date Tue, 21 Feb 2012 21:22:44 +0100
parents 397e7e49bb0b
children 756d712b3118
comparison
equal deleted inserted replaced
3360:068bb8a58a4e 3361:6a03b0ea2e12
257 } 257 }
258 } 258 }
259 } 259 }
260 260
261 /* 261 /*
262 * Unescape characters in "p" that appear in "escaped".
263 */
264 static void
265 unescape_shellxquote(char_u *p, char_u *escaped)
266 {
267 int l = STRLEN(p);
268 int n;
269
270 while (*p != NUL)
271 {
272 if (*p == '^' && vim_strchr(escaped, p[1]) != NULL)
273 mch_memmove(p, p + 1, l--);
274 #ifdef FEAT_MBYTE
275 n = (*mb_ptr2len)(p);
276 #else
277 n = 1;
278 #endif
279 p += n;
280 l -= n;
281 }
282 }
283
284 /*
262 * Load library "name". 285 * Load library "name".
263 */ 286 */
264 HINSTANCE 287 HINSTANCE
265 vimLoadLib(char *name) 288 vimLoadLib(char *name)
266 { 289 {
3557 int c; 3580 int c;
3558 int noread_cnt = 0; 3581 int noread_cnt = 0;
3559 garray_T ga; 3582 garray_T ga;
3560 int delay = 1; 3583 int delay = 1;
3561 DWORD buffer_off = 0; /* valid bytes in buffer[] */ 3584 DWORD buffer_off = 0; /* valid bytes in buffer[] */
3585 char *p = NULL;
3562 3586
3563 SECURITY_ATTRIBUTES saAttr; 3587 SECURITY_ATTRIBUTES saAttr;
3564 3588
3565 /* Set the bInheritHandle flag so pipe handles are inherited. */ 3589 /* Set the bInheritHandle flag so pipe handles are inherited. */
3566 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 3590 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
3597 si.lpReserved2 = NULL; 3621 si.lpReserved2 = NULL;
3598 3622
3599 if (options & SHELL_READ) 3623 if (options & SHELL_READ)
3600 ga_init2(&ga, 1, BUFLEN); 3624 ga_init2(&ga, 1, BUFLEN);
3601 3625
3626 if (cmd != NULL)
3627 {
3628 p = (char *)vim_strsave((char_u *)cmd);
3629 if (p != NULL)
3630 unescape_shellxquote((char_u *)p, p_sxe);
3631 else
3632 p = cmd;
3633 }
3634
3602 /* Now, run the command */ 3635 /* Now, run the command */
3603 CreateProcess(NULL, /* Executable name */ 3636 CreateProcess(NULL, /* Executable name */
3604 cmd, /* Command to execute */ 3637 p, /* Command to execute */
3605 NULL, /* Process security attributes */ 3638 NULL, /* Process security attributes */
3606 NULL, /* Thread security attributes */ 3639 NULL, /* Thread security attributes */
3607 3640
3608 // this command can be litigeous, handle inheritence was 3641 // this command can be litigeous, handle inheritence was
3609 // deactivated for pending temp file, but, if we deactivate 3642 // deactivated for pending temp file, but, if we deactivate
3614 NULL, /* Environment */ 3647 NULL, /* Environment */
3615 NULL, /* Current directory */ 3648 NULL, /* Current directory */
3616 &si, /* Startup information */ 3649 &si, /* Startup information */
3617 &pi); /* Process information */ 3650 &pi); /* Process information */
3618 3651
3652 if (p != cmd)
3653 vim_free(p);
3619 3654
3620 /* Close our unused side of the pipes */ 3655 /* Close our unused side of the pipes */
3621 CloseHandle(g_hChildStd_IN_Rd); 3656 CloseHandle(g_hChildStd_IN_Rd);
3622 CloseHandle(g_hChildStd_OUT_Wr); 3657 CloseHandle(g_hChildStd_OUT_Wr);
3623 3658
3896 x = mch_system(p_sh, options); 3931 x = mch_system(p_sh, options);
3897 } 3932 }
3898 else 3933 else
3899 { 3934 {
3900 /* we use "command" or "cmd" to start the shell; slow but easy */ 3935 /* we use "command" or "cmd" to start the shell; slow but easy */
3901 char_u *newcmd; 3936 char_u *cmdbase = cmd;
3902 long_u cmdlen = ( 3937
3938 /* Skip a leading ", ( and "(. */
3939 if (*cmdbase == '"' )
3940 ++cmdbase;
3941 if (*cmdbase == '(')
3942 ++cmdbase;
3943
3944 if ((STRNICMP(cmdbase, "start", 5) == 0) && vim_iswhite(cmdbase[5]))
3945 {
3946 STARTUPINFO si;
3947 PROCESS_INFORMATION pi;
3948 DWORD flags = CREATE_NEW_CONSOLE;
3949 char_u *p;
3950
3951 si.cb = sizeof(si);
3952 si.lpReserved = NULL;
3953 si.lpDesktop = NULL;
3954 si.lpTitle = NULL;
3955 si.dwFlags = 0;
3956 si.cbReserved2 = 0;
3957 si.lpReserved2 = NULL;
3958
3959 cmdbase = skipwhite(cmdbase + 5);
3960 if ((STRNICMP(cmdbase, "/min", 4) == 0)
3961 && vim_iswhite(cmdbase[4]))
3962 {
3963 cmdbase = skipwhite(cmdbase + 4);
3964 si.dwFlags = STARTF_USESHOWWINDOW;
3965 si.wShowWindow = SW_SHOWMINNOACTIVE;
3966 }
3967 else if ((STRNICMP(cmdbase, "/b", 2) == 0)
3968 && vim_iswhite(cmdbase[2]))
3969 {
3970 cmdbase = skipwhite(cmdbase + 2);
3971 flags = CREATE_NO_WINDOW;
3972 si.dwFlags = STARTF_USESTDHANDLES;
3973 si.hStdInput = CreateFile("\\\\.\\NUL", // File name
3974 GENERIC_READ, // Access flags
3975 0, // Share flags
3976 NULL, // Security att.
3977 OPEN_EXISTING, // Open flags
3978 FILE_ATTRIBUTE_NORMAL, // File att.
3979 NULL); // Temp file
3980 si.hStdOutput = si.hStdInput;
3981 si.hStdError = si.hStdInput;
3982 }
3983
3984 /* Remove a trailing ", ) and )" if they have a match
3985 * at the start of the command. */
3986 if (cmdbase > cmd)
3987 {
3988 p = cmdbase + STRLEN(cmdbase);
3989 if (p > cmdbase && p[-1] == '"' && *cmd == '"')
3990 *--p = NUL;
3991 if (p > cmdbase && p[-1] == ')'
3992 && (*cmd =='(' || cmd[1] == '('))
3993 *--p = NUL;
3994 }
3995
3996 /*
3997 * Unescape characters in shellxescape. This is workaround for
3998 * /b option. Only redirect character should be unescaped.
3999 */
4000 unescape_shellxquote(cmdbase,
4001 (flags & CREATE_NEW_CONSOLE) ? p_sxe : "<>");
4002
4003 /*
4004 * Now, start the command as a process, so that it doesn't
4005 * inherit our handles which causes unpleasant dangling swap
4006 * files if we exit before the spawned process
4007 */
4008 if (CreateProcess(NULL, // Executable name
4009 cmdbase, // Command to execute
4010 NULL, // Process security attributes
4011 NULL, // Thread security attributes
4012 FALSE, // Inherit handles
4013 flags, // Creation flags
4014 NULL, // Environment
4015 NULL, // Current directory
4016 &si, // Startup information
4017 &pi)) // Process information
4018 x = 0;
4019 else
4020 {
4021 x = -1;
4022 #ifdef FEAT_GUI_W32
4023 EMSG(_("E371: Command not found"));
4024 #endif
4025 }
4026 if (si.hStdInput != NULL)
4027 {
4028 /* Close the handle to \\.\NUL */
4029 CloseHandle(si.hStdInput);
4030 }
4031 /* Close the handles to the subprocess, so that it goes away */
4032 CloseHandle(pi.hThread);
4033 CloseHandle(pi.hProcess);
4034 }
4035 else
4036 {
4037 char_u *newcmd;
4038 long_u cmdlen = (
3903 #ifdef FEAT_GUI_W32 4039 #ifdef FEAT_GUI_W32
3904 (allowPiping && !p_stmp ? 0 : STRLEN(vimrun_path)) + 4040 (allowPiping && !p_stmp ? 0 : STRLEN(vimrun_path)) +
3905 #endif 4041 #endif
3906 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10); 4042 STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10);
3907 4043
3908 newcmd = lalloc(cmdlen, TRUE); 4044 newcmd = lalloc(cmdlen, TRUE);
3909 if (newcmd != NULL) 4045 if (newcmd != NULL)
3910 {
3911 char_u *cmdbase = cmd;
3912
3913 /* Skip a leading ", ( and "(. */
3914 if (*cmdbase == '"' )
3915 ++cmdbase;
3916 if (*cmdbase == '(')
3917 ++cmdbase;
3918 if ((STRNICMP(cmdbase, "start", 5) == 0) && vim_iswhite(cmdbase[5]))
3919 {
3920 STARTUPINFO si;
3921 PROCESS_INFORMATION pi;
3922 DWORD flags = CREATE_NEW_CONSOLE;
3923
3924 si.cb = sizeof(si);
3925 si.lpReserved = NULL;
3926 si.lpDesktop = NULL;
3927 si.lpTitle = NULL;
3928 si.dwFlags = 0;
3929 si.cbReserved2 = 0;
3930 si.lpReserved2 = NULL;
3931
3932 cmdbase = skipwhite(cmdbase + 5);
3933 if ((STRNICMP(cmdbase, "/min", 4) == 0)
3934 && vim_iswhite(cmdbase[4]))
3935 {
3936 cmdbase = skipwhite(cmdbase + 4);
3937 si.dwFlags = STARTF_USESHOWWINDOW;
3938 si.wShowWindow = SW_SHOWMINNOACTIVE;
3939 }
3940 else if ((STRNICMP(cmdbase, "/b", 2) == 0)
3941 && vim_iswhite(cmdbase[2]))
3942 {
3943 cmdbase = skipwhite(cmdbase + 2);
3944 flags = CREATE_NO_WINDOW;
3945 si.dwFlags = STARTF_USESTDHANDLES;
3946 si.hStdInput = CreateFile("\\\\.\\NUL", // File name
3947 GENERIC_READ, // Access flags
3948 0, // Share flags
3949 NULL, // Security att.
3950 OPEN_EXISTING, // Open flags
3951 FILE_ATTRIBUTE_NORMAL, // File att.
3952 NULL); // Temp file
3953 si.hStdOutput = si.hStdInput;
3954 si.hStdError = si.hStdInput;
3955 }
3956
3957 /* When the command is in double quotes, but 'shellxquote' is
3958 * empty, keep the double quotes around the command.
3959 * Otherwise remove the double quotes, they aren't needed
3960 * here, because we don't use a shell to run the command. */
3961 if (cmdbase > cmd)
3962 {
3963 if (STRNCMP(cmd, p_sxq, cmd - cmdbase) != 0)
3964 {
3965 STRCPY(newcmd, cmd);
3966 }
3967 else
3968 {
3969 char_u *p;
3970
3971 STRCPY(newcmd, cmdbase);
3972 /* Remove a trailing ", ) and )" if they have a match
3973 * at the start of the command. */
3974 p = newcmd + STRLEN(newcmd);
3975 if (p > newcmd && p[-1] == '"' && *cmd == '"')
3976 *--p = NUL;
3977 if (p > newcmd && p[-1] == ')'
3978 && (*cmd =='(' || cmd[1] == '('))
3979 *--p = NUL;
3980 }
3981 }
3982
3983 /*
3984 * Now, start the command as a process, so that it doesn't
3985 * inherit our handles which causes unpleasant dangling swap
3986 * files if we exit before the spawned process
3987 */
3988 if (CreateProcess(NULL, // Executable name
3989 newcmd, // Command to execute
3990 NULL, // Process security attributes
3991 NULL, // Thread security attributes
3992 FALSE, // Inherit handles
3993 flags, // Creation flags
3994 NULL, // Environment
3995 NULL, // Current directory
3996 &si, // Startup information
3997 &pi)) // Process information
3998 x = 0;
3999 else
4000 {
4001 x = -1;
4002 #ifdef FEAT_GUI_W32
4003 EMSG(_("E371: Command not found"));
4004 #endif
4005 }
4006 if (si.hStdInput != NULL)
4007 {
4008 /* Close the handle to \\.\NUL */
4009 CloseHandle(si.hStdInput);
4010 }
4011 /* Close the handles to the subprocess, so that it goes away */
4012 CloseHandle(pi.hThread);
4013 CloseHandle(pi.hProcess);
4014 }
4015 else
4016 { 4046 {
4017 #if defined(FEAT_GUI_W32) 4047 #if defined(FEAT_GUI_W32)
4018 if (need_vimrun_warning) 4048 if (need_vimrun_warning)
4019 { 4049 {
4020 MessageBox(NULL, 4050 MessageBox(NULL,
4036 else 4066 else
4037 #endif 4067 #endif
4038 vim_snprintf((char *)newcmd, cmdlen, "%s %s %s", 4068 vim_snprintf((char *)newcmd, cmdlen, "%s %s %s",
4039 p_sh, p_shcf, cmd); 4069 p_sh, p_shcf, cmd);
4040 x = mch_system((char *)newcmd, options); 4070 x = mch_system((char *)newcmd, options);
4071 vim_free(newcmd);
4041 } 4072 }
4042 vim_free(newcmd);
4043 } 4073 }
4044 } 4074 }
4045 4075
4046 if (tmode == TMODE_RAW) 4076 if (tmode == TMODE_RAW)
4047 settmode(TMODE_RAW); /* set to raw mode */ 4077 settmode(TMODE_RAW); /* set to raw mode */