cmd: Change command line parsing away from argv/argc.
This commit is contained in:
parent
a2db974d19
commit
f252e9dfc8
|
@ -1861,7 +1861,12 @@ cmd.exe /c " echo passed2 "
|
|||
echo --- Test 14
|
||||
cmd.exe /c "dir /ad ..\fooba* /b"
|
||||
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
|
||||
echo file2 > file2
|
||||
cmd.exe /c copy file1 file2 >nul
|
||||
|
|
|
@ -910,23 +910,23 @@ value1
|
|||
------------ cmd.exe command lines ------------
|
||||
--- Test 1
|
||||
Line1
|
||||
@todo_wine@"Line2"
|
||||
"Line2"
|
||||
--- Test 2
|
||||
@todo_wine@Test quotes "&" work
|
||||
Test quotes "&" work
|
||||
--- Test 3
|
||||
@todo_wine@"&"
|
||||
"&"
|
||||
--- Test 4
|
||||
@todo_wine@"<"
|
||||
"<"
|
||||
--- Test 5
|
||||
@todo_wine@">"
|
||||
">"
|
||||
--- Test 6
|
||||
@todo_wine@"\"
|
||||
"\"
|
||||
--- Test 7
|
||||
@todo_wine@"|"
|
||||
"|"
|
||||
--- Test 8
|
||||
@todo_wine@"`"
|
||||
"`"
|
||||
--- Test 9
|
||||
@todo_wine@"""
|
||||
"""
|
||||
--- Test 10
|
||||
--- Test 11
|
||||
--- Test 12
|
||||
|
@ -936,6 +936,10 @@ passed2@space@
|
|||
--- Test 14
|
||||
foobar
|
||||
--- 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 here2
|
||||
%hello1%
|
||||
|
|
|
@ -2300,7 +2300,9 @@ void WCMD_free_commands(CMD_LIST *cmds) {
|
|||
int wmain (int argc, WCHAR *argvW[])
|
||||
{
|
||||
int args;
|
||||
WCHAR *cmd;
|
||||
WCHAR *cmdLine = NULL;
|
||||
WCHAR *cmd = NULL;
|
||||
WCHAR *argPos = NULL;
|
||||
WCHAR string[1024];
|
||||
WCHAR envvar[4];
|
||||
BOOL opt_q;
|
||||
|
@ -2318,19 +2320,26 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
LocalFree(cmd);
|
||||
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;
|
||||
while (args > 0)
|
||||
WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
|
||||
while (argPos && argPos[0] != 0x00)
|
||||
{
|
||||
WCHAR c;
|
||||
WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(*argvW));
|
||||
if ((*argvW)[0]!='/' || (*argvW)[1]=='\0') {
|
||||
argvW++;
|
||||
args--;
|
||||
WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(argPos));
|
||||
if (argPos[0]!='/' || argPos[1]=='\0') {
|
||||
args++;
|
||||
WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
|
||||
continue;
|
||||
}
|
||||
|
||||
c=(*argvW)[1];
|
||||
c=argPos[1];
|
||||
if (tolowerW(c)=='c') {
|
||||
opt_c = TRUE;
|
||||
} else if (tolowerW(c)=='q') {
|
||||
|
@ -2343,19 +2352,20 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
unicodeOutput = FALSE;
|
||||
} else if (tolowerW(c)=='u') {
|
||||
unicodeOutput = TRUE;
|
||||
} else if (tolowerW(c)=='t' && (*argvW)[2]==':') {
|
||||
opt_t=strtoulW(&(*argvW)[3], NULL, 16);
|
||||
} else if (tolowerW(c)=='t' && argPos[2]==':') {
|
||||
opt_t=strtoulW(&argPos[3], NULL, 16);
|
||||
} else if (tolowerW(c)=='x' || tolowerW(c)=='y') {
|
||||
/* Ignored for compatibility with Windows */
|
||||
}
|
||||
|
||||
if ((*argvW)[2]==0) {
|
||||
argvW++;
|
||||
args--;
|
||||
if (argPos[2]==0 || argPos[2]==' ' || argPos[2]=='\t') {
|
||||
args++;
|
||||
WCMD_parameter(cmdLine, args, &argPos, NULL, TRUE);
|
||||
}
|
||||
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 */
|
||||
|
@ -2371,64 +2381,50 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
interactive = FALSE;
|
||||
|
||||
if (opt_c || opt_k) {
|
||||
int len,qcount;
|
||||
WCHAR** arg;
|
||||
int argsLeft;
|
||||
WCHAR* p;
|
||||
int len;
|
||||
WCHAR *q1 = NULL,*q2 = NULL,*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
|
||||
* one quoted string (exactly two quote characters). The quoted string
|
||||
* must be an executable name that has whitespace and must not have the
|
||||
* following characters: &<>()@^| */
|
||||
|
||||
/* Build the command to execute */
|
||||
len = 0;
|
||||
qcount = 0;
|
||||
argsLeft = args;
|
||||
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 (!opt_s) {
|
||||
/* 1. Confirm there is at least one quote */
|
||||
q1 = strchrW(argPos, '"');
|
||||
if (!q1) opt_s=1;
|
||||
}
|
||||
|
||||
/* If there is not exactly 2 quote characters, then /S (old behaviour) is enabled */
|
||||
if (qcount!=2)
|
||||
opt_s = TRUE;
|
||||
if (!opt_s) {
|
||||
/* 2. Confirm there is a second quote */
|
||||
q2 = strchrW(q1+1, '"');
|
||||
if (!q2) opt_s=1;
|
||||
}
|
||||
|
||||
/* check argvW[0] for a space and invalid characters. There must not be any invalid
|
||||
* characters, but there must be one or more whitespace */
|
||||
if (!opt_s) {
|
||||
/* 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) {
|
||||
opt_s = TRUE;
|
||||
p=*argvW;
|
||||
while (*p!='\0') {
|
||||
p=q1;
|
||||
while (p!=q2) {
|
||||
if (*p=='&' || *p=='<' || *p=='>' || *p=='(' || *p==')'
|
||||
|| *p=='@' || *p=='^' || *p=='|') {
|
||||
opt_s = TRUE;
|
||||
|
@ -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));
|
||||
|
||||
/* Finally, we only stay in new mode IF the first parameter is quoted and
|
||||
|
|
Loading…
Reference in New Issue