cmd.exe: Support IF..ELSE processing tolerate multiline/part lines.
This commit is contained in:
parent
345cb89175
commit
d2e7b401a2
|
@ -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 */
|
||||
if (WCMD_ReadAndParseLine(NULL, &toExecute, h) == NULL)
|
||||
break;
|
||||
WCMD_process_commands(toExecute);
|
||||
WCMD_process_commands(toExecute, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
}
|
||||
|
|
|
@ -790,6 +790,14 @@ void WCMD_popd (void) {
|
|||
* WCMD_if
|
||||
*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
|
@ -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 defdW[] = {'d','e','f','i','n','e','d','\0'};
|
||||
static const WCHAR eqeqW[] = {'=','=','\0'};
|
||||
CMD_LIST *curPosition;
|
||||
int myDepth;
|
||||
|
||||
if (!lstrcmpiW (param1, notW)) {
|
||||
negate = 1;
|
||||
|
@ -835,10 +845,83 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
|
|||
WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
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) {
|
||||
command = WCMD_strdupW(command);
|
||||
WCMD_process_command (command, cmdList);
|
||||
free (command);
|
||||
WCHAR *cmd = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars,
|
|||
LPDWORD charsRead, const LPOVERLAPPED unused);
|
||||
|
||||
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);
|
||||
|
||||
/* Data structure to hold context when executing batch files */
|
||||
|
|
|
@ -324,7 +324,7 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
|
||||
/* Parse the command string, without reading any more input */
|
||||
WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
|
||||
WCMD_process_commands(toExecute);
|
||||
WCMD_process_commands(toExecute, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
|
||||
|
@ -417,7 +417,7 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
if (opt_k) {
|
||||
/* Parse the command string, without reading any more input */
|
||||
WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
|
||||
WCMD_process_commands(toExecute);
|
||||
WCMD_process_commands(toExecute, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, cmd);
|
||||
|
@ -449,7 +449,7 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
if (WCMD_ReadAndParseLine(NULL, &toExecute,
|
||||
GetStdHandle(STD_INPUT_HANDLE)) == NULL)
|
||||
break;
|
||||
WCMD_process_commands(toExecute);
|
||||
WCMD_process_commands(toExecute, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
}
|
||||
|
@ -2044,6 +2044,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
|
|||
break;
|
||||
|
||||
case '"': inQuotes = !inQuotes;
|
||||
curString[curLen++] = *curPos;
|
||||
break;
|
||||
|
||||
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 & */
|
||||
|
||||
/* Add an entry to the command list */
|
||||
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
|
||||
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
|
||||
(curLen+1) * sizeof(WCHAR));
|
||||
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
|
||||
thisEntry->command[curLen] = 0x00;
|
||||
curLen = 0;
|
||||
thisEntry->nextcommand = NULL;
|
||||
thisEntry->isAmphersand = isAmphersand;
|
||||
thisEntry->bracketDepth = curDepth;
|
||||
if (lastEntry) {
|
||||
lastEntry->nextcommand = thisEntry;
|
||||
} else {
|
||||
*output = thisEntry;
|
||||
if (curLen > 0) {
|
||||
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
|
||||
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
|
||||
(curLen+1) * sizeof(WCHAR));
|
||||
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
|
||||
thisEntry->command[curLen] = 0x00;
|
||||
curLen = 0;
|
||||
thisEntry->nextcommand = NULL;
|
||||
thisEntry->isAmphersand = isAmphersand;
|
||||
thisEntry->bracketDepth = curDepth;
|
||||
if (lastEntry) {
|
||||
lastEntry->nextcommand = thisEntry;
|
||||
} else {
|
||||
*output = thisEntry;
|
||||
}
|
||||
lastEntry = thisEntry;
|
||||
}
|
||||
lastEntry = thisEntry;
|
||||
isAmphersand = TRUE;
|
||||
} else {
|
||||
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
|
||||
*/
|
||||
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 */
|
||||
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
|
||||
about them and it will be handled in there)
|
||||
Also, skip over any batch labels (eg. :fred) */
|
||||
if (thisCmd->command && thisCmd->command[0] != ':') {
|
||||
|
||||
WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command));
|
||||
|
||||
if (strchrW(thisCmd->command,'|') != NULL) {
|
||||
WCMD_pipe (&thisCmd);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
|
|
Loading…
Reference in New Issue