mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-30 05:31:39 +00:00
cmd: Create helper to execute a command.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
This commit is contained in:
parent
a899caac7b
commit
855642d565
|
@ -1445,23 +1445,15 @@ static BOOL set_std_redirections(CMD_REDIRECTION *redir, WCHAR *in_pipe)
|
|||
* try to run it as an internal command. 'retrycall' represents whether
|
||||
* we are attempting this retry.
|
||||
*/
|
||||
void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects,
|
||||
CMD_NODE **cmdList, BOOL retrycall)
|
||||
static void execute_single_command(const WCHAR *command, CMD_NODE **cmdList, BOOL retrycall)
|
||||
{
|
||||
WCHAR *cmd, *parms_start;
|
||||
int status, i, cmd_index;
|
||||
DWORD count;
|
||||
int status, cmd_index, count;
|
||||
WCHAR *whichcmd;
|
||||
WCHAR *new_cmd = NULL;
|
||||
HANDLE old_stdhandles[3] = {GetStdHandle (STD_INPUT_HANDLE),
|
||||
GetStdHandle (STD_OUTPUT_HANDLE),
|
||||
GetStdHandle (STD_ERROR_HANDLE)};
|
||||
static DWORD idx_stdhandles[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
|
||||
BOOL prev_echo_mode, piped = FALSE;
|
||||
CMD_REDIRECTION *piped_redir;
|
||||
BOOL prev_echo_mode;
|
||||
|
||||
WINE_TRACE("command on entry:%s (%p)\n",
|
||||
wine_dbgstr_w(command), cmdList);
|
||||
TRACE("command on entry:%s (%p)\n", wine_dbgstr_w(command), cmdList);
|
||||
|
||||
/* Move copy of the command onto the heap so it can be expanded */
|
||||
new_cmd = xalloc(MAXSTRING * sizeof(WCHAR));
|
||||
|
@ -1470,7 +1462,7 @@ void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects,
|
|||
|
||||
/* Strip leading whitespaces, and a '@' if supplied */
|
||||
whichcmd = WCMD_skip_leading_spaces(cmd);
|
||||
WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd));
|
||||
TRACE("Command: '%s'\n", wine_dbgstr_w(cmd));
|
||||
if (whichcmd[0] == '@') whichcmd++;
|
||||
|
||||
/* Check if the command entered is internal, and identify which one */
|
||||
|
@ -1484,40 +1476,6 @@ void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects,
|
|||
}
|
||||
parms_start = WCMD_skip_leading_spaces (&whichcmd[count]);
|
||||
|
||||
/* 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
|
||||
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
|
||||
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 */
|
||||
if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF) &&
|
||||
cmdList && (*cmdList)->op == CMD_PIPE) {
|
||||
|
||||
WCHAR temp_path[MAX_PATH];
|
||||
|
||||
/* Remember piping is in action */
|
||||
WINE_TRACE("Output needs to be piped\n");
|
||||
piped = TRUE;
|
||||
|
||||
/* Generate a unique temporary filename */
|
||||
GetTempPathW(ARRAY_SIZE(temp_path), temp_path);
|
||||
GetTempFileNameW(temp_path, L"CMD", 0, CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile);
|
||||
WINE_TRACE("Using temporary file of %s\n",
|
||||
wine_dbgstr_w(CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile));
|
||||
}
|
||||
|
||||
/* If piped output, send stdout to the pipe by appending >filename to redirects */
|
||||
if (piped) {
|
||||
const WCHAR *to = CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile;
|
||||
piped_redir = redirection_create_file(REDIR_WRITE_TO, 1, to);
|
||||
piped_redir->next = redirects;
|
||||
} else {
|
||||
piped_redir = redirects;
|
||||
}
|
||||
/* Expand variables in command line mode only (batch mode will
|
||||
be expanded as the line is read in, except for 'for' loops) */
|
||||
handleExpansion(new_cmd, (context != NULL), delayedsubst);
|
||||
|
||||
/*
|
||||
|
@ -1548,27 +1506,8 @@ void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
WCHAR *in_pipe = NULL;
|
||||
if (cmdList && CMD_node_get_command(*cmdList)->pipeFile[0] != 0x00)
|
||||
in_pipe = CMD_node_get_command(*cmdList)->pipeFile;
|
||||
if (!set_std_redirections(piped_redir, in_pipe)) {
|
||||
WCMD_print_error ();
|
||||
goto cleanup;
|
||||
}
|
||||
if (in_pipe)
|
||||
/* No need to remember the temporary name any longer once opened */
|
||||
in_pipe[0] = 0x00;
|
||||
} else {
|
||||
WINE_TRACE("Not touching redirects for a FOR or IF command\n");
|
||||
}
|
||||
WCMD_parse (parms_start, quals, param1, param2);
|
||||
WINE_TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2));
|
||||
TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2));
|
||||
|
||||
if (cmd_index <= WCMD_EXIT && (parms_start[0] == '/') && (parms_start[1] == '?')) {
|
||||
/* this is a help request for a builtin program */
|
||||
|
@ -1722,16 +1661,116 @@ void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects,
|
|||
WCMD_run_program (whichcmd, FALSE);
|
||||
echo_mode = prev_echo_mode;
|
||||
}
|
||||
cleanup:
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* 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, CMD_REDIRECTION *redirects,
|
||||
CMD_NODE **cmdList, BOOL retrycall)
|
||||
{
|
||||
WCHAR *cmd;
|
||||
int i, cmd_index, count;
|
||||
WCHAR *whichcmd;
|
||||
WCHAR *new_cmd = NULL;
|
||||
HANDLE old_stdhandles[3] = {GetStdHandle (STD_INPUT_HANDLE),
|
||||
GetStdHandle (STD_OUTPUT_HANDLE),
|
||||
GetStdHandle (STD_ERROR_HANDLE)};
|
||||
static DWORD idx_stdhandles[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
|
||||
CMD_REDIRECTION *piped_redir = redirects;
|
||||
|
||||
TRACE("command on entry:%s (%p)\n", wine_dbgstr_w(command), cmdList);
|
||||
|
||||
/* Move copy of the command onto the heap so it can be expanded */
|
||||
new_cmd = xalloc(MAXSTRING * sizeof(WCHAR));
|
||||
lstrcpyW(new_cmd, command);
|
||||
cmd = new_cmd;
|
||||
|
||||
/* Strip leading whitespaces, and a '@' if supplied */
|
||||
whichcmd = WCMD_skip_leading_spaces(cmd);
|
||||
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 (cmd_index=0; cmd_index<=WCMD_EXIT; cmd_index++) {
|
||||
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
||||
whichcmd, count, inbuilt[cmd_index], -1) == CSTR_EQUAL) break;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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
|
||||
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 */
|
||||
/* FIXME this is wrong: we need to discriminate between redirection in individual
|
||||
* commands in the blocks, vs redirection of the whole command.
|
||||
*/
|
||||
if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF) &&
|
||||
cmdList && (*cmdList)->op == CMD_PIPE)
|
||||
{
|
||||
const WCHAR *to;
|
||||
WCHAR temp_path[MAX_PATH];
|
||||
|
||||
/* Remember piping is in action */
|
||||
TRACE("Output needs to be piped\n");
|
||||
|
||||
/* Generate a unique temporary filename */
|
||||
GetTempPathW(ARRAY_SIZE(temp_path), temp_path);
|
||||
GetTempFileNameW(temp_path, L"CMD", 0, CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile);
|
||||
TRACE("Using temporary file of %s\n",
|
||||
wine_dbgstr_w(CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile));
|
||||
/* send stdout to the pipe by appending >filename to redirects */
|
||||
to = CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile;
|
||||
piped_redir = redirection_create_file(REDIR_WRITE_TO, 1, to);
|
||||
piped_redir->next = redirects;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* FIXME this is wrong (see above) */
|
||||
if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF)) {
|
||||
WCHAR *in_pipe = NULL;
|
||||
if (cmdList && CMD_node_get_command(*cmdList)->pipeFile[0] != 0x00)
|
||||
in_pipe = CMD_node_get_command(*cmdList)->pipeFile;
|
||||
if (!set_std_redirections(piped_redir, in_pipe)) {
|
||||
WCMD_print_error ();
|
||||
goto cleanup;
|
||||
}
|
||||
if (in_pipe)
|
||||
/* No need to remember the temporary name any longer once opened */
|
||||
in_pipe[0] = 0x00;
|
||||
} else {
|
||||
TRACE("Not touching redirects for a FOR or IF command\n");
|
||||
}
|
||||
execute_single_command(command, cmdList, retrycall);
|
||||
cleanup:
|
||||
free(cmd);
|
||||
if (piped_redir != redirects) free(piped_redir);
|
||||
|
||||
/* Restore old handles */
|
||||
for (i=0; i<3; i++) {
|
||||
if (old_stdhandles[i] != GetStdHandle(idx_stdhandles[i])) {
|
||||
CloseHandle (GetStdHandle (idx_stdhandles[i]));
|
||||
SetStdHandle (idx_stdhandles[i], old_stdhandles[i]);
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (old_stdhandles[i] != GetStdHandle(idx_stdhandles[i]))
|
||||
{
|
||||
CloseHandle(GetStdHandle (idx_stdhandles[i]));
|
||||
SetStdHandle(idx_stdhandles[i], old_stdhandles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue