mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-30 04:48:36 +00:00
cmd: Remove old FOR loop related code.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
This commit is contained in:
parent
f98077591f
commit
96762f12e7
|
@ -1673,110 +1673,6 @@ void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
|||
}
|
||||
}
|
||||
|
||||
static BOOL option_equals(WCHAR **haystack, const WCHAR *needle)
|
||||
{
|
||||
int len = wcslen(needle);
|
||||
|
||||
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
||||
*haystack, len, needle, len) == CSTR_EQUAL) {
|
||||
*haystack += len;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* WCMD_parse_forf_options
|
||||
*
|
||||
* Parses the for /f 'options', extracting the values and validating the
|
||||
* keywords. Note all keywords are optional.
|
||||
* Parameters:
|
||||
* options [I] The unparsed parameter string
|
||||
* eol [O] Set to the comment character (eol=x)
|
||||
* skip [O] Set to the number of lines to skip (skip=xx)
|
||||
* delims [O] Set to the token delimiters (delims=)
|
||||
* tokens [O] Set to the requested tokens, as provided (tokens=)
|
||||
* usebackq [O] Set to TRUE if usebackq found
|
||||
*
|
||||
* Returns TRUE on success, FALSE on syntax error
|
||||
*
|
||||
*/
|
||||
static BOOL WCMD_parse_forf_options(WCHAR *options, WCHAR *eol, int *skip,
|
||||
WCHAR *delims, WCHAR *tokens, BOOL *usebackq)
|
||||
{
|
||||
|
||||
WCHAR *pos = options;
|
||||
int len = lstrlenW(pos);
|
||||
|
||||
/* Initialize to defaults */
|
||||
lstrcpyW(delims, L" \t");
|
||||
lstrcpyW(tokens, L"1");
|
||||
*eol = 0;
|
||||
*skip = 0;
|
||||
*usebackq = FALSE;
|
||||
|
||||
/* Strip (optional) leading and trailing quotes */
|
||||
if ((*pos == '"') && (pos[len-1] == '"')) {
|
||||
pos[len-1] = 0;
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* Process each keyword */
|
||||
while (pos && *pos) {
|
||||
if (*pos == ' ' || *pos == '\t') {
|
||||
pos++;
|
||||
|
||||
/* Save End of line character (Ignore line if first token (based on delims) starts with it) */
|
||||
} else if (option_equals(&pos, L"eol=")) {
|
||||
*eol = *pos++;
|
||||
WINE_TRACE("Found eol as %c(%x)\n", *eol, *eol);
|
||||
|
||||
/* Save number of lines to skip (Can be in base 10, hex (0x...) or octal (0xx) */
|
||||
} else if (option_equals(&pos, L"skip=")) {
|
||||
WCHAR *nextchar = NULL;
|
||||
*skip = wcstoul(pos, &nextchar, 0);
|
||||
WINE_TRACE("Found skip as %d lines\n", *skip);
|
||||
pos = nextchar;
|
||||
|
||||
/* Save if usebackq semantics are in effect */
|
||||
} else if (option_equals(&pos, L"usebackq")) {
|
||||
*usebackq = TRUE;
|
||||
WINE_TRACE("Found usebackq\n");
|
||||
|
||||
/* Save the supplied delims. Slightly odd as space can be a delimiter but only
|
||||
if you finish the optionsroot string with delims= otherwise the space is
|
||||
just a token delimiter! */
|
||||
} else if (option_equals(&pos, L"delims=")) {
|
||||
int i=0;
|
||||
|
||||
while (*pos && *pos != ' ') {
|
||||
delims[i++] = *pos;
|
||||
pos++;
|
||||
}
|
||||
if (*pos==' ' && *(pos+1)==0) delims[i++] = *pos;
|
||||
delims[i++] = 0; /* Null terminate the delims */
|
||||
WINE_TRACE("Found delims as '%s'\n", wine_dbgstr_w(delims));
|
||||
|
||||
/* Save the tokens being requested */
|
||||
} else if (option_equals(&pos, L"tokens=")) {
|
||||
int i=0;
|
||||
|
||||
while (*pos && *pos != ' ') {
|
||||
tokens[i++] = *pos;
|
||||
pos++;
|
||||
}
|
||||
tokens[i++] = 0; /* Null terminate the tokens */
|
||||
WINE_TRACE("Found tokens as '%s'\n", wine_dbgstr_w(tokens));
|
||||
|
||||
} else {
|
||||
WINE_WARN("Unexpected data in optionsroot: '%s'\n", wine_dbgstr_w(pos));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* WCMD_add_dirstowalk
|
||||
*
|
||||
|
@ -1953,177 +1849,6 @@ int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
|
|||
return nexttoken;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* WCMD_parse_line
|
||||
*
|
||||
* When parsing file or string contents (for /f), once the string to parse
|
||||
* has been identified, handle the various options and call the do part
|
||||
* if appropriate.
|
||||
*
|
||||
* Parameters:
|
||||
* cmdStart [I] - Identifies the list of commands making up the
|
||||
* for loop body (especially if brackets in use)
|
||||
* firstCmd [I] - The textual start of the command after the DO
|
||||
* which is within the first item of cmdStart
|
||||
* cmdEnd [O] - Identifies where to continue after the DO
|
||||
* variable [I] - The variable identified on the for line
|
||||
* buffer [I] - The string to parse
|
||||
* doExecuted [O] - Set to TRUE if the DO is ever executed once
|
||||
* forf_skip [I/O] - How many lines to skip first
|
||||
* forf_eol [I] - The 'end of line' (comment) character
|
||||
* forf_delims [I] - The delimiters to use when breaking the string apart
|
||||
* forf_tokens [I] - The tokens to use when breaking the string apart
|
||||
*/
|
||||
static void WCMD_parse_line(CMD_NODE *cmdStart,
|
||||
const WCHAR *firstCmd,
|
||||
CMD_NODE **cmdEnd,
|
||||
int varidx,
|
||||
WCHAR *buffer,
|
||||
BOOL *doExecuted,
|
||||
int *forf_skip,
|
||||
WCHAR forf_eol,
|
||||
WCHAR *forf_delims,
|
||||
WCHAR *forf_tokens) {
|
||||
|
||||
WCHAR *parm;
|
||||
int varoffset;
|
||||
int nexttoken, lasttoken = -1;
|
||||
BOOL starfound = FALSE;
|
||||
BOOL thisduplicate = FALSE;
|
||||
BOOL anyduplicates = FALSE;
|
||||
int totalfound;
|
||||
static WCHAR emptyW[] = L"";
|
||||
|
||||
/* Skip lines if requested */
|
||||
if (*forf_skip) {
|
||||
(*forf_skip)--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save away any existing for variable context (e.g. nested for loops) */
|
||||
WCMD_save_for_loop_context(FALSE);
|
||||
|
||||
/* Extract the parameters based on the tokens= value (There will always
|
||||
be some value, as if it is not supplied, it defaults to tokens=1).
|
||||
Rough logic:
|
||||
Count how many tokens are named in the line, identify the lowest
|
||||
Empty (set to null terminated string) that number of named variables
|
||||
While lasttoken != nextlowest
|
||||
%letter = parameter number 'nextlowest'
|
||||
letter++ (if >26 or >52 abort)
|
||||
Go through token= string finding next lowest number
|
||||
If token ends in * set %letter = raw position of token(nextnumber+1)
|
||||
*/
|
||||
lasttoken = -1;
|
||||
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, &totalfound,
|
||||
&starfound, &thisduplicate);
|
||||
|
||||
/* Empty out variables */
|
||||
for (varoffset=0;
|
||||
varidx >= 0 && varoffset<totalfound && for_var_index_in_range(varidx, varoffset);
|
||||
varoffset++) {
|
||||
WCMD_set_for_loop_variable(varidx + varoffset, emptyW);
|
||||
}
|
||||
|
||||
/* Loop extracting the tokens
|
||||
Note: nexttoken of 0 means there were no tokens requested, to handle
|
||||
the special case of tokens=* */
|
||||
varoffset = 0;
|
||||
WINE_TRACE("Parsing buffer into tokens: '%s'\n", wine_dbgstr_w(buffer));
|
||||
while (varidx >= 0 && (nexttoken > 0 && (nexttoken > lasttoken))) {
|
||||
anyduplicates |= thisduplicate;
|
||||
|
||||
if (!for_var_index_in_range(varidx, varoffset)) break;
|
||||
|
||||
/* Extract the token number requested and set into the next variable context */
|
||||
parm = WCMD_parameter_with_delims(buffer, (nexttoken-1), NULL, TRUE, FALSE, forf_delims);
|
||||
WINE_TRACE("Parsed token %d(%d) as parameter %s\n", nexttoken,
|
||||
varidx + varoffset, wine_dbgstr_w(parm));
|
||||
if (varidx >=0) {
|
||||
if (parm)
|
||||
WCMD_set_for_loop_variable(varidx + varoffset, parm);
|
||||
varoffset++;
|
||||
}
|
||||
|
||||
/* Find the next token */
|
||||
lasttoken = nexttoken;
|
||||
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, NULL,
|
||||
&starfound, &thisduplicate);
|
||||
}
|
||||
|
||||
/* If all the rest of the tokens were requested, and there is still space in
|
||||
the variable range, write them now */
|
||||
if (!anyduplicates && starfound && varidx >= 0 && for_var_index_in_range(varidx, varoffset)) {
|
||||
nexttoken++;
|
||||
WCMD_parameter_with_delims(buffer, (nexttoken-1), &parm, FALSE, FALSE, forf_delims);
|
||||
WINE_TRACE("Parsed allremaining tokens (%d) as parameter %s\n",
|
||||
varidx + varoffset, wine_dbgstr_w(parm));
|
||||
if (parm)
|
||||
WCMD_set_for_loop_variable(varidx + varoffset, parm);
|
||||
}
|
||||
|
||||
/* Execute the body of the foor loop with these values */
|
||||
if (varidx >= 0 && forloopcontext->variable[varidx] && forloopcontext->variable[varidx][0] != forf_eol) {
|
||||
CMD_NODE *thisCmdStart = cmdStart;
|
||||
*doExecuted = TRUE;
|
||||
WCMD_part_execute(&thisCmdStart, firstCmd, FALSE, TRUE);
|
||||
*cmdEnd = thisCmdStart;
|
||||
}
|
||||
|
||||
WCMD_restore_for_loop_context();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* WCMD_forf_getinput
|
||||
*
|
||||
* Return a FILE* which can be used for reading the input lines,
|
||||
* either to a specific file (which may be quote delimited as we have to
|
||||
* read the parameters in raw mode) or to a command which we need to
|
||||
* execute. The command being executed runs in its own shell and stores
|
||||
* its data in a temporary file.
|
||||
*
|
||||
* Parameters:
|
||||
* usebackq [I] - Indicates whether usebackq is in effect or not
|
||||
* itemStr [I] - The item to be handled, either a filename or
|
||||
* whole command string to execute
|
||||
* iscmd [I] - Identifies whether this is a command or not
|
||||
*
|
||||
* Returns a file handle which can be used to read the input lines from.
|
||||
*/
|
||||
static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
|
||||
{
|
||||
WCHAR *trimmed = NULL;
|
||||
FILE* ret;
|
||||
|
||||
/* Remove leading and trailing character (but there may be trailing whitespace too) */
|
||||
if ((iscmd && (itemstr[0] == '`' && usebackq)) ||
|
||||
(iscmd && (itemstr[0] == '\'' && !usebackq)) ||
|
||||
(!iscmd && (itemstr[0] == '"' && usebackq)))
|
||||
{
|
||||
trimmed = WCMD_strtrim(itemstr);
|
||||
if (trimmed)
|
||||
itemstr = trimmed;
|
||||
itemstr[lstrlenW(itemstr)-1] = 0x00;
|
||||
itemstr++;
|
||||
}
|
||||
|
||||
if (iscmd)
|
||||
{
|
||||
WCHAR temp_cmd[MAXSTRING];
|
||||
wsprintfW(temp_cmd, L"CMD.EXE /C %s", itemstr);
|
||||
WINE_TRACE("Reading output of '%s'\n", wine_dbgstr_w(temp_cmd));
|
||||
ret = _wpopen(temp_cmd, L"rt,ccs=unicode");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Open the file, read line by line and process */
|
||||
WINE_TRACE("Reading input to parse from '%s'\n", wine_dbgstr_w(itemstr));
|
||||
ret = _wfopen(itemstr, L"rt,ccs=unicode");
|
||||
}
|
||||
free(trimmed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* WCMD_for
|
||||
*
|
||||
|
@ -2136,411 +1861,6 @@ static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
|
|||
*
|
||||
*/
|
||||
|
||||
static void WCMD_for_OLD (WCHAR *p, CMD_NODE **cmdList) {
|
||||
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hff;
|
||||
int i;
|
||||
const int in_len = lstrlenW(L"in");
|
||||
CMD_NODE *setStart, *thisSet, *cmdStart, *cmdEnd;
|
||||
WCHAR variable[4];
|
||||
int varidx = -1;
|
||||
WCHAR *firstCmd;
|
||||
int thisDepth;
|
||||
WCHAR optionsRoot[MAX_PATH];
|
||||
DIRECTORY_STACK *dirsToWalk = NULL;
|
||||
BOOL expandDirs = FALSE;
|
||||
BOOL useNumbers = FALSE;
|
||||
BOOL doFileset = FALSE;
|
||||
BOOL doRecurse = FALSE;
|
||||
BOOL doExecuted = FALSE; /* Has the 'do' part been executed */
|
||||
LONG numbers[3] = {0,0,0}; /* Defaults to 0 in native */
|
||||
int itemNum;
|
||||
CMD_NODE *thisCmdStart;
|
||||
int parameterNo = 0;
|
||||
WCHAR forf_eol = 0;
|
||||
int forf_skip = 0;
|
||||
WCHAR forf_delims[256];
|
||||
WCHAR forf_tokens[MAXSTRING];
|
||||
BOOL forf_usebackq = FALSE;
|
||||
|
||||
/* Handle optional qualifiers (multiple are allowed) */
|
||||
WCHAR *thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
|
||||
|
||||
optionsRoot[0] = 0;
|
||||
while (thisArg && *thisArg == '/') {
|
||||
WINE_TRACE("Processing qualifier at %s\n", wine_dbgstr_w(thisArg));
|
||||
thisArg++;
|
||||
switch (towupper(*thisArg)) {
|
||||
case 'D': expandDirs = TRUE; break;
|
||||
case 'L': useNumbers = TRUE; break;
|
||||
|
||||
/* Recursive is special case - /R can have an optional path following it */
|
||||
/* filenamesets are another special case - /F can have an optional options following it */
|
||||
case 'R':
|
||||
case 'F':
|
||||
{
|
||||
/* When recursing directories, use current directory as the starting point unless
|
||||
subsequently overridden */
|
||||
doRecurse = (towupper(*thisArg) == 'R');
|
||||
if (doRecurse) GetCurrentDirectoryW(ARRAY_SIZE(optionsRoot), optionsRoot);
|
||||
|
||||
doFileset = (towupper(*thisArg) == 'F');
|
||||
|
||||
/* Retrieve next parameter to see if is root/options (raw form required
|
||||
with for /f, or unquoted in for /r) */
|
||||
thisArg = WCMD_parameter(p, parameterNo, NULL, doFileset, FALSE);
|
||||
|
||||
/* Next parm is either qualifier, path/options or variable -
|
||||
only care about it if it is the path/options */
|
||||
if (thisArg && *thisArg != '/' && *thisArg != '%') {
|
||||
parameterNo++;
|
||||
lstrcpyW(optionsRoot, thisArg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WINE_FIXME("for qualifier '%c' unhandled\n", *thisArg);
|
||||
}
|
||||
|
||||
/* Step to next token */
|
||||
thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* Ensure line continues with variable */
|
||||
if (*thisArg != '%') {
|
||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return;
|
||||
}
|
||||
|
||||
/* With for /f parse the options if provided */
|
||||
if (doFileset) {
|
||||
if (!WCMD_parse_forf_options(optionsRoot, &forf_eol, &forf_skip,
|
||||
forf_delims, forf_tokens, &forf_usebackq))
|
||||
{
|
||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up the list of directories to recurse if we are going to */
|
||||
} else if (doRecurse) {
|
||||
/* Allocate memory, add to list */
|
||||
dirsToWalk = WCMD_dir_stack_create(optionsRoot, NULL);
|
||||
TRACE("Starting with root directory %s\n", wine_dbgstr_w(dirsToWalk->dirName));
|
||||
}
|
||||
|
||||
/* Variable should follow */
|
||||
lstrcpyW(variable, thisArg);
|
||||
WINE_TRACE("Variable identified as %s\n", wine_dbgstr_w(variable));
|
||||
varidx = for_var_char_to_index(variable[1]);
|
||||
|
||||
/* Ensure line continues with IN */
|
||||
thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
|
||||
if (!thisArg
|
||||
|| !(CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
||||
thisArg, in_len, L"in", in_len) == CSTR_EQUAL)) {
|
||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save away where the set of data starts and the variable */
|
||||
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 &&
|
||||
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 = CMD_node_next(*cmdList);
|
||||
}
|
||||
|
||||
/* Skip the close bracket, if there is one */
|
||||
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", CMD_node_get_command(*cmdList)->command)) {
|
||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||
return;
|
||||
}
|
||||
|
||||
cmdEnd = *cmdList;
|
||||
|
||||
/* Loop repeatedly per-directory we are potentially walking, when in for /r
|
||||
mode, or once for the rest of the time. */
|
||||
do {
|
||||
|
||||
/* Save away the starting position for the commands (and offset for the
|
||||
first one) */
|
||||
cmdStart = *cmdList;
|
||||
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
|
||||
prefix the root when searching for the item */
|
||||
if (dirsToWalk) WCMD_add_dirstowalk(dirsToWalk);
|
||||
|
||||
thisSet = setStart;
|
||||
/* Loop through all set entries */
|
||||
while (thisSet &&
|
||||
CMD_node_get_command(thisSet)->command != NULL &&
|
||||
CMD_node_get_depth(thisSet) >= thisDepth) {
|
||||
|
||||
/* Loop through all entries on the same line */
|
||||
WCHAR *staticitem;
|
||||
WCHAR *itemStart;
|
||||
WCHAR buffer[MAXSTRING];
|
||||
|
||||
WINE_TRACE("Processing for set %p\n", thisSet);
|
||||
i = 0;
|
||||
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
|
||||
* otherwise do a literal substitution.
|
||||
*/
|
||||
|
||||
/* Take a copy of the item returned from WCMD_parameter as it is held in a
|
||||
static buffer which can be overwritten during parsing of the for body */
|
||||
WCHAR item[MAXSTRING];
|
||||
lstrcpyW(item, staticitem);
|
||||
|
||||
thisCmdStart = cmdStart;
|
||||
|
||||
itemNum++;
|
||||
WINE_TRACE("Processing for item %d '%s'\n", itemNum, wine_dbgstr_w(item));
|
||||
|
||||
if (!useNumbers && !doFileset) {
|
||||
WCHAR fullitem[MAX_PATH];
|
||||
int prefixlen = 0;
|
||||
|
||||
/* Now build the item to use / search for in the specified directory,
|
||||
as it is fully qualified in the /R case */
|
||||
if (dirsToWalk) {
|
||||
lstrcpyW(fullitem, dirsToWalk->dirName);
|
||||
lstrcatW(fullitem, L"\\");
|
||||
lstrcatW(fullitem, item);
|
||||
} else {
|
||||
WCHAR *prefix = wcsrchr(item, '\\');
|
||||
if (prefix) prefixlen = (prefix - item) + 1;
|
||||
lstrcpyW(fullitem, item);
|
||||
}
|
||||
|
||||
if (wcspbrk(fullitem, L"*?")) {
|
||||
hff = FindFirstFileW(fullitem, &fd);
|
||||
if (hff != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
BOOL isDirectory = FALSE;
|
||||
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) isDirectory = TRUE;
|
||||
|
||||
/* Handle as files or dirs appropriately, but ignore . and .. */
|
||||
if (isDirectory == expandDirs &&
|
||||
(lstrcmpW(fd.cFileName, L"..") != 0) && (lstrcmpW(fd.cFileName, L".") != 0))
|
||||
{
|
||||
thisCmdStart = cmdStart;
|
||||
WINE_TRACE("Processing FOR filename %s\n", wine_dbgstr_w(fd.cFileName));
|
||||
|
||||
if (doRecurse) {
|
||||
if (wcslen(dirsToWalk->dirName) + 1 + wcslen(fd.cFileName) >= MAX_PATH)
|
||||
{
|
||||
WINE_TRACE("Skipping too long path %s\\%s\n",
|
||||
debugstr_w(dirsToWalk->dirName), debugstr_w(fd.cFileName));
|
||||
continue;
|
||||
}
|
||||
lstrcpyW(fullitem, dirsToWalk->dirName);
|
||||
lstrcatW(fullitem, L"\\");
|
||||
lstrcatW(fullitem, fd.cFileName);
|
||||
} else {
|
||||
if (prefixlen) lstrcpynW(fullitem, item, prefixlen + 1);
|
||||
fullitem[prefixlen] = 0x00;
|
||||
lstrcatW(fullitem, fd.cFileName);
|
||||
}
|
||||
doExecuted = TRUE;
|
||||
|
||||
WCMD_save_for_loop_context(FALSE);
|
||||
/* Save away any existing for variable context (e.g. nested for loops)
|
||||
and restore it after executing the body of this for loop */
|
||||
if (varidx >= 0)
|
||||
WCMD_set_for_loop_variable(varidx, fullitem);
|
||||
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
|
||||
WCMD_restore_for_loop_context();
|
||||
|
||||
cmdEnd = thisCmdStart;
|
||||
}
|
||||
} while (FindNextFileW(hff, &fd) != 0);
|
||||
FindClose (hff);
|
||||
}
|
||||
} else {
|
||||
doExecuted = TRUE;
|
||||
|
||||
WCMD_save_for_loop_context(FALSE);
|
||||
/* Save away any existing for variable context (e.g. nested for loops)
|
||||
and restore it after executing the body of this for loop */
|
||||
if (varidx >= 0)
|
||||
WCMD_set_for_loop_variable(varidx, fullitem);
|
||||
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
|
||||
WCMD_restore_for_loop_context();
|
||||
|
||||
cmdEnd = thisCmdStart;
|
||||
}
|
||||
|
||||
} else if (useNumbers) {
|
||||
/* Convert the first 3 numbers to signed longs and save */
|
||||
if (itemNum <=3) numbers[itemNum-1] = wcstol(item, NULL, 10);
|
||||
/* else ignore them! */
|
||||
|
||||
/* Filesets - either a list of files, or a command to run and parse the output */
|
||||
} else if (doFileset && ((!forf_usebackq && *itemStart != '"') ||
|
||||
(forf_usebackq && *itemStart != '\''))) {
|
||||
|
||||
FILE *input;
|
||||
WCHAR *itemparm;
|
||||
|
||||
WINE_TRACE("Processing for filespec from item %d '%s'\n", itemNum,
|
||||
wine_dbgstr_w(item));
|
||||
|
||||
/* If backquote or single quote, we need to launch that command
|
||||
and parse the results - use a temporary file */
|
||||
if ((forf_usebackq && *itemStart == '`') ||
|
||||
(!forf_usebackq && *itemStart == '\'')) {
|
||||
|
||||
/* Use itemstart because the command is the whole set, not just the first token */
|
||||
itemparm = itemStart;
|
||||
} else {
|
||||
|
||||
/* Use item because the file to process is just the first item in the set */
|
||||
itemparm = item;
|
||||
}
|
||||
input = WCMD_forf_getinput(forf_usebackq, itemparm, (itemparm==itemStart));
|
||||
|
||||
/* Process the input file */
|
||||
if (!input) {
|
||||
WCMD_print_error ();
|
||||
WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), item);
|
||||
errorlevel = 1;
|
||||
return; /* FOR loop aborts at first failure here */
|
||||
|
||||
} else {
|
||||
|
||||
/* Read line by line until end of file */
|
||||
while (fgetws(buffer, ARRAY_SIZE(buffer), input)) {
|
||||
size_t len = wcslen(buffer);
|
||||
/* Either our buffer isn't large enough to fit a full line, or there's a stray
|
||||
* '\0' in the buffer.
|
||||
*/
|
||||
if (!feof(input) && (len == 0 || (buffer[len - 1] != '\n' && buffer[len - 1] != '\r')))
|
||||
break;
|
||||
while (len && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r'))
|
||||
buffer[--len] = L'\0';
|
||||
WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, for_var_char_to_index(variable[1]), buffer, &doExecuted,
|
||||
&forf_skip, forf_eol, forf_delims, forf_tokens);
|
||||
buffer[0] = 0;
|
||||
}
|
||||
fclose (input);
|
||||
}
|
||||
|
||||
/* When we have processed the item as a whole command, abort future set processing */
|
||||
if (itemparm==itemStart) {
|
||||
thisSet = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Filesets - A string literal */
|
||||
} else if (doFileset && ((!forf_usebackq && *itemStart == '"') ||
|
||||
(forf_usebackq && *itemStart == '\''))) {
|
||||
|
||||
/* Remove leading and trailing character, ready to parse with delims= delimiters
|
||||
Note that the last quote is removed from the set and the string terminates
|
||||
there to mimic windows */
|
||||
WCHAR *strend = wcsrchr(itemStart, forf_usebackq?'\'':'"');
|
||||
if (strend) {
|
||||
*strend = 0x00;
|
||||
itemStart++;
|
||||
}
|
||||
|
||||
/* Copy the item away from the global buffer used by WCMD_parameter */
|
||||
lstrcpyW(buffer, itemStart);
|
||||
WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, for_var_char_to_index(variable[1]), buffer, &doExecuted,
|
||||
&forf_skip, forf_eol, forf_delims, forf_tokens);
|
||||
|
||||
/* Only one string can be supplied in the whole set, abort future set processing */
|
||||
thisSet = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
WINE_TRACE("Post-command, cmdEnd = %p\n", cmdEnd);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Move onto the next set line */
|
||||
if (thisSet) thisSet = CMD_node_next(thisSet);
|
||||
}
|
||||
|
||||
/* If /L is provided, now run the for loop */
|
||||
if (useNumbers) {
|
||||
WCHAR thisNum[20];
|
||||
|
||||
WINE_TRACE("FOR /L provided range from %ld to %ld step %ld\n",
|
||||
numbers[0], numbers[2], numbers[1]);
|
||||
for (i=numbers[0];
|
||||
(numbers[1]<0)? i>=numbers[2] : i<=numbers[2];
|
||||
i=i + numbers[1]) {
|
||||
|
||||
swprintf(thisNum, ARRAY_SIZE(thisNum), L"%d", i);
|
||||
WINE_TRACE("Processing FOR number %s\n", wine_dbgstr_w(thisNum));
|
||||
|
||||
thisCmdStart = cmdStart;
|
||||
doExecuted = TRUE;
|
||||
|
||||
/* Save away any existing for variable context (e.g. nested for loops)
|
||||
and restore it after executing the body of this for loop */
|
||||
if (varidx >= 0)
|
||||
{
|
||||
WCMD_save_for_loop_context(FALSE);
|
||||
WCMD_set_for_loop_variable(varidx, thisNum);
|
||||
}
|
||||
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
|
||||
if (varidx >= 0)
|
||||
WCMD_restore_for_loop_context();
|
||||
}
|
||||
cmdEnd = thisCmdStart;
|
||||
}
|
||||
|
||||
/* If we are walking directories, move on to any which remain */
|
||||
if (dirsToWalk != NULL) {
|
||||
dirsToWalk = WCMD_dir_stack_free(dirsToWalk);
|
||||
if (dirsToWalk) WINE_TRACE("Moving to next directory to iterate: %s\n",
|
||||
wine_dbgstr_w(dirsToWalk->dirName));
|
||||
else WINE_TRACE("Finished all directories.\n");
|
||||
}
|
||||
|
||||
} while (dirsToWalk != NULL);
|
||||
|
||||
/* Now skip over the do part if we did not perform the for loop so far.
|
||||
We store in cmdEnd the next command after the do block, but we only
|
||||
know this if something was run. If it has not been, we need to calculate
|
||||
it. */
|
||||
if (!doExecuted) {
|
||||
thisCmdStart = cmdStart;
|
||||
WINE_TRACE("Skipping for loop commands due to no valid iterations\n");
|
||||
WCMD_part_execute(&thisCmdStart, firstCmd, FALSE, FALSE);
|
||||
cmdEnd = thisCmdStart;
|
||||
}
|
||||
|
||||
/* When the loop ends, either something like a GOTO or EXIT /b has terminated
|
||||
all processing, OR it should be pointing to the end of && processing OR
|
||||
it should be pointing at the NULL end of bracket for the DO. The return
|
||||
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 && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
|
||||
}
|
||||
|
||||
void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
|
||||
{
|
||||
CMD_FOR_CONTROL *for_ctrl;
|
||||
|
@ -2548,8 +1868,7 @@ void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
|
|||
for_ctrl = for_control_parse(p);
|
||||
if (!for_ctrl)
|
||||
{
|
||||
/* temporary code: use OLD code for non migrated FOR constructs */
|
||||
WCMD_for_OLD(p, cmdList);
|
||||
*cmdList = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2277,6 +2277,7 @@ CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var)
|
|||
for_op = CMD_FOR_FILE_SET;
|
||||
break;
|
||||
default:
|
||||
FIXME("Unexpected situation\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue