cmd: Add support for calling a built in command.
This commit is contained in:
parent
9f83165efb
commit
3c05818515
|
@ -89,7 +89,10 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
|
|||
CMD_LIST *toExecute = NULL; /* Commands left to be executed */
|
||||
if (!WCMD_ReadAndParseLine(NULL, &toExecute, h))
|
||||
break;
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL);
|
||||
/* Note: although this batch program itself may be called, we are not retrying
|
||||
the command as a result of a call failing to find a program, hence the
|
||||
retryCall parameter below is FALSE */
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
}
|
||||
|
@ -649,6 +652,8 @@ void WCMD_call (WCHAR *command) {
|
|||
/* Run other program if no leading ':' */
|
||||
if (*command != ':') {
|
||||
WCMD_run_program(command, TRUE);
|
||||
/* If the thing we try to run does not exist, call returns 1 */
|
||||
if (errorlevel) errorlevel=1;
|
||||
} else {
|
||||
|
||||
WCHAR gotoLabel[MAX_PATH];
|
||||
|
|
|
@ -1439,7 +1439,7 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
|||
/* Process the first command, if there is one */
|
||||
if (executecmds && firstcmd && *firstcmd) {
|
||||
WCHAR *command = WCMD_strdupW(firstcmd);
|
||||
WCMD_execute (firstcmd, (*cmdList)->redirects, variable, value, cmdList);
|
||||
WCMD_execute (firstcmd, (*cmdList)->redirects, variable, value, cmdList, FALSE);
|
||||
HeapFree(GetProcessHeap(), 0, command);
|
||||
}
|
||||
|
||||
|
@ -1468,14 +1468,14 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
|||
(*cmdList)->prevDelim == CMD_ONSUCCESS) {
|
||||
if (processThese && (*cmdList)->command) {
|
||||
WCMD_execute ((*cmdList)->command, (*cmdList)->redirects, variable,
|
||||
value, cmdList);
|
||||
value, cmdList, FALSE);
|
||||
}
|
||||
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, variable, value);
|
||||
*cmdList = WCMD_process_commands(*cmdList, TRUE, variable, value, FALSE);
|
||||
WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
|
||||
}
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
|
@ -1497,7 +1497,7 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd,
|
|||
/* Skip leading whitespace between condition and the command */
|
||||
while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
|
||||
if (*cmd) {
|
||||
WCMD_execute (cmd, (*cmdList)->redirects, variable, value, cmdList);
|
||||
WCMD_execute (cmd, (*cmdList)->redirects, variable, value, cmdList, FALSE);
|
||||
}
|
||||
}
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
|
@ -1809,7 +1809,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
|
|||
|
||||
/* Execute program and redirect output */
|
||||
wsprintfW(temp_cmd, redirOut, (itemStart+1), temp_file);
|
||||
WCMD_execute (itemStart, temp_cmd, NULL, NULL, NULL);
|
||||
WCMD_execute (itemStart, temp_cmd, NULL, NULL, NULL, FALSE);
|
||||
|
||||
/* Open the file, read line by line and process */
|
||||
input = CreateFileW(temp_file, GENERIC_READ, FILE_SHARE_READ,
|
||||
|
|
|
@ -1599,6 +1599,22 @@ echo %ErrorLevel%
|
|||
rem First look for programs in the path before trying a builtin
|
||||
echo echo non-builtin dir> dir.cmd
|
||||
call dir /b
|
||||
del dir.cmd
|
||||
rem The below line equates to call (, which does nothing, then the
|
||||
rem subsequent lines are executed.
|
||||
call (
|
||||
echo Line one
|
||||
echo Line two
|
||||
)
|
||||
rem The below line equates to call if, which always fails, then the
|
||||
rem subsequent lines are executed. Note cmd.exe swallows all lines
|
||||
rem starting with )
|
||||
call if 1==1 (
|
||||
echo Get if
|
||||
) else (
|
||||
echo ... and else!
|
||||
)
|
||||
call call call echo passed
|
||||
cd .. & rd /s/q foobar
|
||||
|
||||
echo ------------ Testing SHIFT ------------
|
||||
|
|
|
@ -824,14 +824,19 @@ foo ""
|
|||
foo ''
|
||||
'' bar
|
||||
--- with builtins
|
||||
@todo_wine@0
|
||||
@todo_wine@foo created
|
||||
@todo_wine@Should expand foobaz
|
||||
@todo_wine@batfile
|
||||
@todo_wine@robinfile
|
||||
@todo_wine@1
|
||||
@todo_wine@1
|
||||
0
|
||||
foo created
|
||||
Should expand foobaz
|
||||
batfile
|
||||
robinfile
|
||||
1
|
||||
1
|
||||
non-builtin dir
|
||||
Line one
|
||||
Line two
|
||||
Get if
|
||||
... and else!
|
||||
passed
|
||||
------------ Testing SHIFT ------------
|
||||
'p1' 'p2' 'p3' 'p4' 'p5'
|
||||
'p2' 'p3' 'p4' 'p5' ''
|
||||
|
|
|
@ -121,11 +121,11 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWO
|
|||
|
||||
WCHAR *WCMD_ReadAndParseLine(const WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom);
|
||||
CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
|
||||
const WCHAR *var, const WCHAR *val);
|
||||
const WCHAR *var, const WCHAR *val, BOOL retrycall);
|
||||
void WCMD_free_commands(CMD_LIST *cmds);
|
||||
void WCMD_execute (const WCHAR *orig_command, const WCHAR *redirects,
|
||||
const WCHAR *parameter, const WCHAR *substitution,
|
||||
CMD_LIST **cmdList);
|
||||
CMD_LIST **cmdList, BOOL retrycall);
|
||||
|
||||
/* Data structure to hold context when executing batch files */
|
||||
|
||||
|
|
|
@ -1000,6 +1000,9 @@ static void init_msvcrt_io_block(STARTUPINFOW* st)
|
|||
* Launching
|
||||
* Once a match has been found, it is launched - Code currently uses
|
||||
* findexecutable to achieve this which is left untouched.
|
||||
* If an executable has not been found, and we were launched through
|
||||
* a call, we need to check if the command is an internal command,
|
||||
* so go back through wcmd_execute.
|
||||
*/
|
||||
|
||||
void WCMD_run_program (WCHAR *command, BOOL called)
|
||||
|
@ -1197,6 +1200,8 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
|||
if (!status)
|
||||
break;
|
||||
|
||||
called = FALSE; /* No need to retry as we launched something */
|
||||
|
||||
if (!assumeInternal && !console) errorlevel = 0;
|
||||
else
|
||||
{
|
||||
|
@ -1212,6 +1217,18 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
|||
}
|
||||
}
|
||||
|
||||
/* Not found anywhere - were we called? */
|
||||
if (called) {
|
||||
CMD_LIST *toExecute = NULL; /* Commands left to be executed */
|
||||
|
||||
/* Parse the command string, without reading any more input */
|
||||
WCMD_ReadAndParseLine(command, &toExecute, INVALID_HANDLE_VALUE);
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL, called);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not found anywhere - give up */
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
WCMD_print_error ();
|
||||
|
@ -1226,10 +1243,13 @@ void WCMD_run_program (WCHAR *command, BOOL called)
|
|||
/*****************************************************************************
|
||||
* Process one command. If the command is EXIT this routine does not return.
|
||||
* We will recurse through here executing batch files.
|
||||
* Note: If call is used to a non-existing program, we reparse the line and
|
||||
* try to run it as an internal command. 'retrycall' represents whether
|
||||
* we are attempting this retry.
|
||||
*/
|
||||
void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||
const WCHAR *forVariable, const WCHAR *forValue,
|
||||
CMD_LIST **cmdList)
|
||||
CMD_LIST **cmdList, BOOL retrycall)
|
||||
{
|
||||
WCHAR *cmd, *p, *redir;
|
||||
int status, i;
|
||||
|
@ -1487,18 +1507,12 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
case WCMD_ECHO:
|
||||
WCMD_echo(&whichcmd[count]);
|
||||
break;
|
||||
case WCMD_FOR:
|
||||
WCMD_for (p, cmdList);
|
||||
break;
|
||||
case WCMD_GOTO:
|
||||
WCMD_goto (cmdList);
|
||||
break;
|
||||
case WCMD_HELP:
|
||||
WCMD_give_help (p);
|
||||
break;
|
||||
case WCMD_IF:
|
||||
WCMD_if (p, cmdList);
|
||||
break;
|
||||
case WCMD_LABEL:
|
||||
WCMD_volume (TRUE, p);
|
||||
break;
|
||||
|
@ -1587,6 +1601,17 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
case WCMD_EXIT:
|
||||
WCMD_exit (cmdList);
|
||||
break;
|
||||
case WCMD_FOR:
|
||||
case WCMD_IF:
|
||||
/* Very oddly, probably because of all the special parsing required for
|
||||
these two commands, neither for nor if are supported when called,
|
||||
ie call if 1==1... will fail. */
|
||||
if (!retrycall) {
|
||||
if (i==WCMD_FOR) WCMD_for (p, cmdList);
|
||||
else if (i==WCMD_IF) WCMD_if (p, cmdList);
|
||||
break;
|
||||
}
|
||||
/* else: drop through */
|
||||
default:
|
||||
prev_echo_mode = echo_mode;
|
||||
WCMD_run_program (whichcmd, FALSE);
|
||||
|
@ -2240,7 +2265,8 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
|
|||
* Process all the commands read in so far
|
||||
*/
|
||||
CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
|
||||
const WCHAR *var, const WCHAR *val) {
|
||||
const WCHAR *var, const WCHAR *val,
|
||||
BOOL retrycall) {
|
||||
|
||||
int bdepth = -1;
|
||||
|
||||
|
@ -2265,7 +2291,7 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
|
|||
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));
|
||||
WCMD_execute (thisCmd->command, thisCmd->redirects, var, val, &thisCmd);
|
||||
WCMD_execute (thisCmd->command, thisCmd->redirects, var, val, &thisCmd, retrycall);
|
||||
}
|
||||
|
||||
/* Step on unless the command itself already stepped on */
|
||||
|
@ -2555,7 +2581,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, FALSE, NULL, NULL);
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
|
||||
|
@ -2642,7 +2668,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, FALSE, NULL, NULL);
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, cmd);
|
||||
|
@ -2662,7 +2688,7 @@ int wmain (int argc, WCHAR *argvW[])
|
|||
if (echo_mode) WCMD_show_prompt();
|
||||
if (!WCMD_ReadAndParseLine(NULL, &toExecute, GetStdHandle(STD_INPUT_HANDLE)))
|
||||
break;
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL);
|
||||
WCMD_process_commands(toExecute, FALSE, NULL, NULL, FALSE);
|
||||
WCMD_free_commands(toExecute);
|
||||
toExecute = NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue