Commit f252e9df authored by Jason Edmeades's avatar Jason Edmeades Committed by Alexandre Julliard

cmd: Change command line parsing away from argv/argc.

parent a2db974d
...@@ -1861,7 +1861,12 @@ cmd.exe /c " echo passed2 " ...@@ -1861,7 +1861,12 @@ cmd.exe /c " echo passed2 "
echo --- Test 14 echo --- Test 14
cmd.exe /c "dir /ad ..\fooba* /b" cmd.exe /c "dir /ad ..\fooba* /b"
echo --- Test 15 echo --- Test 15
cmd.exe /cecho No whitespace
echo --- Test 16
cmd.exe /c
echo --- Test 17
cmd.exe /c@space@
echo --- Test 18
rem Ensure no interactive prompting when cmd.exe /c or /k rem Ensure no interactive prompting when cmd.exe /c or /k
echo file2 > file2 echo file2 > file2
cmd.exe /c copy file1 file2 >nul cmd.exe /c copy file1 file2 >nul
......
...@@ -910,23 +910,23 @@ value1 ...@@ -910,23 +910,23 @@ value1
------------ cmd.exe command lines ------------ ------------ cmd.exe command lines ------------
--- Test 1 --- Test 1
Line1 Line1
@todo_wine@"Line2" "Line2"
--- Test 2 --- Test 2
@todo_wine@Test quotes "&" work Test quotes "&" work
--- Test 3 --- Test 3
@todo_wine@"&" "&"
--- Test 4 --- Test 4
@todo_wine@"<" "<"
--- Test 5 --- Test 5
@todo_wine@">" ">"
--- Test 6 --- Test 6
@todo_wine@"\" "\"
--- Test 7 --- Test 7
@todo_wine@"|" "|"
--- Test 8 --- Test 8
@todo_wine@"`" "`"
--- Test 9 --- Test 9
@todo_wine@""" """
--- Test 10 --- Test 10
--- Test 11 --- Test 11
--- Test 12 --- Test 12
...@@ -936,6 +936,10 @@ passed2@space@ ...@@ -936,6 +936,10 @@ passed2@space@
--- Test 14 --- Test 14
foobar foobar
--- Test 15 --- Test 15
No whitespace
--- Test 16
--- Test 17
--- Test 18
No prompts or I would not get here1 No prompts or I would not get here1
No prompts or I would not get here2 No prompts or I would not get here2
%hello1% %hello1%
......
...@@ -2300,7 +2300,9 @@ void WCMD_free_commands(CMD_LIST *cmds) { ...@@ -2300,7 +2300,9 @@ void WCMD_free_commands(CMD_LIST *cmds) {
int wmain (int argc, WCHAR *argvW[]) int wmain (int argc, WCHAR *argvW[])
{ {
int args; int args;
WCHAR *cmd; WCHAR *cmdLine = NULL;
WCHAR *cmd = NULL;
WCHAR *argPos = NULL;
WCHAR string[1024]; WCHAR string[1024];
WCHAR envvar[4]; WCHAR envvar[4];
BOOL opt_q; BOOL opt_q;
...@@ -2318,19 +2320,26 @@ int wmain (int argc, WCHAR *argvW[]) ...@@ -2318,19 +2320,26 @@ int wmain (int argc, WCHAR *argvW[])
LocalFree(cmd); LocalFree(cmd);
cmd = NULL; cmd = NULL;
args = argc; /* Can't use argc/argv as it will have stripped quotes from parameters
* meaning cmd.exe /C echo "quoted string" is impossible
*/
cmdLine = GetCommandLineW();
WINE_TRACE("Full commandline '%s'\n", wine_dbgstr_w(cmdLine));
args = 1; /* start at first arg, skipping cmd.exe itself */
opt_c = opt_k = opt_q = opt_s = FALSE; opt_c = opt_k = opt_q = opt_s = FALSE;
while (args > 0) WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
while (argPos && argPos[0] != 0x00)
{ {
WCHAR c; WCHAR c;
WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(*argvW)); WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(argPos));
if ((*argvW)[0]!='/' || (*argvW)[1]=='\0') { if (argPos[0]!='/' || argPos[1]=='\0') {
argvW++; args++;
args--; WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
continue; continue;
} }
c=(*argvW)[1]; c=argPos[1];
if (tolowerW(c)=='c') { if (tolowerW(c)=='c') {
opt_c = TRUE; opt_c = TRUE;
} else if (tolowerW(c)=='q') { } else if (tolowerW(c)=='q') {
...@@ -2343,19 +2352,20 @@ int wmain (int argc, WCHAR *argvW[]) ...@@ -2343,19 +2352,20 @@ int wmain (int argc, WCHAR *argvW[])
unicodeOutput = FALSE; unicodeOutput = FALSE;
} else if (tolowerW(c)=='u') { } else if (tolowerW(c)=='u') {
unicodeOutput = TRUE; unicodeOutput = TRUE;
} else if (tolowerW(c)=='t' && (*argvW)[2]==':') { } else if (tolowerW(c)=='t' && argPos[2]==':') {
opt_t=strtoulW(&(*argvW)[3], NULL, 16); opt_t=strtoulW(&argPos[3], NULL, 16);
} else if (tolowerW(c)=='x' || tolowerW(c)=='y') { } else if (tolowerW(c)=='x' || tolowerW(c)=='y') {
/* Ignored for compatibility with Windows */ /* Ignored for compatibility with Windows */
} }
if ((*argvW)[2]==0) { if (argPos[2]==0 || argPos[2]==' ' || argPos[2]=='\t') {
argvW++; args++;
args--; WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
} }
else /* handle `cmd /cnotepad.exe` and `cmd /x/c ...` */ else /* handle `cmd /cnotepad.exe` and `cmd /x/c ...` */
{ {
*argvW+=2; /* Do not step to next paramater, instead carry on parsing this one */
argPos+=2;
} }
if (opt_c || opt_k) /* break out of parsing immediately after c or k */ if (opt_c || opt_k) /* break out of parsing immediately after c or k */
...@@ -2371,64 +2381,50 @@ int wmain (int argc, WCHAR *argvW[]) ...@@ -2371,64 +2381,50 @@ int wmain (int argc, WCHAR *argvW[])
interactive = FALSE; interactive = FALSE;
if (opt_c || opt_k) { if (opt_c || opt_k) {
int len,qcount; int len;
WCHAR** arg; WCHAR *q1 = NULL,*q2 = NULL,*p;
int argsLeft;
WCHAR* p; /* Handle very edge case error scenarion, "cmd.exe /c" ie when there are no
* parameters after the /C or /K by pretending there was a single space */
if (argPos == NULL) argPos = (WCHAR *)spaceW;
/* Build the command to execute - It is what is left in argPos */
len = strlenW(argPos);
/* Take a copy */
cmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!cmd)
exit(1);
strcpyW(cmd, argPos);
/* opt_s left unflagged if the command starts with and contains exactly /* opt_s left unflagged if the command starts with and contains exactly
* one quoted string (exactly two quote characters). The quoted string * one quoted string (exactly two quote characters). The quoted string
* must be an executable name that has whitespace and must not have the * must be an executable name that has whitespace and must not have the
* following characters: &<>()@^| */ * following characters: &<>()@^| */
/* Build the command to execute */ if (!opt_s) {
len = 0; /* 1. Confirm there is at least one quote */
qcount = 0; q1 = strchrW(argPos, '"');
argsLeft = args; if (!q1) opt_s=1;
for (arg = argvW; argsLeft>0; arg++,argsLeft--)
{
BOOL has_space = FALSE;
int bcount;
WCHAR* a;
bcount=0;
a=*arg;
if( !*a ) has_space = TRUE;
while (*a!='\0') {
if (*a=='\\') {
bcount++;
} else {
if (*a==' ' || *a=='\t') {
has_space = TRUE;
} else if (*a=='"') {
/* doubling of '\' preceding a '"',
* plus escaping of said '"'
*/
len+=2*bcount+1;
qcount++;
}
bcount=0;
}
a++;
}
len+=(a-*arg) + 1; /* for the separating space */
if (has_space)
{
len+=2; /* for the quotes */
qcount+=2;
}
} }
/* If there is not exactly 2 quote characters, then /S (old behaviour) is enabled */ if (!opt_s) {
if (qcount!=2) /* 2. Confirm there is a second quote */
opt_s = TRUE; q2 = strchrW(q1+1, '"');
if (!q2) opt_s=1;
}
/* check argvW[0] for a space and invalid characters. There must not be any invalid if (!opt_s) {
* characters, but there must be one or more whitespace */ /* 3. Ensure there are no more quotes */
if (strchrW(q2+1, '"')) opt_s=1;
}
/* check first parameter for a space and invalid characters. There must not be any
* invalid characters, but there must be one or more whitespace */
if (!opt_s) { if (!opt_s) {
opt_s = TRUE; opt_s = TRUE;
p=*argvW; p=q1;
while (*p!='\0') { while (p!=q2) {
if (*p=='&' || *p=='<' || *p=='>' || *p=='(' || *p==')' if (*p=='&' || *p=='<' || *p=='>' || *p=='(' || *p==')'
|| *p=='@' || *p=='^' || *p=='|') { || *p=='@' || *p=='^' || *p=='|') {
opt_s = TRUE; opt_s = TRUE;
...@@ -2440,73 +2436,6 @@ int wmain (int argc, WCHAR *argvW[]) ...@@ -2440,73 +2436,6 @@ int wmain (int argc, WCHAR *argvW[])
} }
} }
cmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!cmd)
exit(1);
p = cmd;
argsLeft = args;
for (arg = argvW; argsLeft>0; arg++,argsLeft--)
{
BOOL has_space = FALSE, has_quote = FALSE;
WCHAR* a;
/* Check for quotes and spaces in this argument */
a=*arg;
if( !*a ) has_space = TRUE;
while (*a!='\0') {
if (*a==' ' || *a=='\t') {
has_space = TRUE;
if (has_quote)
break;
} else if (*a=='"') {
has_quote = TRUE;
if (has_space)
break;
}
a++;
}
/* Now transfer it to the command line */
if (has_space)
*p++='"';
if (has_quote) {
int bcount;
WCHAR* a;
bcount=0;
a=*arg;
while (*a!='\0') {
if (*a=='\\') {
*p++=*a;
bcount++;
} else {
if (*a=='"') {
int i;
/* Double all the '\\' preceding this '"', plus one */
for (i=0;i<=bcount;i++)
*p++='\\';
*p++='"';
} else {
*p++=*a;
}
bcount=0;
}
a++;
}
} else {
strcpyW(p,*arg);
p+=strlenW(*arg);
}
if (has_space)
*p++='"';
*p++=' ';
}
if (p > cmd)
p--; /* remove last space */
*p = '\0';
WINE_TRACE("/c command line: '%s'\n", wine_dbgstr_w(cmd)); WINE_TRACE("/c command line: '%s'\n", wine_dbgstr_w(cmd));
/* Finally, we only stay in new mode IF the first parameter is quoted and /* Finally, we only stay in new mode IF the first parameter is quoted and
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment