cmd.exe: Support IF..ELSE processing tolerate multiline/part lines.

This commit is contained in:
Jason Edmeades 2007-06-15 20:59:27 +01:00 committed by Alexandre Julliard
parent 345cb89175
commit d2e7b401a2
4 changed files with 130 additions and 24 deletions

View File

@ -109,7 +109,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, int called, WCHAR *startLabel, HAN
CMD_LIST *toExecute = NULL; /* Commands left to be executed */ CMD_LIST *toExecute = NULL; /* Commands left to be executed */
if (WCMD_ReadAndParseLine(NULL, &toExecute, h) == NULL) if (WCMD_ReadAndParseLine(NULL, &toExecute, h) == NULL)
break; break;
WCMD_process_commands(toExecute); WCMD_process_commands(toExecute, FALSE);
WCMD_free_commands(toExecute); WCMD_free_commands(toExecute);
toExecute = NULL; toExecute = NULL;
} }

View File

@ -790,6 +790,14 @@ void WCMD_popd (void) {
* WCMD_if * WCMD_if
* *
* Batch file conditional. * Batch file conditional.
*
* On entry, cmdlist will point to command containing the IF, and optionally
* the first command to execute (if brackets not found)
* If &&'s were found, this may be followed by a record flagged as isAmpersand
* If ('s were found, execute all within that bracket
* Command may optionally be followed by an ELSE - need to skip instructions
* in the else using the same logic
*
* FIXME: Much more syntax checking needed! * FIXME: Much more syntax checking needed!
*/ */
@ -802,6 +810,8 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
static const WCHAR existW[] = {'e','x','i','s','t','\0'}; static const WCHAR existW[] = {'e','x','i','s','t','\0'};
static const WCHAR defdW[] = {'d','e','f','i','n','e','d','\0'}; static const WCHAR defdW[] = {'d','e','f','i','n','e','d','\0'};
static const WCHAR eqeqW[] = {'=','=','\0'}; static const WCHAR eqeqW[] = {'=','=','\0'};
CMD_LIST *curPosition;
int myDepth;
if (!lstrcmpiW (param1, notW)) { if (!lstrcmpiW (param1, notW)) {
negate = 1; negate = 1;
@ -835,10 +845,83 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR)); WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
return; return;
} }
/* Process rest of IF statement which is on the same line
Note: This may process all or some of the cmdList (eg a GOTO) */
curPosition = *cmdList;
myDepth = (*cmdList)->bracketDepth;
if (test != negate) { if (test != negate) {
command = WCMD_strdupW(command); WCHAR *cmd = command;
WCMD_process_command (command, cmdList);
free (command); /* Skip leading whitespace between condition and the command */
while (cmd && *cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
if (cmd && *cmd) {
command = WCMD_strdupW(cmd);
WCMD_process_command (command, cmdList);
free (command);
}
}
/* If it didnt move the position, step to next command */
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
/* Process any other parts of the IF */
if (*cmdList) {
BOOL processThese = (test != negate);
while (*cmdList) {
const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
/* execute all appropriate commands */
curPosition = *cmdList;
WINE_TRACE("Processing cmdList(%p) - &(%d) bd(%d / %d)\n",
*cmdList,
(*cmdList)->isAmphersand,
(*cmdList)->bracketDepth, myDepth);
/* Execute any appended to the statement with &&'s */
if ((*cmdList)->isAmphersand) {
if (processThese) {
WCMD_process_command((*cmdList)->command, cmdList);
}
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
/* Execute any appended to the statement with (...) */
} else if ((*cmdList)->bracketDepth > myDepth) {
if (processThese) {
*cmdList = WCMD_process_commands(*cmdList, TRUE);
WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
}
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
/* End of the command - does 'ELSE ' follow as the next command? */
} else {
if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
(*cmdList)->command, 5, ifElse, -1) == 2) {
/* Swap between if and else processing */
processThese = !processThese;
/* Process the ELSE part */
if (processThese) {
WCHAR *cmd = ((*cmdList)->command) + strlenW(ifElse);
/* Skip leading whitespace between condition and the command */
while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
if (*cmd) {
WCMD_process_command(cmd, cmdList);
}
}
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
} else {
WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
break;
}
}
}
} }
} }

View File

@ -102,7 +102,7 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars,
LPDWORD charsRead, const LPOVERLAPPED unused); LPDWORD charsRead, const LPOVERLAPPED unused);
WCHAR *WCMD_ReadAndParseLine(WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom); WCHAR *WCMD_ReadAndParseLine(WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom);
void WCMD_process_commands(CMD_LIST *thisCmd); CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket);
void WCMD_free_commands(CMD_LIST *cmds); void WCMD_free_commands(CMD_LIST *cmds);
/* Data structure to hold context when executing batch files */ /* Data structure to hold context when executing batch files */

View File

@ -324,7 +324,7 @@ int wmain (int argc, WCHAR *argvW[])
/* Parse the command string, without reading any more input */ /* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE); WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
WCMD_process_commands(toExecute); WCMD_process_commands(toExecute, FALSE);
WCMD_free_commands(toExecute); WCMD_free_commands(toExecute);
toExecute = NULL; toExecute = NULL;
@ -417,7 +417,7 @@ int wmain (int argc, WCHAR *argvW[])
if (opt_k) { if (opt_k) {
/* Parse the command string, without reading any more input */ /* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE); WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
WCMD_process_commands(toExecute); WCMD_process_commands(toExecute, FALSE);
WCMD_free_commands(toExecute); WCMD_free_commands(toExecute);
toExecute = NULL; toExecute = NULL;
HeapFree(GetProcessHeap(), 0, cmd); HeapFree(GetProcessHeap(), 0, cmd);
@ -449,7 +449,7 @@ int wmain (int argc, WCHAR *argvW[])
if (WCMD_ReadAndParseLine(NULL, &toExecute, if (WCMD_ReadAndParseLine(NULL, &toExecute,
GetStdHandle(STD_INPUT_HANDLE)) == NULL) GetStdHandle(STD_INPUT_HANDLE)) == NULL)
break; break;
WCMD_process_commands(toExecute); WCMD_process_commands(toExecute, FALSE);
WCMD_free_commands(toExecute); WCMD_free_commands(toExecute);
toExecute = NULL; toExecute = NULL;
} }
@ -2044,6 +2044,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
break; break;
case '"': inQuotes = !inQuotes; case '"': inQuotes = !inQuotes;
curString[curLen++] = *curPos;
break; break;
case '(': /* If a '(' is the first non whitespace in a command portion case '(': /* If a '(' is the first non whitespace in a command portion
@ -2101,21 +2102,23 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
curPos++; /* Skip other & */ curPos++; /* Skip other & */
/* Add an entry to the command list */ /* Add an entry to the command list */
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST)); if (curLen > 0) {
thisEntry->command = HeapAlloc(GetProcessHeap(), 0, thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
(curLen+1) * sizeof(WCHAR)); thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR)); (curLen+1) * sizeof(WCHAR));
thisEntry->command[curLen] = 0x00; memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
curLen = 0; thisEntry->command[curLen] = 0x00;
thisEntry->nextcommand = NULL; curLen = 0;
thisEntry->isAmphersand = isAmphersand; thisEntry->nextcommand = NULL;
thisEntry->bracketDepth = curDepth; thisEntry->isAmphersand = isAmphersand;
if (lastEntry) { thisEntry->bracketDepth = curDepth;
lastEntry->nextcommand = thisEntry; if (lastEntry) {
} else { lastEntry->nextcommand = thisEntry;
*output = thisEntry; } else {
*output = thisEntry;
}
lastEntry = thisEntry;
} }
lastEntry = thisEntry;
isAmphersand = TRUE; isAmphersand = TRUE;
} else { } else {
curString[curLen++] = *curPos; curString[curLen++] = *curPos;
@ -2224,24 +2227,44 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
* *
* Process all the commands read in so far * Process all the commands read in so far
*/ */
void WCMD_process_commands(CMD_LIST *thisCmd) { CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket) {
int bdepth = -1;
if (thisCmd && oneBracket) bdepth = thisCmd->bracketDepth;
/* Loop through the commands, processing them one by one */ /* Loop through the commands, processing them one by one */
while (thisCmd) { while (thisCmd) {
CMD_LIST *origCmd = thisCmd;
/* If processing one bracket only, and we find the end bracket
entry (or less), return */
if (oneBracket && !thisCmd->command &&
bdepth <= thisCmd->bracketDepth) {
WINE_TRACE("Finished bracket @ %p, next command is %p\n",
thisCmd, thisCmd->nextcommand);
return thisCmd->nextcommand;
}
/* Ignore the NULL entries a ')' inserts (Only 'if' cares /* Ignore the NULL entries a ')' inserts (Only 'if' cares
about them and it will be handled in there) about them and it will be handled in there)
Also, skip over any batch labels (eg. :fred) */ Also, skip over any batch labels (eg. :fred) */
if (thisCmd->command && thisCmd->command[0] != ':') { if (thisCmd->command && thisCmd->command[0] != ':') {
WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command)); WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command));
if (strchrW(thisCmd->command,'|') != NULL) { if (strchrW(thisCmd->command,'|') != NULL) {
WCMD_pipe (&thisCmd); WCMD_pipe (&thisCmd);
} else { } else {
WCMD_process_command (thisCmd->command, &thisCmd); WCMD_process_command (thisCmd->command, &thisCmd);
} }
} }
if (thisCmd) thisCmd = thisCmd->nextcommand;
/* Step on unless the command itself already stepped on */
if (thisCmd == origCmd) thisCmd = thisCmd->nextcommand;
} }
return NULL;
} }
/*************************************************************************** /***************************************************************************