mirror of
https://github.com/reactos/wine.git
synced 2025-01-31 17:23:53 +00:00
cmd.exe: Fix redirect ordering on a command line.
This commit is contained in:
parent
c7b88e95f5
commit
1ee75382c7
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user