[ros-diffs] [jmorlan] 39795: Handle quotes in a CMD /C or CMD /K argument properly.

jmorlan at svn.reactos.org jmorlan at svn.reactos.org
Fri Feb 27 19:09:34 CET 2009


Author: jmorlan
Date: Fri Feb 27 21:09:33 2009
New Revision: 39795

URL: http://svn.reactos.org/svn/reactos?rev=39795&view=rev
Log:
Handle quotes in a CMD /C or CMD /K argument properly.

Modified:
    trunk/reactos/base/shell/cmd/cmd.c

Modified: trunk/reactos/base/shell/cmd/cmd.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.c?rev=39795&r1=39794&r2=39795&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] Fri Feb 27 21:09:33 2009
@@ -1529,23 +1529,73 @@
 	RegCloseKey(hkey);
 }
 
+/* Get the command that comes after a /C or /K switch */
+static VOID
+GetCmdLineCommand(TCHAR *commandline, TCHAR *ptr, BOOL AlwaysStrip)
+{
+	TCHAR *LastQuote;
+
+	while (_istspace(*ptr))
+		ptr++;
+
+	/* Remove leading quote, find final quote */
+	if (*ptr == _T('"') &&
+	    (LastQuote = _tcsrchr(++ptr, _T('"'))) != NULL)
+	{
+		TCHAR *Space;
+		/* Under certain circumstances, all quotes are preserved.
+		 * CMD /? documents these conditions as follows:
+		 *  1. No /S switch
+		 *  2. Exactly two quotes
+		 *  3. No "special characters" between the quotes
+		 *     (CMD /? says &<>()@^| but parentheses did not
+		 *     trigger this rule when I tested them.)
+		 *  4. Whitespace exists between the quotes
+		 *  5. Enclosed string is an executable filename
+		 */
+		*LastQuote = _T('\0');
+		for (Space = ptr + 1; Space < LastQuote; Space++)
+		{
+			if (_istspace(*Space))                         /* Rule 4 */
+			{
+				if (!AlwaysStrip &&                        /* Rule 1 */
+				    !_tcspbrk(ptr, _T("\"&<>@^|")) &&      /* Rules 2, 3 */
+				    SearchForExecutable(ptr, commandline)) /* Rule 5 */
+				{
+					/* All conditions met: preserve both the quotes */
+					*LastQuote = _T('"');
+					_tcscpy(commandline, ptr - 1);
+					return;
+				}
+				break;
+			}
+		}
+
+		/* The conditions were not met: remove both the
+		 * leading quote and the last quote */
+		_tcscpy(commandline, ptr);
+		_tcscpy(&commandline[LastQuote - ptr], LastQuote + 1);
+		return;
+	}
+
+	/* No quotes; just copy */
+	_tcscpy(commandline, ptr);
+}
+
 /*
  * set up global initializations and process parameters
- *
- * argc - number of parameters to command.com
- * argv - command-line parameters
- *
  */
 static VOID
-Initialize (int argc, const TCHAR* argv[])
+Initialize()
 {
 	TCHAR commandline[CMDLINE_LENGTH];
 	TCHAR ModuleName[_MAX_PATH + 1];
-	INT i;
 	TCHAR lpBuffer[2];
 
 	//INT len;
-	//TCHAR *ptr, *cmdLine;
+	TCHAR *ptr, *cmdLine;
+	BOOL AlwaysStrip = FALSE;
+	BOOL ShowVersion = TRUE;
 
 	/* get version information */
 	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
@@ -1572,13 +1622,8 @@
 		NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
 	}
 
-
-	TRACE ("[command args:\n");
-	for (i = 0; i < argc; i++)
-	{
-		TRACE ("%d. %s\n", i, debugstr_aw(argv[i]));
-	}
-	TRACE ("]\n");
+	cmdLine = GetCommandLine();
+	TRACE ("[command args: %s]\n", debugstr_aw(cmdLine));
 
 	InitLocale ();
 
@@ -1594,22 +1639,22 @@
 	    SetEnvironmentVariable (_T("PROMPT"), _T("$P$G"));
 
 
-	if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2))
-	{
-		ConOutResPaging(TRUE,STRING_CMD_HELP8);
-		cmd_exit(0);
-	}
 	SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
 
 #ifdef INCLUDE_CMD_CHDIR
 	InitLastPath ();
 #endif
 
-	if (argc >= 2)
-	{
-		for (i = 1; i < argc; i++)
-		{
-			if (!_tcsicmp (argv[i], _T("/p")))
+	for (ptr = cmdLine; *ptr; ptr++)
+	{
+		if (*ptr == _T('/'))
+		{
+			if (ptr[1] == _T('?'))
+			{
+				ConOutResPaging(TRUE,STRING_CMD_HELP8);
+				cmd_exit(0);
+			}
+			else if (_totlower(ptr[1]) == _T('p'))
 			{
 				if (!IsExistingFile (_T("\\autoexec.bat")))
 				{
@@ -1626,56 +1671,38 @@
 				}
 				bCanExit = FALSE;
 			}
-			else if (!_tcsicmp (argv[i], _T("/c")))
+			else if (_totlower(ptr[1]) == _T('c'))
 			{
 				/* This just runs a program and exits */
-				++i;
-				if (i < argc)
-				{
-					_tcscpy (commandline, argv[i]);
-					while (++i < argc)
-					{
-						_tcscat (commandline, _T(" "));
-						_tcscat (commandline, argv[i]);
-					}
-
-					ParseCommandLine(commandline);
-					cmd_exit (ProcessInput (TRUE));
-				}
-				else
-				{
-					cmd_exit (0);
-				}
+				GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
+				ParseCommandLine(commandline);
+				cmd_exit (ProcessInput (TRUE));
 			}
-			else if (!_tcsicmp (argv[i], _T("/k")))
+			else if (_totlower(ptr[1]) == _T('k'))
 			{
 				/* This just runs a program and remains */
-				++i;
-				if (i < argc)
-				{
-					_tcscpy (commandline, _T("\""));
-					_tcscat (commandline, argv[i]);
-					_tcscat (commandline, _T("\""));
-					while (++i < argc)
-					{
-						_tcscat (commandline, _T(" "));
-						_tcscat (commandline, argv[i]);
-					}
-					ParseCommandLine(commandline);
-				}
+				GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
+				ParseCommandLine(commandline);
+				ShowVersion = FALSE;
+				break;
+			}
+			else if (_totlower(ptr[1]) == _T('s'))
+			{
+				AlwaysStrip = TRUE;
 			}
 #ifdef INCLUDE_CMD_COLOR
-			else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
+			else if (!_tcsnicmp(ptr, _T("/t:"), 3))
 			{
 				/* process /t (color) argument */
-				wDefColor = (WORD)_tcstoul (&argv[i][3], NULL, 16);
+				wDefColor = (WORD)_tcstoul(&ptr[3], &ptr, 16);
 				wColor = wDefColor;
 				SetScreenColor (wColor, TRUE);
 			}
 #endif
 		}
 	}
-    else
+
+	if (ShowVersion)
     {
         /* Display a simple version string */
         ConOutPrintf(_T("ReactOS Operating System [Version %s-%s]\n"), 
@@ -1710,7 +1737,7 @@
 }
 
 
-static VOID Cleanup (int argc, const TCHAR *argv[])
+static VOID Cleanup()
 {
 	/* run cmdexit.bat */
 	if (IsExistingFile (_T("cmdexit.bat")))
@@ -1782,13 +1809,13 @@
 	CMD_ModuleHandle = GetModuleHandle(NULL);
 
 	/* check switches on command-line */
-	Initialize(argc, argv);
+	Initialize();
 
 	/* call prompt routine */
 	nExitCode = ProcessInput(FALSE);
 
 	/* do the cleanup */
-	Cleanup(argc, argv);
+	Cleanup();
 
 	cmd_exit(nExitCode);
 	return(nExitCode);



More information about the Ros-diffs mailing list