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


*** ../vim-7.3.446/src/os_win32.c	2012-02-19 18:19:24.000000000 +0100
--- src/os_win32.c	2012-02-21 20:56:51.000000000 +0100
***************
*** 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);
  	    }
  	}
      }
  
*** ../vim-7.3.446/src/version.c	2012-02-20 22:18:23.000000000 +0100
--- src/version.c	2012-02-21 21:20:05.000000000 +0100
***************
*** 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    ///
