From: Eric Pouech epouech@codeweavers.com
This structure will held information for a redirection, and can be chained in a list when multiple redirections are listed.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/batch.c | 2 +- programs/cmd/wcmd.h | 21 ++- programs/cmd/wcmdmain.c | 399 ++++++++++++++++++++++++++-------------- 3 files changed, 281 insertions(+), 141 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index b68642fc29f..455cc99083c 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -93,7 +93,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA 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, FALSE); - WCMD_free_commands(toExecute); + node_dispose_tree(toExecute); toExecute = NULL; } CloseHandle (h); diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index f538e4fc1a6..3ed98bcf73e 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -34,6 +34,19 @@ /* msdn specified max for Win XP */ #define MAXSTRING 8192
+/* Data structure to express a redirection */ +typedef struct _CMD_REDIRECTION +{ + enum CMD_REDIRECTION_KIND {REDIR_READ_FROM, REDIR_WRITE_TO, REDIR_WRITE_APPEND, REDIR_WRITE_CLONE} kind; + unsigned short fd; + struct _CMD_REDIRECTION *next; + union + { + unsigned short clone; /* only if kind is REDIR_WRITE_CLONE */ + WCHAR file[1]; /* only if kind is READ_FROM, WRITE or WRITE_APPEND */ + }; +} CMD_REDIRECTION; + /* Data structure to hold commands delimiters/separators */
typedef enum _CMD_OPERATOR @@ -50,7 +63,7 @@ typedef enum _CMD_OPERATOR typedef struct _CMD_COMMAND { WCHAR *command; /* Command string to execute */ - WCHAR *redirects; /* Redirects in place */ + CMD_REDIRECTION *redirects; /* Redirects in place */ int bracketDepth;/* How deep bracketing have we got to */ WCHAR pipeFile[MAX_PATH]; /* Where to get input from for pipes */ } CMD_COMMAND; @@ -153,9 +166,9 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars, LPDWO
WCHAR *WCMD_ReadAndParseLine(const WCHAR *initialcmd, CMD_NODE **output, HANDLE readFrom); CMD_NODE *WCMD_process_commands(CMD_NODE *thisCmd, BOOL oneBracket, BOOL retrycall); -void WCMD_free_commands(CMD_NODE *cmds); -void WCMD_execute (const WCHAR *orig_command, const WCHAR *redirects, - CMD_NODE **cmdList, BOOL retrycall); +void node_dispose_tree(CMD_NODE *cmds); +void WCMD_execute(const WCHAR *orig_command, CMD_REDIRECTION *redirects, + CMD_NODE **cmdList, BOOL retrycall);
void *xrealloc(void *, size_t) __WINE_ALLOC_SIZE(2) __WINE_DEALLOC(free);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index a2eef017bfd..7f3e995b6e4 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -31,6 +31,8 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(cmd); +WINE_DECLARE_DEBUG_CHANNEL(cmd_lexer); +WINE_DECLARE_DEBUG_CHANNEL(cmd_redir);
extern const WCHAR inbuilt[][10]; extern struct env_stack *pushd_directories; @@ -946,6 +948,92 @@ static void WCMD_parse (const WCHAR *s, WCHAR *q, WCHAR *p1, WCHAR *p2) /* Data structures for commands */ /* ============================== */
+static void redirection_dispose_list(CMD_REDIRECTION *redir) + { + while (redir) + { + CMD_REDIRECTION *next = redir->next; + free(redir); + redir = next; + } +} + +static CMD_REDIRECTION *redirection_create_file(enum CMD_REDIRECTION_KIND kind, unsigned fd, const WCHAR *file) +{ + size_t len = wcslen(file); + CMD_REDIRECTION *redir = xalloc(offsetof(CMD_REDIRECTION, file[len + 1])); + + redir->kind = kind; + redir->fd = fd; + memcpy(redir->file, file, len * sizeof(WCHAR)); + redir->file[len] = L'\0'; + redir->next = NULL; + + return redir; +} + +static CMD_REDIRECTION *redirection_create_clone(unsigned fd, unsigned fd_clone) +{ + CMD_REDIRECTION *redir = xalloc(sizeof(*redir)); + + redir->kind = REDIR_WRITE_CLONE; + redir->fd = fd; + redir->clone = fd_clone; + redir->next = NULL; + + return redir; +} + +static const char *redirection_as_string(const CMD_REDIRECTION *redir) +{ + switch (redir->kind) + { + case REDIR_READ_FROM: + return wine_dbg_sprintf("%u< (%ls)", redir->fd, redir->file); + case REDIR_WRITE_TO: + return wine_dbg_sprintf("%u> (%ls)", redir->fd, redir->file); + case REDIR_WRITE_APPEND: + return wine_dbg_sprintf("%u>> (%ls)", redir->fd, redir->file); + case REDIR_WRITE_CLONE: + return wine_dbg_sprintf("%u>&%u", redir->fd, redir->clone); + default: + return "-^-"; + } +} + +static void command_dispose(CMD_COMMAND *cmd) +{ + if (cmd) + { + free(cmd->command); + redirection_dispose_list(cmd->redirects); + free(cmd); + } +} + +/*************************************************************************** + * node_dispose_tree + * + * Frees the storage held for a parsed command line + * - This is not done in the process_commands, as eventually the current + * pointer will be modified within the commands, and hence a single free + * routine is simpler + */ +void node_dispose_tree(CMD_NODE *cmds) +{ + /* Loop through the commands, freeing them one by one */ + while (cmds) + { + CMD_NODE *thisCmd = cmds; + cmds = CMD_node_next(cmds); + if (thisCmd->op == CMD_SINGLE) + command_dispose(thisCmd->command); + else + node_dispose_tree(thisCmd->left); + free(thisCmd); + } +} + static CMD_NODE *node_create_single(CMD_COMMAND *c) { CMD_NODE *new = xalloc(sizeof(CMD_NODE)); @@ -967,6 +1055,66 @@ static CMD_NODE *node_create_binary(CMD_OPERATOR op, CMD_NODE *l, CMD_NODE *r) return new; }
+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"; +} + +/* Helper for WCMD_DumpCommands */ +static void dump_cmd_node_tree(CMD_NODE *node) +{ + TRACE("("); + if (!node) + TRACE("<<>>"); + else + { + switch (node->op) + { + case CMD_SINGLE: + if (node->command) /* FIXME temp */ + { + TRACE("[[%ls]]", node->command->command); + if (node->command->redirects) + { + const CMD_REDIRECTION *redir; + TRACE("{{"); + for (redir = node->command->redirects; redir; redir = redir->next) + TRACE("%s%s", redirection_as_string(redir), redir->next ? ", " : ""); + TRACE("}}"); + } + } + else + TRACE("[~]"); + break; + case CMD_CONCAT: + case CMD_ONFAILURE: + case CMD_ONSUCCESS: + case CMD_PIPE: + dump_cmd_node_tree(node->left); + TRACE(" %s ", op2str(node->op)); + dump_cmd_node_tree(node->right); + break; + default: + FIXME("Unsupported node operator %u\n", node->op); + } + } + TRACE(")"); +} + +/*************************************************************************** + * WCMD_DumpCommands + * + * Dumps out the parsed command line to ensure syntax is correct + */ +static void WCMD_DumpCommands(CMD_NODE *commands, const char *what) +{ + TRACE("%s:\n", what); + dump_cmd_node_tree(commands); + TRACE("\n"); +} + static void init_msvcrt_io_block(STARTUPINFOW* st) { STARTUPINFOW st_p; @@ -1280,7 +1428,7 @@ void WCMD_run_program (WCHAR *command, BOOL called) /* Parse the command string, without reading any more input */ WCMD_ReadAndParseLine(command, &toExecute, INVALID_HANDLE_VALUE); WCMD_process_commands(toExecute, FALSE, called); - WCMD_free_commands(toExecute); + node_dispose_tree(toExecute); toExecute = NULL; return; } @@ -1295,10 +1443,17 @@ void WCMD_run_program (WCHAR *command, BOOL called)
}
-static BOOL set_std_redirections(WCHAR *new_redir, WCHAR *in_pipe) +/* this is obviously wrong... will require more work to be fixed */ +static inline unsigned clamp_fd(unsigned fd) { - SECURITY_ATTRIBUTES sa = {.nLength = sizeof(sa), .lpSecurityDescriptor = NULL, .bInheritHandle = TRUE}; - WCHAR *pos, *redir; + return fd <= 2 ? fd : 1; +} + +static BOOL set_std_redirections(CMD_REDIRECTION *redir, WCHAR *in_pipe) +{ + static DWORD std_index[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; + static SECURITY_ATTRIBUTES sa = {.nLength = sizeof(sa), .lpSecurityDescriptor = NULL, .bInheritHandle = TRUE}; + WCHAR expanded_filename[MAXSTRING]; HANDLE h;
/* STDIN could come from a preceding pipe, so delete on close if it does */ @@ -1312,62 +1467,54 @@ static BOOL set_std_redirections(WCHAR *new_redir, WCHAR *in_pipe) SetStdHandle(STD_INPUT_HANDLE, h); /* Otherwise STDIN could come from a '<' redirect */ } - else if ((pos = wcschr(new_redir,'<')) != NULL) + for (; redir; redir = redir->next) { - h = CreateFileW(WCMD_parameter(++pos, 0, NULL, FALSE, FALSE), GENERIC_READ, FILE_SHARE_READ, - &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) return FALSE; - SetStdHandle(STD_INPUT_HANDLE, h); - } - - redir = new_redir; - /* Scan the whole command looking for > and 2> */ - while (redir != NULL && ((pos = wcschr(redir,'>')) != NULL)) - { - DWORD disposition; - int std_idx; - - if (pos > redir && (*(pos-1)=='2')) - std_idx = STD_ERROR_HANDLE; - else - /* FIXME what if a number different from 1 & 2 is present? */ - std_idx = STD_OUTPUT_HANDLE; - - pos++; - if ('>' == *pos) + if (redir->kind != REDIR_WRITE_CLONE) { - disposition = OPEN_ALWAYS; - pos++; + wcscpy(expanded_filename, redir->file); + handleExpansion(expanded_filename, (context != NULL), delayedsubst); } - else - disposition = CREATE_ALWAYS; - - /* Add support for 2>&1 */ - redir = pos; - if (*pos == '&') + switch (redir->kind) { - int idx = *(pos+1) - '0'; - - /* FIXME what if a number different from 1 & 2 is present? */ + case REDIR_READ_FROM: + if (in_pipe) continue;/* give precedence to pipe */ + h = CreateFileW(expanded_filename, GENERIC_READ, FILE_SHARE_READ, + &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + TRACE_(cmd_redir)("Open (%ls) => %p\n", redir->file, h); + if (h == INVALID_HANDLE_VALUE) + { + WARN("Failed to open (%ls): %lu\n", redir->file, GetLastError()); + return FALSE; + } + break; + case REDIR_WRITE_TO: + case REDIR_WRITE_APPEND: + { + DWORD disposition = redir->kind == REDIR_WRITE_TO ? CREATE_ALWAYS : OPEN_ALWAYS; + h = CreateFileW(expanded_filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, + &sa, disposition, FILE_ATTRIBUTE_NORMAL, NULL); + TRACE_(cmd_redir)("Open %u (%ls) => %p\n", redir->fd, redir->file, h); + if (h == INVALID_HANDLE_VALUE) + { + WARN("Failed to open %u (%ls): %lu\n", redir->fd, redir->file, GetLastError()); + return FALSE; + } + if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + WCMD_print_error(); + } + break; + case REDIR_WRITE_CLONE: if (!DuplicateHandle(GetCurrentProcess(), - GetStdHandle(idx == 2 ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE), + GetStdHandle(std_index[clamp_fd(redir->clone)]), GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - WINE_FIXME("Duplicating handle failed with gle %ld\n", GetLastError()); + WARN("Duplicating handle failed with gle %ld\n", GetLastError()); } + break; } - else - { - WCHAR *param = WCMD_parameter(pos, 0, NULL, FALSE, FALSE); - h = CreateFileW(param, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, - &sa, disposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) return FALSE; - if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - WCMD_print_error(); - } - SetStdHandle(std_idx, h); + SetStdHandle(std_index[clamp_fd(redir->fd)], h); } return TRUE; } @@ -1379,20 +1526,20 @@ static BOOL set_std_redirections(WCHAR *new_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, const WCHAR *redirects, - CMD_NODE **cmdList, BOOL retrycall) +void WCMD_execute(const WCHAR *command, CMD_REDIRECTION *redirects, + CMD_NODE **cmdList, BOOL retrycall) { WCHAR *cmd, *parms_start; int status, i, cmd_index; DWORD count; WCHAR *whichcmd; WCHAR *new_cmd = NULL; - WCHAR *new_redir = 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;
WINE_TRACE("command on entry:%s (%p)\n", wine_dbgstr_w(command), cmdList); @@ -1402,9 +1549,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, lstrcpyW(new_cmd, command); cmd = new_cmd;
- /* Move copy of the redirects onto the heap so it can be expanded */ - new_redir = xalloc(MAXSTRING * sizeof(WCHAR)); - /* Strip leading whitespaces, and a '@' if supplied */ whichcmd = WCMD_skip_leading_spaces(cmd); WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd)); @@ -1447,15 +1591,15 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
/* If piped output, send stdout to the pipe by appending >filename to redirects */ if (piped) { - 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)); + 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 { - lstrcpyW(new_redir, redirects); + 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); - handleExpansion(new_redir, (context != NULL), delayedsubst);
/* * Changing default drive has to be handled as a special case, anything @@ -1482,9 +1626,7 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, WINE_TRACE("Got directory %s as %s\n", wine_dbgstr_w(envvar), wine_dbgstr_w(cmd)); status = SetCurrentDirectoryW(cmd); if (!status) WCMD_print_error (); - free(cmd); - free(new_redir); - return; + goto cleanup; }
/* @@ -1496,11 +1638,9 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, 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(new_redir, in_pipe)) { + if (!set_std_redirections(piped_redir, in_pipe)) { WCMD_print_error (); - free(cmd); - free(new_redir); - return; + goto cleanup; } if (in_pipe) /* No need to remember the temporary name any longer once opened */ @@ -1663,8 +1803,9 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, WCMD_run_program (whichcmd, FALSE); echo_mode = prev_echo_mode; } +cleanup: free(cmd); - free(new_redir); + if (piped_redir != redirects) free(piped_redir);
/* Restore old handles */ for (i=0; i<3; i++) { @@ -1690,34 +1831,11 @@ WCHAR *WCMD_LoadMessage(UINT id) { return msg; }
-static const char *op2str(CMD_OPERATOR op) +static WCHAR *find_chr(WCHAR *in, WCHAR *last, const WCHAR *delims) { - 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) -{ - CMD_NODE *thisCmd = commands; - - WINE_TRACE("Parsed line:\n"); - 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); - } + for (; in < last; in++) + if (wcschr(delims, *in)) return in; + return NULL; }
/*************************************************************************** @@ -1737,15 +1855,53 @@ static CMD_COMMAND *WCMD_createCommand(WCHAR *command, int *commandLen,
/* Copy in the command */ if (command) { + WCHAR *pos; + WCHAR *last = redirs + *redirLen; + CMD_REDIRECTION **insrt; + thisEntry->command = xalloc((*commandLen + 1) * sizeof(WCHAR)); memcpy(thisEntry->command, command, *commandLen * sizeof(WCHAR)); thisEntry->command[*commandLen] = 0x00;
- /* Copy in the redirects */ - thisEntry->redirects = xalloc((*redirLen + 1) * sizeof(WCHAR)); - memcpy(thisEntry->redirects, redirs, *redirLen * sizeof(WCHAR)); - thisEntry->redirects[*redirLen] = 0x00; - thisEntry->pipeFile[0] = 0x00; + TRACE_(cmd_redir)("Splitting redirect from %s\n", wine_dbgstr_wn(redirs, *redirLen)); + if (redirs) redirs[*redirLen] = 0; + /* Create redirects, keeping order (eg "2>foo 1>&2") */ + insrt = &thisEntry->redirects; + *insrt = NULL; + for (pos = redirs; pos; insrt = &(*insrt)->next) + { + WCHAR *p = find_chr(pos, last, L"<>"); + WCHAR *filename; + + TRACE_(cmd_redir)("\t=> %s\n", wine_dbgstr_wn(p, *redirLen - (p - redirs))); + if (!p) break; + + if (*p == L'<') + { + filename = WCMD_parameter(p + 1, 0, NULL, FALSE, FALSE); + *insrt = redirection_create_file(REDIR_READ_FROM, 0, filename); + } + else + { + unsigned fd = 1; + unsigned op = REDIR_WRITE_TO; + + if (p > redirs && p[-1] >= L'2' && p[-1] <= L'9') fd = p[-1] - L'0'; + if (*++p == L'>') {p++; op = REDIR_WRITE_APPEND;} + if (*p == L'&' && (p[1] >= L'0' && p[1] <= L'9')) + { + *insrt = redirection_create_clone(fd, p[1] - '0'); + p++; + } + else + { + filename = WCMD_parameter(p, 0, NULL, FALSE, FALSE); + *insrt = redirection_create_file(op, fd, filename); + } + } + TRACE_(cmd_redir)("Adding redirect %s\n", redirection_as_string(*insrt)); + pos = p + 1; + }
/* Reset the lengths */ *commandLen = 0; @@ -1756,10 +1912,10 @@ static CMD_COMMAND *WCMD_createCommand(WCHAR *command, int *commandLen, } else { thisEntry->command = NULL; thisEntry->redirects = NULL; - thisEntry->pipeFile[0] = 0x00; }
/* Fill in other fields */ + thisEntry->pipeFile[0] = 0x00; thisEntry->bracketDepth = curDepth; return thisEntry; } @@ -1901,6 +2057,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE return NULL; } curPos = extraSpace; + TRACE_(cmd_lexer)("About to parse line (%ls)\n", extraSpace);
/* Handle truncated input - issue warning */ if (lstrlenW(extraSpace) == MAXSTRING -1) { @@ -2381,13 +2538,13 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output, HANDLE
if (curDepth > lineCurDepth) { WINE_TRACE("Brackets do not match, error out without executing.\n"); - WCMD_free_commands(*output); + node_dispose_tree(*output); *output = NULL; errorlevel = 255; }
/* Dump out the parsed output */ - WCMD_DumpCommands(*output); + WCMD_DumpCommands(*output, "Parsed line");
return extraSpace; } @@ -2423,7 +2580,7 @@ CMD_NODE *WCMD_process_commands(CMD_NODE *thisCmd, BOOL oneBracket, Also, skip over any batch labels (eg. :fred) */ 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); + 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 */ @@ -2432,36 +2589,6 @@ CMD_NODE *WCMD_process_commands(CMD_NODE *thisCmd, BOOL oneBracket, return NULL; }
-static void WCMD_free_command(CMD_COMMAND *cmd) -{ - free(cmd->command); - free(cmd->redirects); - free(cmd); -} - -/*************************************************************************** - * WCMD_free_commands - * - * Frees the storage held for a parsed command line - * - This is not done in the process_commands, as eventually the current - * pointer will be modified within the commands, and hence a single free - * routine is simpler - */ -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); - if (thisCmd->op == CMD_SINGLE) - WCMD_free_command(thisCmd->command); - else - WCMD_free_commands(thisCmd->left); - free(thisCmd); - } -} - static BOOL WINAPI my_event_handler(DWORD ctrl) { WCMD_output(L"\n"); @@ -2738,7 +2865,7 @@ int __cdecl 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, FALSE); - WCMD_free_commands(toExecute); + node_dispose_tree(toExecute); toExecute = NULL;
free(cmd); @@ -2819,7 +2946,7 @@ int __cdecl 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, FALSE); - WCMD_free_commands(toExecute); + node_dispose_tree(toExecute); toExecute = NULL; free(cmd); } @@ -2838,7 +2965,7 @@ int __cdecl wmain (int argc, WCHAR *argvW[]) if (!WCMD_ReadAndParseLine(NULL, &toExecute, GetStdHandle(STD_INPUT_HANDLE))) break; WCMD_process_commands(toExecute, FALSE, FALSE); - WCMD_free_commands(toExecute); + node_dispose_tree(toExecute); promptNewLine = !!toExecute; toExecute = NULL; }