From: Eric Pouech epouech@codeweavers.com
For now, the tree is degenerated into a list (as it was before).
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/builtins.c | 33 +++++++--- programs/cmd/wcmd.h | 37 +++++++---- programs/cmd/wcmdmain.c | 136 ++++++++++++++++++++++++++-------------- 3 files changed, 136 insertions(+), 70 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 4a012166e25..bc9ba9e5f11 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1524,6 +1524,7 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd, { CMD_NODE *curPosition = *cmdList; int myDepth = CMD_node_get_depth(*cmdList); + CMD_OPERATOR prev_op = CMD_CONCAT;
WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d), isIF(%d)\n", cmdList, wine_dbgstr_w(firstcmd), executecmds, isIF); @@ -1550,31 +1551,40 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd, /* execute all appropriate commands */ curPosition = *cmdList;
- WINE_TRACE("Processing cmdList(%p) - delim(%d) bd(%d / %d) processThese(%d)\n", + WINE_TRACE("Processing cmdList(%p) - operator(%d) bd(%d / %d) processThese(%d)\n", *cmdList, - CMD_node_get_command(*cmdList)->prevDelim, + prev_op, 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 (CMD_node_get_command(*cmdList)->prevDelim == CMD_ONFAILURE || - CMD_node_get_command(*cmdList)->prevDelim == CMD_ONSUCCESS) { + if (prev_op == CMD_ONFAILURE || + prev_op == 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 = CMD_node_next(*cmdList); + if (curPosition == *cmdList) + { + prev_op = (*cmdList)->op; + *cmdList = CMD_node_next(*cmdList); + }
/* Execute any appended to the statement with (...) */ } else if (CMD_node_get_depth(*cmdList) > myDepth) { if (processThese) { + /* FIXME this is wrong, we don't recompute prev_op */ *cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE); } else { WINE_TRACE("Skipping command %p due to stack depth\n", *cmdList); } - if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList); + if (curPosition == *cmdList) + { + prev_op = (*cmdList)->op; + *cmdList = CMD_node_next(*cmdList); + }
/* End of the command - does 'ELSE ' follow as the next command? */ } else { @@ -1597,15 +1607,20 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd, depth, including skipping commands and their subsequent pipes (eg cmd | prog) */ do { + prev_op = (*cmdList)->op; *cmdList = CMD_node_next(*cmdList); } while (*cmdList && (CMD_node_get_depth(*cmdList) > myDepth || - CMD_node_get_command(*cmdList)->prevDelim)); + (prev_op != CMD_SINGLE && prev_op != CMD_CONCAT)));
/* After the else is complete, we need to now process subsequent commands */ processThese = TRUE; } - if (curPosition == *cmdList) *cmdList = CMD_node_next(*cmdList); + if (curPosition == *cmdList) + { + prev_op = (*cmdList)->op; + *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 @@ -1613,6 +1628,7 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd, } 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"); + prev_op = (*cmdList)->op; *cmdList = CMD_node_next(*cmdList); } else { WINE_TRACE("Found end of this nested IF statement, ending this if\n"); @@ -1628,7 +1644,6 @@ static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd, } } } - return; }
static BOOL option_equals(WCHAR **haystack, const WCHAR *needle) diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index f004dfe4c4d..f538e4fc1a6 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -36,12 +36,14 @@
/* Data structure to hold commands delimiters/separators */
-typedef enum _CMDdelimiters { - CMD_NONE, /* End of line or single & */ - CMD_ONFAILURE, /* || */ - CMD_ONSUCCESS, /* && */ - CMD_PIPE, /* Single | */ -} CMD_DELIMITERS; +typedef enum _CMD_OPERATOR +{ + CMD_SINGLE, /* single command */ + CMD_CONCAT, /* & */ + CMD_ONFAILURE, /* || */ + CMD_ONSUCCESS, /* && */ + CMD_PIPE, /* Single | */ +} CMD_OPERATOR;
/* Data structure to hold commands to be processed */
@@ -49,30 +51,39 @@ typedef struct _CMD_COMMAND { WCHAR *command; /* Command string to execute */ WCHAR *redirects; /* Redirects in place */ - CMD_DELIMITERS prevDelim; /* Previous delimiter */ int bracketDepth;/* How deep bracketing have we got to */ WCHAR pipeFile[MAX_PATH]; /* Where to get input from for pipes */ } CMD_COMMAND;
typedef struct _CMD_NODE { - CMD_COMMAND *single; - struct _CMD_NODE *nextcommand; /* Next command string to execute */ + CMD_OPERATOR op; /* operator */ + union + { + CMD_COMMAND *command; /* CMD_SINGLE */ + struct /* binary operator (CMD_CONCAT, ONFAILURE, ONSUCCESS, PIPE) */ + { + struct _CMD_NODE *left; + struct _CMD_NODE *right; + }; + }; } 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; + if (node->op == CMD_SINGLE) return node->command; + /* assert(node->left && node->left->op == CMD_SINGLE); */ + return node->left->command; } static inline CMD_NODE *CMD_node_next(const CMD_NODE *node) { - return node->nextcommand; + return (node->op == CMD_SINGLE) ? NULL : node->right; } static inline int CMD_node_get_depth(const CMD_NODE *node) { - return node->single->bracketDepth; + CMD_COMMAND *cmd = CMD_node_get_command(node); + return cmd->bracketDepth; } /* end temporary */
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index ce7a32d79e0..2c5cf4a3196 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -942,6 +942,31 @@ static void WCMD_parse (const WCHAR *s, WCHAR *q, WCHAR *p1, WCHAR *p2) } }
+/* ============================== */ +/* Data structures for commands */ +/* ============================== */ + +static CMD_NODE *node_create_single(CMD_COMMAND *c) +{ + CMD_NODE *new = xalloc(sizeof(CMD_NODE)); + + new->op = CMD_SINGLE; + new->command = c; + + return new; +} + +static CMD_NODE *node_create_binary(CMD_OPERATOR op, CMD_NODE *l, CMD_NODE *r) +{ + CMD_NODE *new = xalloc(sizeof(CMD_NODE)); + + new->op = op; + new->left = l; + new->right = r; + + return new; +} + static void init_msvcrt_io_block(STARTUPINFOW* st) { STARTUPINFOW st_p; @@ -1334,8 +1359,7 @@ 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 && CMD_node_next(*cmdList) && - CMD_node_get_command(CMD_node_next(*cmdList))->prevDelim == CMD_PIPE) { + cmdList && (*cmdList)->op == CMD_PIPE) {
WCHAR temp_path[MAX_PATH];
@@ -1669,24 +1693,33 @@ WCHAR *WCMD_LoadMessage(UINT id) { return msg; }
+static const char *op2str(CMD_OPERATOR op) +{ + static const char* optable[] = {"op-single", "op-&", "op-||", "op-&&", "op-|"}; + if (op < ARRAY_SIZE(optable)) return optable[op]; + return "op-unk"; +} + /*************************************************************************** * WCMD_DumpCommands * * Dumps out the parsed command line to ensure syntax is correct */ -static void WCMD_DumpCommands(CMD_NODE *commands) { +static void WCMD_DumpCommands(CMD_NODE *commands) +{ CMD_NODE *thisCmd = commands;
WINE_TRACE("Parsed line:\n"); - while (thisCmd != NULL) { - WINE_TRACE("%p %d %2.2d %p %s Redir:%s\n", - thisCmd, - 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); + while (thisCmd != NULL) + { + TRACE("%p %2.2d %p %s Redir:%s %s\n", + thisCmd, + 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), + op2str(thisCmd->op)); + thisCmd = CMD_node_next(thisCmd); } }
@@ -1698,8 +1731,8 @@ static void WCMD_DumpCommands(CMD_NODE *commands) { static CMD_COMMAND *WCMD_createCommand(WCHAR *command, int *commandLen, WCHAR *redirs, int *redirLen, WCHAR **copyTo, int **copyToLen, - CMD_DELIMITERS prevDelim, int curDepth) - { + int curDepth) +{ CMD_COMMAND *thisEntry = NULL;
/* Allocate storage for command */ @@ -1730,21 +1763,24 @@ static CMD_COMMAND *WCMD_createCommand(WCHAR *command, int *commandLen, }
/* Fill in other fields */ - thisEntry->prevDelim = prevDelim; thisEntry->bracketDepth = curDepth; return thisEntry; }
-static void WCMD_appendCommand(CMD_COMMAND *command, CMD_NODE **node) +static void WCMD_appendCommand(CMD_OPERATOR op, CMD_COMMAND *command, CMD_NODE **node) { - CMD_NODE *new = xalloc(sizeof(CMD_NODE)); + /* append as left to right operators */ + if (*node) + { + CMD_NODE **last = node; + while ((*last)->op != CMD_SINGLE) + last = &(*last)->right;
- if (new) + *last = node_create_binary(op, *last, node_create_single(command)); + } + else { - new->single = command; - new->nextcommand = NULL; - for (; *node; node = &((*node)->nextcommand)) {} - *node = new; + *node = node_create_single(command); } }
@@ -1828,7 +1864,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE int *curLen; int curDepth = 0; CMD_COMMAND *single_cmd = NULL; - CMD_DELIMITERS prevDelim = CMD_NONE; + CMD_OPERATOR cmd_op = CMD_CONCAT; static WCHAR *extraSpace = NULL; /* Deliberately never freed */ BOOL inOneLine = FALSE; BOOL inFor = FALSE; @@ -2099,15 +2135,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE single_cmd = WCMD_createCommand(curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output); }
if (*(curPos+1) == '|') { curPos++; /* Skip other | */ - prevDelim = CMD_ONFAILURE; + cmd_op = CMD_ONFAILURE; } else { - prevDelim = CMD_PIPE; + cmd_op = CMD_PIPE; }
/* If in an IF or ELSE statement, put subsequent chained @@ -2172,8 +2208,8 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE single_cmd = WCMD_createCommand(curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output);
curDepth++; } else { @@ -2203,15 +2239,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE single_cmd = WCMD_createCommand(curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output); }
if (*(curPos+1) == '&') { curPos++; /* Skip other & */ - prevDelim = CMD_ONSUCCESS; + cmd_op = CMD_ONSUCCESS; } else { - prevDelim = CMD_NONE; + cmd_op = CMD_CONCAT; } /* If in an IF or ELSE statement, put subsequent chained commands at a higher depth as if brackets were supplied @@ -2235,17 +2271,17 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE single_cmd = WCMD_createCommand(curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output); }
/* Add an empty entry to the command list */ - prevDelim = CMD_NONE; + cmd_op = CMD_CONCAT; single_cmd = WCMD_createCommand(NULL, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output);
curDepth--;
@@ -2281,8 +2317,8 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE single_cmd = WCMD_createCommand(curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen, - prevDelim, curDepth); - WCMD_appendCommand(single_cmd, output); + curDepth); + WCMD_appendCommand(cmd_op, single_cmd, output);
/* If we had a single line if or else, and we pretended to add brackets, end them now */ @@ -2302,7 +2338,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE WINE_TRACE("Need to read more data as outstanding brackets or carets\n"); inOneLine = FALSE; ignoreBracket = FALSE; - prevDelim = CMD_NONE; + cmd_op = CMD_CONCAT; inQuotes = 0; memset(extraSpace, 0x00, (MAXSTRING+1) * sizeof(WCHAR)); extraData = extraSpace; @@ -2414,14 +2450,18 @@ static void WCMD_free_command(CMD_COMMAND *cmd) * pointer will be modified within the commands, and hence a single free * routine is simpler */ -void WCMD_free_commands(CMD_NODE *cmds) { - +void WCMD_free_commands(CMD_NODE *cmds) +{ /* Loop through the commands, freeing them one by one */ - while (cmds) { - CMD_NODE *thisCmd = cmds; - cmds = CMD_node_next(cmds); - WCMD_free_command(CMD_node_get_command(thisCmd)); - free(thisCmd); + while (cmds) + { + CMD_NODE *thisCmd = cmds; + cmds = CMD_node_next(cmds); + if (thisCmd->op == CMD_SINGLE) + WCMD_free_command(thisCmd->command); + else + WCMD_free_commands(thisCmd->left); + free(thisCmd); } }