Mercurial > vim
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 */ |