cmd.exe: Fix redirect ordering on a command line.

This commit is contained in:
Jason Edmeades 2007-09-11 21:43:08 +01:00 committed by Alexandre Julliard
parent c7b88e95f5
commit 1ee75382c7
5 changed files with 232 additions and 133 deletions

View File

@ -2,6 +2,7 @@
* CMD - Wine-compatible command line interface - batch interface.
*
* Copyright (C) 1999 D A Pickles
* Copyright (C) 2007 J Edmeades
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@ -2,6 +2,7 @@
* CMD - Wine-compatible command line interface - built-in functions.
*
* Copyright (C) 1999 D A Pickles
* Copyright (C) 2007 J Edmeades
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -832,7 +833,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
if (*itemStart == '`' || *itemStart == '\'') {
WCHAR temp_path[MAX_PATH], temp_cmd[MAXSTRING];
static const WCHAR redirOut[] = {'%','s',' ','>',' ','%','s','\0'};
static const WCHAR redirOut[] = {'>','%','s','\0'};
static const WCHAR cmdW[] = {'C','M','D','\0'};
/* Remove trailing character */
@ -844,7 +845,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
/* Execute program and redirect output */
wsprintf (temp_cmd, redirOut, (itemStart+1), temp_file);
WCMD_execute (temp_cmd, NULL, NULL, NULL);
WCMD_execute (itemStart, temp_cmd, NULL, NULL, NULL);
/* Open the file, read line by line and process */
input = CreateFile (temp_file, GENERIC_READ, FILE_SHARE_READ,
@ -977,7 +978,7 @@ void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
/* Process the first command, if there is one */
if (conditionTRUE && firstcmd && *firstcmd) {
WCHAR *command = WCMD_strdupW(firstcmd);
WCMD_execute (firstcmd, variable, value, cmdList);
WCMD_execute (firstcmd, (*cmdList)->redirects, variable, value, cmdList);
free (command);
}
@ -1005,7 +1006,8 @@ void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
/* Execute any appended to the statement with &&'s */
if ((*cmdList)->isAmphersand) {
if (processThese) {
WCMD_execute ((*cmdList)->command, variable, value, cmdList);
WCMD_execute ((*cmdList)->command, (*cmdList)->redirects, variable,
value, cmdList);
}
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
@ -1033,7 +1035,7 @@ void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
/* Skip leading whitespace between condition and the command */
while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
if (*cmd) {
WCMD_execute (cmd, variable, value, cmdList);
WCMD_execute (cmd, (*cmdList)->redirects, variable, value, cmdList);
}
}
if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;

View File

@ -2,6 +2,7 @@
* CMD - Wine-compatible command line interface - Directory functions.
*
* Copyright (C) 1999 D A Pickles
* Copyright (C) 2007 J Edmeades
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@ -2,6 +2,7 @@
* CMD - Wine-compatible command line interface.
*
* Copyright (C) 1999 D A Pickles
* Copyright (C) 2007 J Edmeades
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -32,6 +33,7 @@
typedef struct _CMD_LIST {
WCHAR *command; /* Command string to execute */
WCHAR *redirects; /* Redirects in place */
struct _CMD_LIST *nextcommand; /* Next command string to execute */
BOOL isAmphersand;/* Whether follows && */
int bracketDepth;/* How deep bracketing have we got to */
@ -103,7 +105,8 @@ BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars,
WCHAR *WCMD_ReadAndParseLine(WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom);
CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, WCHAR *var, WCHAR *val);
void WCMD_free_commands(CMD_LIST *cmds);
void WCMD_execute (WCHAR *orig_command, WCHAR *parameter, WCHAR *substitution, CMD_LIST **cmdList);
void WCMD_execute (WCHAR *orig_command, WCHAR *redirects, WCHAR *parameter,
WCHAR *substitution, CMD_LIST **cmdList);
/* Data structure to hold context when executing batch files */

View File

@ -2,6 +2,7 @@
* CMD - Wine-compatible command line interface.
*
* Copyright (C) 1999 - 2001 D A Pickles
* Copyright (C) 2007 J Edmeades
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -96,6 +97,7 @@ static char *output_bufA = NULL;
BOOL unicodePipes = FALSE;
static WCHAR *WCMD_expand_envvar(WCHAR *start, WCHAR *forvar, WCHAR *forVal);
static void WCMD_output_asis_len(const WCHAR *message, int len, HANDLE device);
/*****************************************************************************
* Main entry point. This is a console application so we have a main() not a
@ -544,7 +546,7 @@ void handleExpansion(WCHAR *cmd, BOOL justFors, WCHAR *forVariable, WCHAR *forVa
*/
void WCMD_execute (WCHAR *command,
void WCMD_execute (WCHAR *command, WCHAR *redirects,
WCHAR *forVariable, WCHAR *forValue,
CMD_LIST **cmdList)
{
@ -555,7 +557,6 @@ void WCMD_execute (WCHAR *command,
WCHAR *whichcmd;
SECURITY_ATTRIBUTES sa;
WCHAR *new_cmd;
WCHAR *first_redir = NULL;
HANDLE old_stdhandles[3] = {INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE};
@ -614,8 +615,7 @@ void WCMD_execute (WCHAR *command,
* Redirect stdin, stdout and/or stderr if required.
*/
if ((p = strchrW(cmd,'<')) != NULL) {
if (first_redir == NULL) first_redir = p;
if ((p = strchrW(redirects,'<')) != NULL) {
h = CreateFile (WCMD_parameter (++p, 0, NULL), GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
@ -628,15 +628,13 @@ void WCMD_execute (WCHAR *command,
}
/* Scan the whole command looking for > and 2> */
redir = cmd;
redir = redirects;
while (redir != NULL && ((p = strchrW(redir,'>')) != NULL)) {
int handle = 0;
if (*(p-1)!='2') {
if (first_redir == NULL) first_redir = p;
handle = 1;
} else {
if (first_redir == NULL) first_redir = (p-1);
handle = 2;
}
@ -683,9 +681,6 @@ void WCMD_execute (WCHAR *command,
SetStdHandle (idx_stdhandles[handle], h);
}
/* Terminate the command string at <, or first 2> or > */
if (first_redir != NULL) *first_redir = '\0';
/*
* Strip leading whitespaces, and a '@' if supplied
*/
@ -1267,9 +1262,12 @@ void WCMD_print_error (void) {
error_code, GetLastError());
return;
}
WCMD_output_asis (lpMsgBuf);
WCMD_output_asis_len(lpMsgBuf, lstrlen(lpMsgBuf),
GetStdHandle(STD_ERROR_HANDLE));
LocalFree ((HLOCAL)lpMsgBuf);
WCMD_output_asis (newline);
WCMD_output_asis_len (newline, lstrlen(newline),
GetStdHandle(STD_ERROR_HANDLE));
return;
}
@ -1338,7 +1336,7 @@ int p = 0;
* and hence required WriteConsoleW to output it, however if file i/o is
* redirected, it needs to be WriteFile'd using OEM (not ANSI) format
*/
static void WCMD_output_asis_len(const WCHAR *message, int len) {
static void WCMD_output_asis_len(const WCHAR *message, int len, HANDLE device) {
DWORD nOut= 0;
DWORD res = 0;
@ -1347,8 +1345,7 @@ static void WCMD_output_asis_len(const WCHAR *message, int len) {
if (!len) return;
/* Try to write as unicode assuming it is to a console */
res = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
message, len, &nOut, NULL);
res = WriteConsoleW(device, message, len, &nOut, NULL);
/* If writing to console fails, assume its file
i/o so convert to OEM codepage and output */
@ -1371,10 +1368,10 @@ static void WCMD_output_asis_len(const WCHAR *message, int len) {
convertedChars = WideCharToMultiByte(GetConsoleOutputCP(), 0, message,
len, output_bufA, MAX_WRITECONSOLE_SIZE,
"?", &usedDefaultChar);
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), output_bufA, convertedChars,
WriteFile(device, output_bufA, convertedChars,
&nOut, FALSE);
} else {
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), message, len*sizeof(WCHAR),
WriteFile(device, message, len*sizeof(WCHAR),
&nOut, FALSE);
}
}
@ -1400,7 +1397,7 @@ void WCMD_output (const WCHAR *format, ...) {
string[ret] = '\0';
}
va_end(ap);
WCMD_output_asis_len(string, ret);
WCMD_output_asis_len(string, ret, GetStdHandle(STD_OUTPUT_HANDLE));
}
@ -1451,19 +1448,22 @@ void WCMD_output_asis (const WCHAR *message) {
ptr++;
};
if (*ptr == '\n') ptr++;
WCMD_output_asis_len(message, (ptr) ? ptr - message : strlenW(message));
WCMD_output_asis_len(message, (ptr) ? ptr - message : strlenW(message),
GetStdHandle(STD_OUTPUT_HANDLE));
if (ptr) {
numChars = 0;
if (++line_count >= max_height - 1) {
line_count = 0;
WCMD_output_asis_len(pagedMessage, strlenW(pagedMessage));
WCMD_output_asis_len(pagedMessage, strlenW(pagedMessage),
GetStdHandle(STD_OUTPUT_HANDLE));
WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), string,
sizeof(string)/sizeof(WCHAR), &count, NULL);
}
}
} while (((message = ptr) != NULL) && (*ptr));
} else {
WCMD_output_asis_len(message, lstrlen(message));
WCMD_output_asis_len(message, lstrlen(message),
GetStdHandle(STD_OUTPUT_HANDLE));
}
}
@ -1544,19 +1544,19 @@ void WCMD_pipe (CMD_LIST **cmdEntry, WCHAR *var, WCHAR *val) {
p = strchrW(command, '|');
*p++ = '\0';
wsprintf (temp_cmd, redirOut, command, temp_file);
WCMD_execute (temp_cmd, var, val, cmdEntry);
WCMD_execute (temp_cmd, (*cmdEntry)->redirects, var, val, cmdEntry);
command = p;
while ((p = strchrW(command, '|'))) {
*p++ = '\0';
GetTempFileName (temp_path, cmdW, 0, temp_file2);
wsprintf (temp_cmd, redirBoth, command, temp_file, temp_file2);
WCMD_execute (temp_cmd, var, val, cmdEntry);
WCMD_execute (temp_cmd, (*cmdEntry)->redirects, var, val, cmdEntry);
DeleteFile (temp_file);
strcpyW (temp_file, temp_file2);
command = p;
}
wsprintf (temp_cmd, redirIn, command, temp_file);
WCMD_execute (temp_cmd, var, val, cmdEntry);
WCMD_execute (temp_cmd, (*cmdEntry)->redirects, var, val, cmdEntry);
DeleteFile (temp_file);
}
@ -1936,7 +1936,8 @@ void WCMD_DumpCommands(CMD_LIST *commands) {
WCHAR buffer[MAXSTRING];
CMD_LIST *thisCmd = commands;
const WCHAR fmt[] = {'%','p',' ','%','c',' ','%','2','.','2','d',' ',
'%','p',' ','%','s','\0'};
'%','p',' ','%','s',' ','R','e','d','i','r',':',
'%','s','\0'};
WINE_TRACE("Parsed line:\n");
while (thisCmd != NULL) {
@ -1945,12 +1946,64 @@ void WCMD_DumpCommands(CMD_LIST *commands) {
thisCmd->isAmphersand?'Y':'N',
thisCmd->bracketDepth,
thisCmd->nextcommand,
thisCmd->command);
thisCmd->command,
thisCmd->redirects);
WINE_TRACE("%s\n", wine_dbgstr_w(buffer));
thisCmd = thisCmd->nextcommand;
}
}
/***************************************************************************
* WCMD_addCommand
*
* Adds a command to the current command list
*/
void WCMD_addCommand(WCHAR *command, int *commandLen,
WCHAR *redirs, int *redirLen,
WCHAR **copyTo, int **copyToLen,
BOOL isAmphersand, int curDepth,
CMD_LIST **lastEntry, CMD_LIST **output) {
CMD_LIST *thisEntry = NULL;
/* Allocate storage for command */
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
/* Copy in the command */
if (command) {
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
(*commandLen+1) * sizeof(WCHAR));
memcpy(thisEntry->command, command, *commandLen * sizeof(WCHAR));
thisEntry->command[*commandLen] = 0x00;
/* Copy in the redirects */
thisEntry->redirects = HeapAlloc(GetProcessHeap(), 0,
(*redirLen+1) * sizeof(WCHAR));
memcpy(thisEntry->redirects, redirs, *redirLen * sizeof(WCHAR));
thisEntry->redirects[*redirLen] = 0x00;
/* Reset the lengths */
*commandLen = 0;
*redirLen = 0;
*copyToLen = commandLen;
*copyTo = command;
} else {
thisEntry->command = NULL;
}
/* Fill in other fields */
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = isAmphersand;
thisEntry->bracketDepth = curDepth;
if (*lastEntry) {
(*lastEntry)->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
*lastEntry = thisEntry;
}
/***************************************************************************
* WCMD_ReadAndParseLine
*
@ -1970,9 +2023,12 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WCHAR *curPos;
BOOL inQuotes = FALSE;
WCHAR curString[MAXSTRING];
int curLen = 0;
int curStringLen = 0;
WCHAR curRedirs[MAXSTRING];
int curRedirsLen = 0;
WCHAR *curCopyTo;
int *curLen;
int curDepth = 0;
CMD_LIST *thisEntry = NULL;
CMD_LIST *lastEntry = NULL;
BOOL isAmphersand = FALSE;
static WCHAR *extraSpace = NULL; /* Deliberately never freed */
@ -1990,6 +2046,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
BOOL lastWasDo = FALSE;
BOOL lastWasIn = FALSE;
BOOL lastWasElse = FALSE;
BOOL lastWasRedirect = TRUE;
/* Allocate working space for a command read from keyboard, file etc */
if (!extraSpace)
@ -2015,8 +2072,12 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
/* Replace env vars if in a batch context */
if (context) handleExpansion(extraSpace, FALSE, NULL, NULL);
/* Start with an empty string */
curLen = 0;
/* Start with an empty string, copying to the command string */
curStringLen = 0;
curRedirsLen = 0;
curCopyTo = curString;
curLen = &curStringLen;
lastWasRedirect = FALSE; /* Required for eg spaces between > and filename */
/* Parse every character on the line being processed */
while (*curPos != 0x00) {
@ -2024,12 +2085,12 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WCHAR thisChar;
/* Debugging AID:
WINE_TRACE("Looking at '%c' (len:%d, lws:%d, ows:%d)\n", *curPos, curLen,
WINE_TRACE("Looking at '%c' (len:%d, lws:%d, ows:%d)\n", *curPos, *curLen,
lastWasWhiteSpace, onlyWhiteSpace);
*/
/* Certain commands need special handling */
if (curLen == 0) {
/* Certain commands need special handling */
if (curStringLen == 0 && curCopyTo == curString) {
const WCHAR forDO[] = {'d','o',' ','\0'};
/* If command starts with 'rem', ignore any &&, ( etc */
@ -2057,8 +2118,8 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
inElse = TRUE;
lastWasElse = TRUE;
onlyWhiteSpace = TRUE;
memcpy(&curString[curLen], curPos, 5*sizeof(WCHAR));
curLen+=5;
memcpy(&curCopyTo[*curLen], curPos, 5*sizeof(WCHAR));
(*curLen)+=5;
curPos+=5;
continue;
@ -2071,12 +2132,12 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WINE_TRACE("Found DO\n");
lastWasDo = TRUE;
onlyWhiteSpace = TRUE;
memcpy(&curString[curLen], curPos, 3*sizeof(WCHAR));
curLen+=3;
memcpy(&curCopyTo[*curLen], curPos, 3*sizeof(WCHAR));
(*curLen)+=3;
curPos+=3;
continue;
}
} else {
} else if (curCopyTo == curString) {
/* Special handling for the 'FOR' command */
if (inFor && lastWasWhiteSpace) {
@ -2089,8 +2150,8 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WINE_TRACE("Found IN\n");
lastWasIn = TRUE;
onlyWhiteSpace = TRUE;
memcpy(&curString[curLen], curPos, 3*sizeof(WCHAR));
curLen+=3;
memcpy(&curCopyTo[*curLen], curPos, 3*sizeof(WCHAR));
(*curLen)+=3;
curPos+=3;
continue;
}
@ -2107,17 +2168,84 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
switch (thisChar) {
case '\t':/* drop through - ignore whitespace at the start of a command */
case ' ': if (curLen > 0)
curString[curLen++] = *curPos;
case '=': /* drop through - ignore token delimiters at the start of a command */
case ',': /* drop through - ignore token delimiters at the start of a command */
case '\t':/* drop through - ignore token delimiters at the start of a command */
case ' ':
/* If a redirect in place, it ends here */
if (!inQuotes && !lastWasRedirect) {
/* If finishing off a redirect, add a whitespace delimiter */
if (curCopyTo == curRedirs) {
curCopyTo[(*curLen)++] = ' ';
}
curCopyTo = curString;
curLen = &curStringLen;
}
if (*curLen > 0) {
curCopyTo[(*curLen)++] = *curPos;
}
/* Remember just processed whitespace */
lastWasWhiteSpace = TRUE;
break;
case '>': /* drop through - handle redirect chars the same */
case '<':
/* Make a redirect start here */
if (!inQuotes) {
curCopyTo = curRedirs;
curLen = &curRedirsLen;
lastWasRedirect = TRUE;
}
/* See if 1>, 2> etc, in which case we have some patching up
to do */
if (curPos != extraSpace &&
*(curPos-1)>='1' && *(curPos-1)<='9') {
curStringLen--;
curString[curStringLen] = 0x00;
curCopyTo[(*curLen)++] = *(curPos-1);
}
curCopyTo[(*curLen)++] = *curPos;
break;
case '|': /* Pipe character only if not || */
if (!inQuotes && *(curPos++) == '|') {
/* || is an alternative form of && but runs regardless */
/* If finishing off a redirect, add a whitespace delimiter */
if (curCopyTo == curRedirs) {
curCopyTo[(*curLen)++] = ' ';
}
/* If a redirect in place, it ends here */
curCopyTo = curString;
curLen = &curStringLen;
curCopyTo[(*curLen)++] = *curPos;
lastWasRedirect = FALSE;
} else if (inQuotes) {
curCopyTo[(*curLen)++] = *curPos;
lastWasRedirect = FALSE;
} else {
/* Make a redirect start here */
curCopyTo = curRedirs;
curLen = &curRedirsLen;
curCopyTo[(*curLen)++] = *curPos;
lastWasRedirect = TRUE;
}
break;
case '"': inQuotes = !inQuotes;
curString[curLen++] = *curPos;
curCopyTo[(*curLen)++] = *curPos;
lastWasRedirect = FALSE;
break;
case '(': /* If a '(' is the first non whitespace in a command portion
@ -2126,18 +2254,19 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WINE_TRACE("Found '(' conditions: curLen(%d), inQ(%d), onlyWS(%d)"
", for(%d, In:%d, Do:%d)"
", if(%d, else:%d, lwe:%d)\n",
curLen, inQuotes,
*curLen, inQuotes,
onlyWhiteSpace,
inFor, lastWasIn, lastWasDo,
inIf, inElse, lastWasElse);
lastWasRedirect = FALSE;
/* Ignore open brackets inside the for set */
if (curLen == 0 && !inIn) {
if (*curLen == 0 && !inIn) {
curDepth++;
/* If in quotes, ignore brackets */
} else if (inQuotes) {
curString[curLen++] = *curPos;
curCopyTo[(*curLen)++] = *curPos;
/* In a FOR loop, an unquoted '(' may occur straight after
IN or DO
@ -2157,98 +2286,71 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
}
/* Add the current command */
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
(curLen+1) * sizeof(WCHAR));
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
thisEntry->command[curLen] = 0x00;
curLen = 0;
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = isAmphersand;
thisEntry->bracketDepth = curDepth;
if (lastEntry) {
lastEntry->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
lastEntry = thisEntry;
WCMD_addCommand(curString, &curStringLen,
curRedirs, &curRedirsLen,
&curCopyTo, &curLen,
isAmphersand, curDepth,
&lastEntry, output);
curDepth++;
} else {
curString[curLen++] = *curPos;
curCopyTo[(*curLen)++] = *curPos;
}
break;
case '&': if (!inQuotes && *(curPos+1) == '&') {
curPos++; /* Skip other & */
lastWasRedirect = FALSE;
/* Add an entry to the command list */
if (curLen > 0) {
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
(curLen+1) * sizeof(WCHAR));
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
thisEntry->command[curLen] = 0x00;
curLen = 0;
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = isAmphersand;
thisEntry->bracketDepth = curDepth;
if (lastEntry) {
lastEntry->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
lastEntry = thisEntry;
if (curStringLen > 0) {
/* Add the current command */
WCMD_addCommand(curString, &curStringLen,
curRedirs, &curRedirsLen,
&curCopyTo, &curLen,
isAmphersand, curDepth,
&lastEntry, output);
}
isAmphersand = TRUE;
} else {
curString[curLen++] = *curPos;
curCopyTo[(*curLen)++] = *curPos;
}
break;
case ')': if (!inQuotes && curDepth > 0) {
lastWasRedirect = FALSE;
/* Add the current command if there is one */
if (curLen) {
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
(curLen+1) * sizeof(WCHAR));
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
thisEntry->command[curLen] = 0x00;
curLen = 0;
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = isAmphersand;
thisEntry->bracketDepth = curDepth;
if (lastEntry) {
lastEntry->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
lastEntry = thisEntry;
if (curStringLen) {
/* Add the current command */
WCMD_addCommand(curString, &curStringLen,
curRedirs, &curRedirsLen,
&curCopyTo, &curLen,
isAmphersand, curDepth,
&lastEntry, output);
}
/* Add an empty entry to the command list */
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
thisEntry->command = NULL;
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = FALSE;
thisEntry->bracketDepth = curDepth;
isAmphersand = FALSE;
WCMD_addCommand(NULL, &curStringLen,
curRedirs, &curRedirsLen,
&curCopyTo, &curLen,
isAmphersand, curDepth,
&lastEntry, output);
curDepth--;
if (lastEntry) {
lastEntry->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
lastEntry = thisEntry;
/* Leave inIn if necessary */
if (inIn) inIn = FALSE;
} else {
curString[curLen++] = *curPos;
curCopyTo[(*curLen)++] = *curPos;
}
break;
default:
curString[curLen++] = *curPos;
lastWasRedirect = FALSE;
curCopyTo[(*curLen)++] = *curPos;
}
curPos++;
@ -2264,24 +2366,14 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
}
/* If we have reached the end, add this command into the list */
if (*curPos == 0x00 && curLen > 0) {
if (*curPos == 0x00 && *curLen > 0) {
/* Add an entry to the command list */
thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
(curLen+1) * sizeof(WCHAR));
memcpy(thisEntry->command, curString, curLen * sizeof(WCHAR));
thisEntry->command[curLen] = 0x00;
curLen = 0;
thisEntry->nextcommand = NULL;
thisEntry->isAmphersand = isAmphersand;
thisEntry->bracketDepth = curDepth;
if (lastEntry) {
lastEntry->nextcommand = thisEntry;
} else {
*output = thisEntry;
}
lastEntry = thisEntry;
WCMD_addCommand(curString, &curStringLen,
curRedirs, &curRedirsLen,
&curCopyTo, &curLen,
isAmphersand, curDepth,
&lastEntry, output);
}
/* If we have reached the end of the string, see if bracketing outstanding */
@ -2340,10 +2432,10 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command));
if (strchrW(thisCmd->command,'|') != NULL) {
if (strchrW(thisCmd->redirects,'|') != NULL) {
WCMD_pipe (&thisCmd, var, val);
} else {
WCMD_execute (thisCmd->command, var, val, &thisCmd);
WCMD_execute (thisCmd->command, thisCmd->redirects, var, val, &thisCmd);
}
}