mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-18 09:26:17 +00:00
cmd: Add helpers to handle list in degenerated binary tree.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
This commit is contained in:
parent
7e70824ed5
commit
603e81a37a
|
@ -1523,7 +1523,7 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
|||
BOOL isIF, BOOL executecmds)
|
||||
{
|
||||
CMD_NODE *curPosition = *cmdList;
|
||||
int myDepth = (*cmdList)->single->bracketDepth;
|
||||
int myDepth = CMD_node_get_depth(*cmdList);
|
||||
|
||||
WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d), isIF(%d)\n", cmdList,
|
||||
wine_dbgstr_w(firstcmd), executecmds, isIF);
|
||||
|
@ -1534,13 +1534,13 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
|||
/* Process the first command, if there is one */
|
||||
if (executecmds && firstcmd && *firstcmd) {
|
||||
WCHAR *command = xstrdupW(firstcmd);
|
||||
WCMD_execute (firstcmd, (*cmdList)->single->redirects, cmdList, FALSE);
|
||||
WCMD_execute (firstcmd, CMD_node_get_command(*cmdList)->redirects, cmdList, FALSE);
|
||||
free(command);
|
||||
}
|
||||
|
||||
|
||||
/* If it didn't move the position, step to next command */
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
/* Process any other parts of the command */
|
||||
if (*cmdList) {
|
||||
|
@ -1552,74 +1552,74 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
|||
|
||||
WINE_TRACE("Processing cmdList(%p) - delim(%d) bd(%d / %d) processThese(%d)\n",
|
||||
*cmdList,
|
||||
(*cmdList)->single->prevDelim,
|
||||
(*cmdList)->single->bracketDepth,
|
||||
CMD_node_get_command(*cmdList)->prevDelim,
|
||||
CMD_node_get_depth(*cmdList),
|
||||
myDepth,
|
||||
processThese);
|
||||
|
||||
/* Execute any statements appended to the line */
|
||||
/* FIXME: Only if previous call worked for && or failed for || */
|
||||
if ((*cmdList)->single->prevDelim == CMD_ONFAILURE ||
|
||||
(*cmdList)->single->prevDelim == CMD_ONSUCCESS) {
|
||||
if (processThese && (*cmdList)->single->command) {
|
||||
WCMD_execute ((*cmdList)->single->command, (*cmdList)->single->redirects,
|
||||
if (CMD_node_get_command(*cmdList)->prevDelim == CMD_ONFAILURE ||
|
||||
CMD_node_get_command(*cmdList)->prevDelim == CMD_ONSUCCESS) {
|
||||
if (processThese && CMD_node_get_command(*cmdList)->command) {
|
||||
WCMD_execute (CMD_node_get_command(*cmdList)->command, CMD_node_get_command(*cmdList)->redirects,
|
||||
cmdList, FALSE);
|
||||
}
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
/* Execute any appended to the statement with (...) */
|
||||
} else if ((*cmdList)->single->bracketDepth > myDepth) {
|
||||
} else if (CMD_node_get_depth(*cmdList) > myDepth) {
|
||||
if (processThese) {
|
||||
*cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE);
|
||||
} else {
|
||||
WINE_TRACE("Skipping command %p due to stack depth\n", *cmdList);
|
||||
}
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
/* End of the command - does 'ELSE ' follow as the next command? */
|
||||
} else {
|
||||
if (isIF && WCMD_keyword_ws_found(L"else", (*cmdList)->single->command)) {
|
||||
if (isIF && WCMD_keyword_ws_found(L"else", CMD_node_get_command(*cmdList)->command)) {
|
||||
/* Swap between if and else processing */
|
||||
processThese = !executecmds;
|
||||
|
||||
/* Process the ELSE part */
|
||||
if (processThese) {
|
||||
const int keyw_len = lstrlenW(L"else") + 1;
|
||||
WCHAR *cmd = ((*cmdList)->single->command) + keyw_len;
|
||||
WCHAR *cmd = (CMD_node_get_command(*cmdList)->command) + keyw_len;
|
||||
|
||||
/* Skip leading whitespace between condition and the command */
|
||||
while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
|
||||
if (*cmd) {
|
||||
WCMD_execute (cmd, (*cmdList)->single->redirects, cmdList, FALSE);
|
||||
WCMD_execute (cmd, CMD_node_get_command(*cmdList)->redirects, cmdList, FALSE);
|
||||
}
|
||||
} else {
|
||||
/* Loop skipping all commands until we get back to the current
|
||||
depth, including skipping commands and their subsequent
|
||||
pipes (eg cmd | prog) */
|
||||
do {
|
||||
*cmdList = (*cmdList)->nextcommand;
|
||||
*cmdList = CMD_node_next(*cmdList);
|
||||
} while (*cmdList &&
|
||||
((*cmdList)->single->bracketDepth > myDepth ||
|
||||
(*cmdList)->single->prevDelim));
|
||||
(CMD_node_get_depth(*cmdList) > myDepth ||
|
||||
CMD_node_get_command(*cmdList)->prevDelim));
|
||||
|
||||
/* After the else is complete, we need to now process subsequent commands */
|
||||
processThese = TRUE;
|
||||
}
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
/* If we were in an IF statement and we didn't 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)->single->bracketDepth == myDepth) {
|
||||
if (WCMD_keyword_ws_found(L"do", (*cmdList)->single->command)) {
|
||||
} else if (isIF && CMD_node_get_depth(*cmdList) == myDepth) {
|
||||
if (WCMD_keyword_ws_found(L"do", CMD_node_get_command(*cmdList)->command)) {
|
||||
WINE_TRACE("Still inside FOR-loop, not an end of IF statement\n");
|
||||
*cmdList = (*cmdList)->nextcommand;
|
||||
*cmdList = CMD_node_next(*cmdList);
|
||||
} else {
|
||||
WINE_TRACE("Found end of this nested IF statement, ending this if\n");
|
||||
break;
|
||||
}
|
||||
} else if (!processThese) {
|
||||
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
WINE_TRACE("Skipping this command, as in not process mode (next = %p)\n", *cmdList);
|
||||
} else {
|
||||
WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
|
||||
|
@ -2219,26 +2219,26 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
}
|
||||
|
||||
/* Save away where the set of data starts and the variable */
|
||||
thisDepth = (*cmdList)->single->bracketDepth;
|
||||
*cmdList = (*cmdList)->nextcommand;
|
||||
thisDepth = CMD_node_get_depth(*cmdList);
|
||||
*cmdList = CMD_node_next(*cmdList);
|
||||
setStart = (*cmdList);
|
||||
|
||||
/* Skip until the close bracket */
|
||||
WINE_TRACE("Searching %p as the set\n", *cmdList);
|
||||
while (*cmdList &&
|
||||
(*cmdList)->single->command != NULL &&
|
||||
(*cmdList)->single->bracketDepth > thisDepth) {
|
||||
CMD_node_get_command(*cmdList)->command != NULL &&
|
||||
CMD_node_get_depth(*cmdList) > thisDepth) {
|
||||
WINE_TRACE("Skipping %p which is part of the set\n", *cmdList);
|
||||
*cmdList = (*cmdList)->nextcommand;
|
||||
*cmdList = CMD_node_next(*cmdList);
|
||||
}
|
||||
|
||||
/* Skip the close bracket, if there is one */
|
||||
if (*cmdList) *cmdList = (*cmdList)->nextcommand;
|
||||
if (*cmdList) *cmdList = CMD_node_next(*cmdList);
|
||||
|
||||
/* Syntax error if missing close bracket, or nothing following it
|
||||
and once we have the complete set, we expect a DO */
|
||||
WINE_TRACE("Looking for 'do ' in %p\n", *cmdList);
|
||||
if ((*cmdList == NULL) || !WCMD_keyword_ws_found(L"do", (*cmdList)->single->command)) {
|
||||
if ((*cmdList == NULL) || !WCMD_keyword_ws_found(L"do", CMD_node_get_command(*cmdList)->command)) {
|
||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return;
|
||||
}
|
||||
|
@ -2252,7 +2252,7 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
/* Save away the starting position for the commands (and offset for the
|
||||
first one) */
|
||||
cmdStart = *cmdList;
|
||||
firstCmd = (*cmdList)->single->command + 3; /* Skip 'do ' */
|
||||
firstCmd = CMD_node_get_command(*cmdList)->command + 3; /* Skip 'do ' */
|
||||
itemNum = 0;
|
||||
|
||||
/* If we are recursing directories (ie /R), add all sub directories now, then
|
||||
|
@ -2262,8 +2262,8 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
thisSet = setStart;
|
||||
/* Loop through all set entries */
|
||||
while (thisSet &&
|
||||
thisSet->single->command != NULL &&
|
||||
thisSet->single->bracketDepth >= thisDepth) {
|
||||
CMD_node_get_command(thisSet)->command != NULL &&
|
||||
CMD_node_get_depth(thisSet) >= thisDepth) {
|
||||
|
||||
/* Loop through all entries on the same line */
|
||||
WCHAR *staticitem;
|
||||
|
@ -2272,7 +2272,7 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
|
||||
WINE_TRACE("Processing for set %p\n", thisSet);
|
||||
i = 0;
|
||||
while (*(staticitem = WCMD_parameter (thisSet->single->command, i, &itemStart, TRUE, FALSE))) {
|
||||
while (*(staticitem = WCMD_parameter (CMD_node_get_command(thisSet)->command, i, &itemStart, TRUE, FALSE))) {
|
||||
|
||||
/*
|
||||
* If the parameter within the set has a wildcard then search for matching files
|
||||
|
@ -2455,7 +2455,7 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
}
|
||||
|
||||
/* Move onto the next set line */
|
||||
if (thisSet) thisSet = thisSet->nextcommand;
|
||||
if (thisSet) thisSet = CMD_node_next(thisSet);
|
||||
}
|
||||
|
||||
/* If /L is provided, now run the for loop */
|
||||
|
@ -2516,7 +2516,7 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
|||
value needs to be the NEXT command to execute, which it either is, or
|
||||
we need to step over the closing bracket */
|
||||
*cmdList = cmdEnd;
|
||||
if (cmdEnd && cmdEnd->single->command == NULL) *cmdList = cmdEnd->nextcommand;
|
||||
if (cmdEnd && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef enum _CMDdelimiters {
|
|||
CMD_NONE, /* End of line or single & */
|
||||
CMD_ONFAILURE, /* || */
|
||||
CMD_ONSUCCESS, /* && */
|
||||
CMD_PIPE /* Single | */
|
||||
CMD_PIPE, /* Single | */
|
||||
} CMD_DELIMITERS;
|
||||
|
||||
/* Data structure to hold commands to be processed */
|
||||
|
@ -60,6 +60,22 @@ typedef struct _CMD_NODE
|
|||
struct _CMD_NODE *nextcommand; /* Next command string to execute */
|
||||
} CMD_NODE;
|
||||
|
||||
/* temporary helpers to fake a list into a tree */
|
||||
/* Note: for binary op, left should be a CMD_SINGLE node */
|
||||
static inline CMD_COMMAND *CMD_node_get_command(const CMD_NODE *node)
|
||||
{
|
||||
return node->single;
|
||||
}
|
||||
static inline CMD_NODE *CMD_node_next(const CMD_NODE *node)
|
||||
{
|
||||
return node->nextcommand;
|
||||
}
|
||||
static inline int CMD_node_get_depth(const CMD_NODE *node)
|
||||
{
|
||||
return node->single->bracketDepth;
|
||||
}
|
||||
/* end temporary */
|
||||
|
||||
void WCMD_assoc (const WCHAR *, BOOL);
|
||||
void WCMD_batch (WCHAR *, WCHAR *, BOOL, WCHAR *, HANDLE);
|
||||
void WCMD_call (WCHAR *command);
|
||||
|
|
|
@ -1334,8 +1334,8 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
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)->nextcommand &&
|
||||
(*cmdList)->nextcommand->single->prevDelim == CMD_PIPE) {
|
||||
cmdList && CMD_node_next(*cmdList) &&
|
||||
CMD_node_get_command(CMD_node_next(*cmdList))->prevDelim == CMD_PIPE) {
|
||||
|
||||
WCHAR temp_path[MAX_PATH];
|
||||
|
||||
|
@ -1345,14 +1345,14 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
|
||||
/* Generate a unique temporary filename */
|
||||
GetTempPathW(ARRAY_SIZE(temp_path), temp_path);
|
||||
GetTempFileNameW(temp_path, L"CMD", 0, (*cmdList)->nextcommand->single->pipeFile);
|
||||
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((*cmdList)->nextcommand->single->pipeFile));
|
||||
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) {
|
||||
wsprintfW (new_redir, L"%s > %s", redirects, (*cmdList)->nextcommand->single->pipeFile);
|
||||
wsprintfW (new_redir, L"%s > %s", redirects, CMD_node_get_command(CMD_node_next(*cmdList))->pipeFile);
|
||||
WINE_TRACE("Redirects now %s\n", wine_dbgstr_w(new_redir));
|
||||
} else {
|
||||
lstrcpyW(new_redir, redirects);
|
||||
|
@ -1404,9 +1404,9 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
*/
|
||||
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)->single->pipeFile[0] != 0x00) {
|
||||
WINE_TRACE("Input coming from %s\n", wine_dbgstr_w((*cmdList)->single->pipeFile));
|
||||
h = CreateFileW((*cmdList)->single->pipeFile, GENERIC_READ,
|
||||
if (cmdList && CMD_node_get_command(*cmdList)->pipeFile[0] != 0x00) {
|
||||
WINE_TRACE("Input coming from %s\n", wine_dbgstr_w(CMD_node_get_command(*cmdList)->pipeFile));
|
||||
h = CreateFileW(CMD_node_get_command(*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) {
|
||||
|
@ -1418,7 +1418,7 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
|||
SetStdHandle (STD_INPUT_HANDLE, h);
|
||||
|
||||
/* No need to remember the temporary name any longer once opened */
|
||||
(*cmdList)->single->pipeFile[0] = 0x00;
|
||||
CMD_node_get_command(*cmdList)->pipeFile[0] = 0x00;
|
||||
|
||||
/* Otherwise STDIN could come from a '<' redirect */
|
||||
} else if ((pos = wcschr(new_redir,'<')) != NULL) {
|
||||
|
@ -1681,12 +1681,12 @@ static void WCMD_DumpCommands(CMD_NODE *commands) {
|
|||
while (thisCmd != NULL) {
|
||||
WINE_TRACE("%p %d %2.2d %p %s Redir:%s\n",
|
||||
thisCmd,
|
||||
thisCmd->single->prevDelim,
|
||||
thisCmd->single->bracketDepth,
|
||||
thisCmd->nextcommand,
|
||||
wine_dbgstr_w(thisCmd->single->command),
|
||||
wine_dbgstr_w(thisCmd->single->redirects));
|
||||
thisCmd = thisCmd->nextcommand;
|
||||
CMD_node_get_command(thisCmd)->prevDelim,
|
||||
CMD_node_get_depth(thisCmd),
|
||||
CMD_node_next(thisCmd),
|
||||
wine_dbgstr_w(CMD_node_get_command(thisCmd)->command),
|
||||
wine_dbgstr_w(CMD_node_get_command(thisCmd)->redirects));
|
||||
thisCmd = CMD_node_next(thisCmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2369,7 +2369,7 @@ CMD_NODE *WCMD_process_commands(CMD_NODE *thisCmd, BOOL oneBracket,
|
|||
|
||||
int bdepth = -1;
|
||||
|
||||
if (thisCmd && oneBracket) bdepth = thisCmd->single->bracketDepth;
|
||||
if (thisCmd && oneBracket) bdepth = CMD_node_get_depth(thisCmd);
|
||||
|
||||
/* Loop through the commands, processing them one by one */
|
||||
while (thisCmd) {
|
||||
|
@ -2378,23 +2378,23 @@ CMD_NODE *WCMD_process_commands(CMD_NODE *thisCmd, BOOL oneBracket,
|
|||
|
||||
/* If processing one bracket only, and we find the end bracket
|
||||
entry (or less), return */
|
||||
if (oneBracket && !thisCmd->single->command &&
|
||||
bdepth <= thisCmd->single->bracketDepth) {
|
||||
if (oneBracket && !CMD_node_get_command(thisCmd)->command &&
|
||||
bdepth <= CMD_node_get_depth(thisCmd)) {
|
||||
WINE_TRACE("Finished bracket @ %p, next command is %p\n",
|
||||
thisCmd, thisCmd->nextcommand);
|
||||
return thisCmd->nextcommand;
|
||||
thisCmd, CMD_node_next(thisCmd));
|
||||
return CMD_node_next(thisCmd);
|
||||
}
|
||||
|
||||
/* 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->single->command && thisCmd->single->command[0] != ':') {
|
||||
WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->single->command));
|
||||
WCMD_execute (thisCmd->single->command, thisCmd->single->redirects, &thisCmd, retrycall);
|
||||
if (CMD_node_get_command(thisCmd)->command && CMD_node_get_command(thisCmd)->command[0] != ':') {
|
||||
WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(CMD_node_get_command(thisCmd)->command));
|
||||
WCMD_execute (CMD_node_get_command(thisCmd)->command, CMD_node_get_command(thisCmd)->redirects, &thisCmd, retrycall);
|
||||
}
|
||||
|
||||
/* Step on unless the command itself already stepped on */
|
||||
if (thisCmd == origCmd) thisCmd = thisCmd->nextcommand;
|
||||
if (thisCmd == origCmd) thisCmd = CMD_node_next(thisCmd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2419,8 +2419,8 @@ void WCMD_free_commands(CMD_NODE *cmds) {
|
|||
/* Loop through the commands, freeing them one by one */
|
||||
while (cmds) {
|
||||
CMD_NODE *thisCmd = cmds;
|
||||
cmds = cmds->nextcommand;
|
||||
WCMD_free_command(thisCmd->single);
|
||||
cmds = CMD_node_next(cmds);
|
||||
WCMD_free_command(CMD_node_get_command(thisCmd));
|
||||
free(thisCmd);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue