cmd: Handle single line 'if' as nested if or with redirects.
A single line if statement causes problems when it has redirects and/or continuation type operators (|, &&, || etc) because it is expected that if there is more than one command in the 'if', then it will use brackets. This patch changes the 'if' parsing to emulate brackets at a continuation character. In addition, 'for' and 'if' statements do not have their output redirected immediately, instead it is redirected on the individual commands being executed not the statement itself. We were opening the redirect once for the 'if' and once for the processing of the statement inside the if. Signed-off-by: Jason Edmeades <us@edmeades.me.uk> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5c444c4e0d
commit
58d21b3319
|
@ -1544,8 +1544,8 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
||||||
CMD_LIST *curPosition = *cmdList;
|
CMD_LIST *curPosition = *cmdList;
|
||||||
int myDepth = (*cmdList)->bracketDepth;
|
int myDepth = (*cmdList)->bracketDepth;
|
||||||
|
|
||||||
WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d)\n", cmdList, wine_dbgstr_w(firstcmd),
|
WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d), isIF(%d)\n", cmdList,
|
||||||
executecmds);
|
wine_dbgstr_w(firstcmd), executecmds, isIF);
|
||||||
|
|
||||||
/* Skip leading whitespace between condition and the command */
|
/* Skip leading whitespace between condition and the command */
|
||||||
while (firstcmd && *firstcmd && (*firstcmd==' ' || *firstcmd=='\t')) firstcmd++;
|
while (firstcmd && *firstcmd && (*firstcmd==' ' || *firstcmd=='\t')) firstcmd++;
|
||||||
|
@ -1592,7 +1592,8 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
||||||
} else if ((*cmdList)->bracketDepth > myDepth) {
|
} else if ((*cmdList)->bracketDepth > myDepth) {
|
||||||
if (processThese) {
|
if (processThese) {
|
||||||
*cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE);
|
*cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE);
|
||||||
WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
|
} else {
|
||||||
|
WINE_TRACE("Skipping command %p due to stack depth\n", *cmdList);
|
||||||
}
|
}
|
||||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||||
|
|
||||||
|
@ -1626,9 +1627,16 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
||||||
processThese = TRUE;
|
processThese = TRUE;
|
||||||
}
|
}
|
||||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||||
|
|
||||||
|
/* If we were in an IF statement and we didnt find an else and yet we get back to
|
||||||
|
the same bracket depth as the IF, then the IF statement is over. This is required
|
||||||
|
to handle nested ifs properly */
|
||||||
|
} else if (isIF && (*cmdList)->bracketDepth == myDepth) {
|
||||||
|
WINE_TRACE("Found end of this nested IF statement, ending this if\n");
|
||||||
|
break;
|
||||||
} else if (!processThese) {
|
} else if (!processThese) {
|
||||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||||
WINE_TRACE("Ignore the next command as well (next = %p)\n", *cmdList);
|
WINE_TRACE("Skipping this command, as in not process mode (next = %p)\n", *cmdList);
|
||||||
} else {
|
} else {
|
||||||
WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
|
WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -179,6 +179,8 @@ if exist foo (type foo) else echo not supported
|
||||||
echo --- redirections within IF statements
|
echo --- redirections within IF statements
|
||||||
if 1==1 echo foo1>bar
|
if 1==1 echo foo1>bar
|
||||||
type bar & del bar
|
type bar & del bar
|
||||||
|
if 1==1 echo foo2>>bar
|
||||||
|
type bar & del bar
|
||||||
echo -----
|
echo -----
|
||||||
if 1==1 (echo foo2>bar) else echo baz2>bar
|
if 1==1 (echo foo2>bar) else echo baz2>bar
|
||||||
type bar & del bar
|
type bar & del bar
|
||||||
|
@ -925,6 +927,13 @@ if %elseIF% == 1 (
|
||||||
) else (
|
) else (
|
||||||
echo else if seems to be broken
|
echo else if seems to be broken
|
||||||
)
|
)
|
||||||
|
if "x" == "a" (
|
||||||
|
echo broken1
|
||||||
|
) else (
|
||||||
|
echo expected1
|
||||||
|
if "y" == "b" echo broken2
|
||||||
|
echo expected post-embedded if
|
||||||
|
)
|
||||||
echo --- case sensitivity with and without /i option
|
echo --- case sensitivity with and without /i option
|
||||||
if bar==BAR echo if does not default to case sensitivity
|
if bar==BAR echo if does not default to case sensitivity
|
||||||
if not bar==BAR echo if seems to default to case sensitivity
|
if not bar==BAR echo if seems to default to case sensitivity
|
||||||
|
|
|
@ -205,7 +205,8 @@ food21
|
||||||
@todo_wine@foo7@space@@space@@or_broken@not supported@space@
|
@todo_wine@foo7@space@@space@@or_broken@not supported@space@
|
||||||
@todo_wine@foo@or_broken@not supported
|
@todo_wine@foo@or_broken@not supported
|
||||||
--- redirections within IF statements
|
--- redirections within IF statements
|
||||||
@todo_wine@foo1
|
foo1
|
||||||
|
foo2
|
||||||
-----
|
-----
|
||||||
foo2
|
foo2
|
||||||
foo3
|
foo3
|
||||||
|
@ -430,7 +431,7 @@ p1
|
||||||
q1
|
q1
|
||||||
@todo_wine@---
|
@todo_wine@---
|
||||||
--- chain else (if false)
|
--- chain else (if false)
|
||||||
@todo_wine@j3
|
j3
|
||||||
---
|
---
|
||||||
k3
|
k3
|
||||||
l3
|
l3
|
||||||
|
@ -661,6 +662,8 @@ if seems not to detect /c as parameter
|
||||||
else if seems to work
|
else if seems to work
|
||||||
else if seems to work
|
else if seems to work
|
||||||
else if seems to work
|
else if seems to work
|
||||||
|
expected1
|
||||||
|
expected post-embedded if
|
||||||
--- case sensitivity with and without /i option
|
--- case sensitivity with and without /i option
|
||||||
if seems to default to case sensitivity
|
if seems to default to case sensitivity
|
||||||
if /i seems to work
|
if /i seems to work
|
||||||
|
|
|
@ -1277,8 +1277,9 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
||||||
void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
CMD_LIST **cmdList, BOOL retrycall)
|
CMD_LIST **cmdList, BOOL retrycall)
|
||||||
{
|
{
|
||||||
WCHAR *cmd, *p, *redir;
|
WCHAR *cmd, *parms_start, *redir;
|
||||||
int status, i;
|
WCHAR *pos;
|
||||||
|
int status, i, cmd_index;
|
||||||
DWORD count, creationDisposition;
|
DWORD count, creationDisposition;
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
WCHAR *whichcmd;
|
WCHAR *whichcmd;
|
||||||
|
@ -1296,13 +1297,42 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
WINE_TRACE("command on entry:%s (%p)\n",
|
WINE_TRACE("command on entry:%s (%p)\n",
|
||||||
wine_dbgstr_w(command), cmdList);
|
wine_dbgstr_w(command), cmdList);
|
||||||
|
|
||||||
|
/* Move copy of the command onto the heap so it can be expanded */
|
||||||
|
new_cmd = heap_alloc(MAXSTRING * sizeof(WCHAR));
|
||||||
|
strcpyW(new_cmd, command);
|
||||||
|
cmd = new_cmd;
|
||||||
|
|
||||||
|
/* Move copy of the redirects onto the heap so it can be expanded */
|
||||||
|
new_redir = heap_alloc(MAXSTRING * sizeof(WCHAR));
|
||||||
|
redir = new_redir;
|
||||||
|
|
||||||
|
/* Strip leading whitespaces, and a '@' if supplied */
|
||||||
|
whichcmd = WCMD_skip_leading_spaces(cmd);
|
||||||
|
WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd));
|
||||||
|
if (whichcmd[0] == '@') whichcmd++;
|
||||||
|
|
||||||
|
/* Check if the command entered is internal, and identify which one */
|
||||||
|
count = 0;
|
||||||
|
while (IsCharAlphaNumericW(whichcmd[count])) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
for (i=0; i<=WCMD_EXIT; i++) {
|
||||||
|
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
||||||
|
whichcmd, count, inbuilt[i], -1) == CSTR_EQUAL) break;
|
||||||
|
}
|
||||||
|
cmd_index = i;
|
||||||
|
parms_start = WCMD_skip_leading_spaces (&whichcmd[count]);
|
||||||
|
|
||||||
/* If the next command is a pipe then we implement pipes by redirecting
|
/* If the next command is a pipe then we implement pipes by redirecting
|
||||||
the output from this command to a temp file and input into the
|
the output from this command to a temp file and input into the
|
||||||
next command from that temp file.
|
next command from that temp file.
|
||||||
|
Note: Do not do this for a for or if statement as the pipe is for
|
||||||
|
the individual statements, not the for or if itself.
|
||||||
FIXME: Use of named pipes would make more sense here as currently this
|
FIXME: Use of named pipes would make more sense here as currently this
|
||||||
process has to finish before the next one can start but this requires
|
process has to finish before the next one can start but this requires
|
||||||
a change to not wait for the first app to finish but rather the pipe */
|
a change to not wait for the first app to finish but rather the pipe */
|
||||||
if (cmdList && (*cmdList)->nextcommand &&
|
if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF) &&
|
||||||
|
cmdList && (*cmdList)->nextcommand &&
|
||||||
(*cmdList)->nextcommand->prevDelim == CMD_PIPE) {
|
(*cmdList)->nextcommand->prevDelim == CMD_PIPE) {
|
||||||
|
|
||||||
WCHAR temp_path[MAX_PATH];
|
WCHAR temp_path[MAX_PATH];
|
||||||
|
@ -1319,13 +1349,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
wine_dbgstr_w((*cmdList)->nextcommand->pipeFile));
|
wine_dbgstr_w((*cmdList)->nextcommand->pipeFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move copy of the command onto the heap so it can be expanded */
|
|
||||||
new_cmd = heap_alloc(MAXSTRING * sizeof(WCHAR));
|
|
||||||
strcpyW(new_cmd, command);
|
|
||||||
|
|
||||||
/* Move copy of the redirects onto the heap so it can be expanded */
|
|
||||||
new_redir = heap_alloc(MAXSTRING * sizeof(WCHAR));
|
|
||||||
|
|
||||||
/* If piped output, send stdout to the pipe by appending >filename to redirects */
|
/* If piped output, send stdout to the pipe by appending >filename to redirects */
|
||||||
if (piped) {
|
if (piped) {
|
||||||
static const WCHAR redirOut[] = {'%','s',' ','>',' ','%','s','\0'};
|
static const WCHAR redirOut[] = {'%','s',' ','>',' ','%','s','\0'};
|
||||||
|
@ -1339,7 +1362,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
be expanded as the line is read in, except for 'for' loops) */
|
be expanded as the line is read in, except for 'for' loops) */
|
||||||
handleExpansion(new_cmd, (context != NULL), delayedsubst);
|
handleExpansion(new_cmd, (context != NULL), delayedsubst);
|
||||||
handleExpansion(new_redir, (context != NULL), delayedsubst);
|
handleExpansion(new_redir, (context != NULL), delayedsubst);
|
||||||
cmd = new_cmd;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Changing default drive has to be handled as a special case, anything
|
* Changing default drive has to be handled as a special case, anything
|
||||||
|
@ -1376,16 +1398,33 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
sa.lpSecurityDescriptor = NULL;
|
sa.lpSecurityDescriptor = NULL;
|
||||||
sa.bInheritHandle = TRUE;
|
sa.bInheritHandle = TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Redirect stdin, stdout and/or stderr if required.
|
* Redirect stdin, stdout and/or stderr if required.
|
||||||
*/
|
* Note: Do not do this for a for or if statement as the pipe is for
|
||||||
|
* the individual statements, not the for or if itself.
|
||||||
|
*/
|
||||||
|
if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF)) {
|
||||||
|
/* STDIN could come from a preceding pipe, so delete on close if it does */
|
||||||
|
if (cmdList && (*cmdList)->pipeFile[0] != 0x00) {
|
||||||
|
WINE_TRACE("Input coming from %s\n", wine_dbgstr_w((*cmdList)->pipeFile));
|
||||||
|
h = CreateFileW((*cmdList)->pipeFile, GENERIC_READ,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
WCMD_print_error ();
|
||||||
|
heap_free(cmd);
|
||||||
|
heap_free(new_redir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetStdHandle (STD_INPUT_HANDLE, h);
|
||||||
|
|
||||||
/* STDIN could come from a preceding pipe, so delete on close if it does */
|
/* No need to remember the temporary name any longer once opened */
|
||||||
if (cmdList && (*cmdList)->pipeFile[0] != 0x00) {
|
(*cmdList)->pipeFile[0] = 0x00;
|
||||||
WINE_TRACE("Input coming from %s\n", wine_dbgstr_w((*cmdList)->pipeFile));
|
|
||||||
h = CreateFileW((*cmdList)->pipeFile, GENERIC_READ,
|
/* Otherwise STDIN could come from a '<' redirect */
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING,
|
} else if ((pos = strchrW(new_redir,'<')) != NULL) {
|
||||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
h = CreateFileW(WCMD_parameter(++pos, 0, NULL, FALSE, FALSE), GENERIC_READ, FILE_SHARE_READ,
|
||||||
|
&sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (h == INVALID_HANDLE_VALUE) {
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
WCMD_print_error ();
|
WCMD_print_error ();
|
||||||
heap_free(cmd);
|
heap_free(cmd);
|
||||||
|
@ -1393,122 +1432,87 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SetStdHandle (STD_INPUT_HANDLE, h);
|
SetStdHandle (STD_INPUT_HANDLE, h);
|
||||||
|
|
||||||
/* No need to remember the temporary name any longer once opened */
|
|
||||||
(*cmdList)->pipeFile[0] = 0x00;
|
|
||||||
|
|
||||||
/* Otherwise STDIN could come from a '<' redirect */
|
|
||||||
} else if ((p = strchrW(new_redir,'<')) != NULL) {
|
|
||||||
h = CreateFileW(WCMD_parameter(++p, 0, NULL, FALSE, FALSE), GENERIC_READ, FILE_SHARE_READ,
|
|
||||||
&sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if (h == INVALID_HANDLE_VALUE) {
|
|
||||||
WCMD_print_error ();
|
|
||||||
heap_free(cmd);
|
|
||||||
heap_free(new_redir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SetStdHandle (STD_INPUT_HANDLE, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scan the whole command looking for > and 2> */
|
|
||||||
redir = new_redir;
|
|
||||||
while (redir != NULL && ((p = strchrW(redir,'>')) != NULL)) {
|
|
||||||
int handle = 0;
|
|
||||||
|
|
||||||
if (p > redir && (*(p-1)=='2'))
|
|
||||||
handle = 2;
|
|
||||||
else
|
|
||||||
handle = 1;
|
|
||||||
|
|
||||||
p++;
|
|
||||||
if ('>' == *p) {
|
|
||||||
creationDisposition = OPEN_ALWAYS;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
creationDisposition = CREATE_ALWAYS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add support for 2>&1 */
|
/* Scan the whole command looking for > and 2> */
|
||||||
redir = p;
|
while (redir != NULL && ((pos = strchrW(redir,'>')) != NULL)) {
|
||||||
if (*p == '&') {
|
int handle = 0;
|
||||||
int idx = *(p+1) - '0';
|
|
||||||
|
|
||||||
if (DuplicateHandle(GetCurrentProcess(),
|
if (pos > redir && (*(pos-1)=='2'))
|
||||||
GetStdHandle(idx_stdhandles[idx]),
|
handle = 2;
|
||||||
GetCurrentProcess(),
|
else
|
||||||
&h,
|
handle = 1;
|
||||||
0, TRUE, DUPLICATE_SAME_ACCESS) == 0) {
|
|
||||||
WINE_FIXME("Duplicating handle failed with gle %d\n", GetLastError());
|
pos++;
|
||||||
|
if ('>' == *pos) {
|
||||||
|
creationDisposition = OPEN_ALWAYS;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
creationDisposition = CREATE_ALWAYS;
|
||||||
}
|
}
|
||||||
WINE_TRACE("Redirect %d (%p) to %d (%p)\n", handle, GetStdHandle(idx_stdhandles[idx]), idx, h);
|
|
||||||
|
|
||||||
} else {
|
/* Add support for 2>&1 */
|
||||||
WCHAR *param = WCMD_parameter(p, 0, NULL, FALSE, FALSE);
|
redir = pos;
|
||||||
h = CreateFileW(param, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE,
|
if (*pos == '&') {
|
||||||
&sa, creationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
int idx = *(pos+1) - '0';
|
||||||
if (h == INVALID_HANDLE_VALUE) {
|
|
||||||
WCMD_print_error ();
|
if (DuplicateHandle(GetCurrentProcess(),
|
||||||
heap_free(cmd);
|
GetStdHandle(idx_stdhandles[idx]),
|
||||||
heap_free(new_redir);
|
GetCurrentProcess(),
|
||||||
return;
|
&h,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS) == 0) {
|
||||||
|
WINE_FIXME("Duplicating handle failed with gle %d\n", GetLastError());
|
||||||
|
}
|
||||||
|
WINE_TRACE("Redirect %d (%p) to %d (%p)\n", handle, GetStdHandle(idx_stdhandles[idx]), idx, h);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
WCHAR *param = WCMD_parameter(pos, 0, NULL, FALSE, FALSE);
|
||||||
|
h = CreateFileW(param, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE,
|
||||||
|
&sa, creationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
WCMD_print_error ();
|
||||||
|
heap_free(cmd);
|
||||||
|
heap_free(new_redir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SetFilePointer (h, 0, NULL, FILE_END) ==
|
||||||
|
INVALID_SET_FILE_POINTER) {
|
||||||
|
WCMD_print_error ();
|
||||||
|
}
|
||||||
|
WINE_TRACE("Redirect %d to '%s' (%p)\n", handle, wine_dbgstr_w(param), h);
|
||||||
}
|
}
|
||||||
if (SetFilePointer (h, 0, NULL, FILE_END) ==
|
|
||||||
INVALID_SET_FILE_POINTER) {
|
SetStdHandle (idx_stdhandles[handle], h);
|
||||||
WCMD_print_error ();
|
|
||||||
}
|
|
||||||
WINE_TRACE("Redirect %d to '%s' (%p)\n", handle, wine_dbgstr_w(param), h);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
SetStdHandle (idx_stdhandles[handle], h);
|
WINE_TRACE("Not touching redirects for a FOR or IF command\n");
|
||||||
}
|
}
|
||||||
|
WCMD_parse (parms_start, quals, param1, param2);
|
||||||
/*
|
|
||||||
* Strip leading whitespaces, and a '@' if supplied
|
|
||||||
*/
|
|
||||||
whichcmd = WCMD_skip_leading_spaces(cmd);
|
|
||||||
WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd));
|
|
||||||
if (whichcmd[0] == '@') whichcmd++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the command entered is internal. If it is, pass the rest of the
|
|
||||||
* line down to the command. If not try to run a program.
|
|
||||||
*/
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
while (IsCharAlphaNumericW(whichcmd[count])) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
for (i=0; i<=WCMD_EXIT; i++) {
|
|
||||||
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
|
||||||
whichcmd, count, inbuilt[i], -1) == CSTR_EQUAL) break;
|
|
||||||
}
|
|
||||||
p = WCMD_skip_leading_spaces (&whichcmd[count]);
|
|
||||||
WCMD_parse (p, quals, param1, param2);
|
|
||||||
WINE_TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2));
|
WINE_TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2));
|
||||||
|
|
||||||
if (i <= WCMD_EXIT && (p[0] == '/') && (p[1] == '?')) {
|
if (i <= WCMD_EXIT && (parms_start[0] == '/') && (parms_start[1] == '?')) {
|
||||||
/* this is a help request for a builtin program */
|
/* this is a help request for a builtin program */
|
||||||
i = WCMD_HELP;
|
i = WCMD_HELP;
|
||||||
memcpy(p, whichcmd, count * sizeof(WCHAR));
|
memcpy(parms_start, whichcmd, count * sizeof(WCHAR));
|
||||||
p[count] = '\0';
|
parms_start[count] = '\0';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
|
|
||||||
case WCMD_CALL:
|
case WCMD_CALL:
|
||||||
WCMD_call (p);
|
WCMD_call (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_CD:
|
case WCMD_CD:
|
||||||
case WCMD_CHDIR:
|
case WCMD_CHDIR:
|
||||||
WCMD_setshow_default (p);
|
WCMD_setshow_default (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_CLS:
|
case WCMD_CLS:
|
||||||
WCMD_clear_screen ();
|
WCMD_clear_screen ();
|
||||||
break;
|
break;
|
||||||
case WCMD_COPY:
|
case WCMD_COPY:
|
||||||
WCMD_copy (p);
|
WCMD_copy (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_CTTY:
|
case WCMD_CTTY:
|
||||||
WCMD_change_tty ();
|
WCMD_change_tty ();
|
||||||
|
@ -1518,10 +1522,10 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
break;
|
break;
|
||||||
case WCMD_DEL:
|
case WCMD_DEL:
|
||||||
case WCMD_ERASE:
|
case WCMD_ERASE:
|
||||||
WCMD_delete (p);
|
WCMD_delete (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_DIR:
|
case WCMD_DIR:
|
||||||
WCMD_directory (p);
|
WCMD_directory (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_ECHO:
|
case WCMD_ECHO:
|
||||||
WCMD_echo(&whichcmd[count]);
|
WCMD_echo(&whichcmd[count]);
|
||||||
|
@ -1530,20 +1534,20 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
WCMD_goto (cmdList);
|
WCMD_goto (cmdList);
|
||||||
break;
|
break;
|
||||||
case WCMD_HELP:
|
case WCMD_HELP:
|
||||||
WCMD_give_help (p);
|
WCMD_give_help (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_LABEL:
|
case WCMD_LABEL:
|
||||||
WCMD_volume (TRUE, p);
|
WCMD_volume (TRUE, parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_MD:
|
case WCMD_MD:
|
||||||
case WCMD_MKDIR:
|
case WCMD_MKDIR:
|
||||||
WCMD_create_dir (p);
|
WCMD_create_dir (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_MOVE:
|
case WCMD_MOVE:
|
||||||
WCMD_move ();
|
WCMD_move ();
|
||||||
break;
|
break;
|
||||||
case WCMD_PATH:
|
case WCMD_PATH:
|
||||||
WCMD_setshow_path (p);
|
WCMD_setshow_path (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_PAUSE:
|
case WCMD_PAUSE:
|
||||||
WCMD_pause ();
|
WCMD_pause ();
|
||||||
|
@ -1559,22 +1563,22 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
break;
|
break;
|
||||||
case WCMD_RD:
|
case WCMD_RD:
|
||||||
case WCMD_RMDIR:
|
case WCMD_RMDIR:
|
||||||
WCMD_remove_dir (p);
|
WCMD_remove_dir (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_SETLOCAL:
|
case WCMD_SETLOCAL:
|
||||||
WCMD_setlocal(p);
|
WCMD_setlocal(parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_ENDLOCAL:
|
case WCMD_ENDLOCAL:
|
||||||
WCMD_endlocal();
|
WCMD_endlocal();
|
||||||
break;
|
break;
|
||||||
case WCMD_SET:
|
case WCMD_SET:
|
||||||
WCMD_setshow_env (p);
|
WCMD_setshow_env (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_SHIFT:
|
case WCMD_SHIFT:
|
||||||
WCMD_shift (p);
|
WCMD_shift (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_START:
|
case WCMD_START:
|
||||||
WCMD_start (p);
|
WCMD_start (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_TIME:
|
case WCMD_TIME:
|
||||||
WCMD_setshow_time ();
|
WCMD_setshow_time ();
|
||||||
|
@ -1584,41 +1588,41 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
WCMD_title(&whichcmd[count+1]);
|
WCMD_title(&whichcmd[count+1]);
|
||||||
break;
|
break;
|
||||||
case WCMD_TYPE:
|
case WCMD_TYPE:
|
||||||
WCMD_type (p);
|
WCMD_type (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_VER:
|
case WCMD_VER:
|
||||||
WCMD_output_asis(newlineW);
|
WCMD_output_asis(newlineW);
|
||||||
WCMD_version ();
|
WCMD_version ();
|
||||||
break;
|
break;
|
||||||
case WCMD_VERIFY:
|
case WCMD_VERIFY:
|
||||||
WCMD_verify (p);
|
WCMD_verify (parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_VOL:
|
case WCMD_VOL:
|
||||||
WCMD_volume (FALSE, p);
|
WCMD_volume (FALSE, parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_PUSHD:
|
case WCMD_PUSHD:
|
||||||
WCMD_pushd(p);
|
WCMD_pushd(parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_POPD:
|
case WCMD_POPD:
|
||||||
WCMD_popd();
|
WCMD_popd();
|
||||||
break;
|
break;
|
||||||
case WCMD_ASSOC:
|
case WCMD_ASSOC:
|
||||||
WCMD_assoc(p, TRUE);
|
WCMD_assoc(parms_start, TRUE);
|
||||||
break;
|
break;
|
||||||
case WCMD_COLOR:
|
case WCMD_COLOR:
|
||||||
WCMD_color();
|
WCMD_color();
|
||||||
break;
|
break;
|
||||||
case WCMD_FTYPE:
|
case WCMD_FTYPE:
|
||||||
WCMD_assoc(p, FALSE);
|
WCMD_assoc(parms_start, FALSE);
|
||||||
break;
|
break;
|
||||||
case WCMD_MORE:
|
case WCMD_MORE:
|
||||||
WCMD_more(p);
|
WCMD_more(parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_CHOICE:
|
case WCMD_CHOICE:
|
||||||
WCMD_choice(p);
|
WCMD_choice(parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_MKLINK:
|
case WCMD_MKLINK:
|
||||||
WCMD_mklink(p);
|
WCMD_mklink(parms_start);
|
||||||
break;
|
break;
|
||||||
case WCMD_EXIT:
|
case WCMD_EXIT:
|
||||||
WCMD_exit (cmdList);
|
WCMD_exit (cmdList);
|
||||||
|
@ -1629,8 +1633,8 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
these two commands, neither 'for' nor 'if' is supported when called,
|
these two commands, neither 'for' nor 'if' is supported when called,
|
||||||
i.e. 'call if 1==1...' will fail. */
|
i.e. 'call if 1==1...' will fail. */
|
||||||
if (!retrycall) {
|
if (!retrycall) {
|
||||||
if (i==WCMD_FOR) WCMD_for (p, cmdList);
|
if (i==WCMD_FOR) WCMD_for (parms_start, cmdList);
|
||||||
else if (i==WCMD_IF) WCMD_if (p, cmdList);
|
else if (i==WCMD_IF) WCMD_if (parms_start, cmdList);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* else: drop through */
|
/* else: drop through */
|
||||||
|
@ -1838,6 +1842,8 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
BOOL lastWasElse = FALSE;
|
BOOL lastWasElse = FALSE;
|
||||||
BOOL lastWasRedirect = TRUE;
|
BOOL lastWasRedirect = TRUE;
|
||||||
BOOL lastWasCaret = FALSE;
|
BOOL lastWasCaret = FALSE;
|
||||||
|
int lineCurDepth; /* Bracket depth when line was read in */
|
||||||
|
BOOL resetAtEndOfLine = FALSE; /* Do we need to reset curdepth at EOL */
|
||||||
|
|
||||||
/* Allocate working space for a command read from keyboard, file etc */
|
/* Allocate working space for a command read from keyboard, file etc */
|
||||||
if (!extraSpace)
|
if (!extraSpace)
|
||||||
|
@ -1905,6 +1911,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
curCopyTo = curString;
|
curCopyTo = curString;
|
||||||
curLen = &curStringLen;
|
curLen = &curStringLen;
|
||||||
lastWasRedirect = FALSE; /* Required e.g. for spaces between > and filename */
|
lastWasRedirect = FALSE; /* Required e.g. for spaces between > and filename */
|
||||||
|
lineCurDepth = curDepth; /* What was the curdepth at the beginning of the line */
|
||||||
|
|
||||||
/* Parse every character on the line being processed */
|
/* Parse every character on the line being processed */
|
||||||
while (*curPos != 0x00) {
|
while (*curPos != 0x00) {
|
||||||
|
@ -1950,6 +1957,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
memcpy(&curCopyTo[*curLen], curPos, keyw_len*sizeof(WCHAR));
|
memcpy(&curCopyTo[*curLen], curPos, keyw_len*sizeof(WCHAR));
|
||||||
(*curLen)+=keyw_len;
|
(*curLen)+=keyw_len;
|
||||||
curPos+=keyw_len;
|
curPos+=keyw_len;
|
||||||
|
|
||||||
|
/* If we had a single line if XXX which reaches an else (needs odd
|
||||||
|
syntax like if 1=1 command && (command) else command we pretended
|
||||||
|
to add brackets for the if, so they are now over */
|
||||||
|
if (resetAtEndOfLine) {
|
||||||
|
WINE_TRACE("Resetting curdepth at end of line to %d\n", lineCurDepth);
|
||||||
|
resetAtEndOfLine = FALSE;
|
||||||
|
curDepth = lineCurDepth;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* In a for loop, the DO command will follow a close bracket followed by
|
/* In a for loop, the DO command will follow a close bracket followed by
|
||||||
|
@ -2073,6 +2089,14 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
} else {
|
} else {
|
||||||
prevDelim = CMD_PIPE;
|
prevDelim = CMD_PIPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If in an IF or ELSE statement, put subsequent chained
|
||||||
|
commands at a higher depth as if brackets were supplied
|
||||||
|
but remember to reset to the original depth at EOL */
|
||||||
|
if ((inIf || inElse) && curDepth == lineCurDepth) {
|
||||||
|
curDepth++;
|
||||||
|
resetAtEndOfLine = TRUE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
curCopyTo[(*curLen)++] = *curPos;
|
curCopyTo[(*curLen)++] = *curPos;
|
||||||
}
|
}
|
||||||
|
@ -2170,6 +2194,13 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
} else {
|
} else {
|
||||||
prevDelim = CMD_NONE;
|
prevDelim = CMD_NONE;
|
||||||
}
|
}
|
||||||
|
/* If in an IF or ELSE statement, put subsequent chained
|
||||||
|
commands at a higher depth as if brackets were supplied
|
||||||
|
but remember to reset to the original depth at EOL */
|
||||||
|
if ((inIf || inElse) && curDepth == lineCurDepth) {
|
||||||
|
curDepth++;
|
||||||
|
resetAtEndOfLine = TRUE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
curCopyTo[(*curLen)++] = *curPos;
|
curCopyTo[(*curLen)++] = *curPos;
|
||||||
}
|
}
|
||||||
|
@ -2232,7 +2263,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
||||||
&curCopyTo, &curLen,
|
&curCopyTo, &curLen,
|
||||||
prevDelim, curDepth,
|
prevDelim, curDepth,
|
||||||
&lastEntry, output);
|
&lastEntry, output);
|
||||||
}
|
|
||||||
|
/* If we had a single line if or else, and we pretended to add
|
||||||
|
brackets, end them now */
|
||||||
|
if (resetAtEndOfLine) {
|
||||||
|
WINE_TRACE("Resetting curdepth at end of line to %d\n", lineCurDepth);
|
||||||
|
resetAtEndOfLine = FALSE;
|
||||||
|
curDepth = lineCurDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we have reached the end of the string, see if bracketing or
|
/* If we have reached the end of the string, see if bracketing or
|
||||||
final caret is outstanding */
|
final caret is outstanding */
|
||||||
|
|
Loading…
Reference in New Issue