2006-02-16 23:23:37 +00:00
|
|
|
/*
|
|
|
|
* FOR.C - for internal batch command.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* History:
|
|
|
|
*
|
|
|
|
* 16-Jul-1998 (Hans B Pufal)
|
|
|
|
* Started.
|
|
|
|
*
|
|
|
|
* 16-Jul-1998 (John P Price)
|
2016-11-05 14:55:55 +00:00
|
|
|
* Separated commands into individual files.
|
2006-02-16 23:23:37 +00:00
|
|
|
*
|
|
|
|
* 19-Jul-1998 (Hans B Pufal)
|
|
|
|
* Implementation of FOR.
|
|
|
|
*
|
|
|
|
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
|
|
* Added config.h include.
|
|
|
|
*
|
|
|
|
* 20-Jan-1999 (Eric Kohl)
|
|
|
|
* Unicode and redirection safe!
|
|
|
|
*
|
|
|
|
* 01-Sep-1999 (Eric Kohl)
|
|
|
|
* Added help text.
|
|
|
|
*
|
|
|
|
* 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
|
|
|
|
* Implemented preservation of echo flag. Some other for related
|
|
|
|
* code in other files fixed, too.
|
|
|
|
*
|
2013-06-30 13:23:30 +00:00
|
|
|
* 28-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
|
2013-06-30 00:08:43 +00:00
|
|
|
* Remove all hardcoded strings in En.rc
|
2006-02-16 23:23:37 +00:00
|
|
|
*/
|
|
|
|
|
2013-01-24 23:00:42 +00:00
|
|
|
#include "precomp.h"
|
2006-02-16 23:23:37 +00:00
|
|
|
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
/* Enable this define for "buggy" Windows' CMD FOR-command compatibility.
|
|
|
|
* Currently, this enables the buggy behaviour of FOR /F token parsing. */
|
|
|
|
#define MSCMD_FOR_QUIRKS
|
|
|
|
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2009-02-24 20:29:18 +00:00
|
|
|
/* FOR is a special command, so this function is only used for showing help now */
|
2020-07-26 18:30:03 +00:00
|
|
|
INT cmd_for(LPTSTR param)
|
2007-10-19 23:21:45 +00:00
|
|
|
{
|
2020-07-26 18:30:03 +00:00
|
|
|
TRACE("cmd_for(\'%s\')\n", debugstr_aw(param));
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2020-07-26 18:30:03 +00:00
|
|
|
if (!_tcsncmp(param, _T("/?"), 2))
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
2020-07-26 18:30:03 +00:00
|
|
|
ConOutResPaging(TRUE, STRING_FOR_HELP1);
|
2013-06-30 00:08:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2020-05-18 00:16:40 +00:00
|
|
|
ParseErrorEx(param);
|
2013-06-30 00:08:43 +00:00
|
|
|
return 1;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
|
|
|
|
2009-03-02 19:08:25 +00:00
|
|
|
/* The stack of current FOR contexts.
|
|
|
|
* NULL when no FOR command is active */
|
2020-07-26 18:30:03 +00:00
|
|
|
PFOR_CONTEXT fc = NULL;
|
2009-03-02 19:08:25 +00:00
|
|
|
|
2009-02-24 20:29:18 +00:00
|
|
|
/* Get the next element of the FOR's list */
|
|
|
|
static BOOL GetNextElement(TCHAR **pStart, TCHAR **pEnd)
|
|
|
|
{
|
2013-06-30 00:08:43 +00:00
|
|
|
TCHAR *p = *pEnd;
|
|
|
|
BOOL InQuotes = FALSE;
|
|
|
|
while (_istspace(*p))
|
|
|
|
p++;
|
|
|
|
if (!*p)
|
|
|
|
return FALSE;
|
|
|
|
*pStart = p;
|
|
|
|
while (*p && (InQuotes || !_istspace(*p)))
|
|
|
|
InQuotes ^= (*p++ == _T('"'));
|
|
|
|
*pEnd = p;
|
|
|
|
return TRUE;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute a single instance of a FOR command */
|
2020-05-18 00:03:15 +00:00
|
|
|
/* Just run the command (variable expansion is done in DoDelayedExpansion) */
|
|
|
|
#define RunInstance(Cmd) \
|
|
|
|
ExecuteCommandWithEcho((Cmd)->Subcommands)
|
2009-02-24 20:29:18 +00:00
|
|
|
|
|
|
|
/* Check if this FOR should be terminated early */
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
#define Exiting(Cmd) \
|
|
|
|
/* Someone might have removed our context */ \
|
|
|
|
(bCtrlBreak || (fc != (Cmd)->For.Context))
|
|
|
|
/* Take also GOTO jumps into account */
|
|
|
|
#define ExitingOrGoto(Cmd) \
|
|
|
|
(Exiting(Cmd) || (bc && bc->current == NULL))
|
2009-02-24 20:29:18 +00:00
|
|
|
|
|
|
|
/* Read the contents of a text file into memory,
|
|
|
|
* dynamically allocating enough space to hold it all */
|
|
|
|
static LPTSTR ReadFileContents(FILE *InputFile, TCHAR *Buffer)
|
|
|
|
{
|
2013-06-30 00:08:43 +00:00
|
|
|
SIZE_T Len = 0;
|
|
|
|
SIZE_T AllocLen = 1000;
|
2017-12-03 17:49:41 +00:00
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
LPTSTR Contents = cmd_alloc(AllocLen * sizeof(TCHAR));
|
|
|
|
if (!Contents)
|
2017-12-03 17:49:41 +00:00
|
|
|
{
|
|
|
|
WARN("Cannot allocate memory for Contents!\n");
|
2013-06-30 00:08:43 +00:00
|
|
|
return NULL;
|
2017-12-03 17:49:41 +00:00
|
|
|
}
|
2013-06-30 00:08:43 +00:00
|
|
|
|
|
|
|
while (_fgetts(Buffer, CMDLINE_LENGTH, InputFile))
|
|
|
|
{
|
|
|
|
ULONG_PTR CharsRead = _tcslen(Buffer);
|
|
|
|
while (Len + CharsRead >= AllocLen)
|
|
|
|
{
|
|
|
|
LPTSTR OldContents = Contents;
|
|
|
|
Contents = cmd_realloc(Contents, (AllocLen *= 2) * sizeof(TCHAR));
|
|
|
|
if (!Contents)
|
|
|
|
{
|
2017-12-03 17:49:41 +00:00
|
|
|
WARN("Cannot reallocate memory for Contents!\n");
|
2013-06-30 00:08:43 +00:00
|
|
|
cmd_free(OldContents);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_tcscpy(&Contents[Len], Buffer);
|
|
|
|
Len += CharsRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
Contents[Len] = _T('\0');
|
|
|
|
return Contents;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2020-07-26 18:30:03 +00:00
|
|
|
/* FOR /F: Parse the contents of each file */
|
2009-04-12 23:51:15 +00:00
|
|
|
static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
2009-02-24 20:29:18 +00:00
|
|
|
{
|
2013-06-30 00:08:43 +00:00
|
|
|
LPTSTR Delims = _T(" \t");
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
PTCHAR DelimsEndPtr = NULL;
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
TCHAR DelimsEndChr = _T('\0');
|
2013-06-30 00:08:43 +00:00
|
|
|
TCHAR Eol = _T(';');
|
|
|
|
INT SkipLines = 0;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
DWORD TokensMask = (1 << 1);
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
DWORD NumTokens = 1;
|
|
|
|
DWORD RemainderVar = 0;
|
|
|
|
#else
|
|
|
|
DWORD NumTokens = 0;
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
TCHAR StringQuote = _T('"');
|
|
|
|
TCHAR CommandQuote = _T('\'');
|
|
|
|
LPTSTR Variables[32];
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
PTCHAR Start, End;
|
2013-06-30 00:08:43 +00:00
|
|
|
INT Ret = 0;
|
|
|
|
|
|
|
|
if (Cmd->For.Params)
|
|
|
|
{
|
|
|
|
TCHAR Quote = 0;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
PTCHAR Param = Cmd->For.Params;
|
2013-06-30 00:08:43 +00:00
|
|
|
if (*Param == _T('"') || *Param == _T('\''))
|
|
|
|
Quote = *Param++;
|
|
|
|
|
|
|
|
while (*Param && *Param != Quote)
|
|
|
|
{
|
|
|
|
if (*Param <= _T(' '))
|
|
|
|
{
|
|
|
|
Param++;
|
|
|
|
}
|
|
|
|
else if (_tcsnicmp(Param, _T("delims="), 7) == 0)
|
|
|
|
{
|
|
|
|
Param += 7;
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
/*
|
|
|
|
* delims=xxx: Specifies the list of characters that separate tokens.
|
|
|
|
* This option does not cumulate: only the latest 'delims=' specification
|
|
|
|
* is taken into account.
|
|
|
|
*/
|
2013-06-30 00:08:43 +00:00
|
|
|
Delims = Param;
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
DelimsEndPtr = NULL;
|
2013-06-30 00:08:43 +00:00
|
|
|
while (*Param && *Param != Quote)
|
|
|
|
{
|
|
|
|
if (*Param == _T(' '))
|
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
PTCHAR FirstSpace = Param;
|
2013-06-30 00:08:43 +00:00
|
|
|
Param += _tcsspn(Param, _T(" "));
|
|
|
|
/* Exclude trailing spaces if this is not the last parameter */
|
|
|
|
if (*Param && *Param != Quote)
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
{
|
|
|
|
/* Save where the delimiters specification string ends */
|
|
|
|
DelimsEndPtr = FirstSpace;
|
|
|
|
}
|
2013-06-30 00:08:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Param++;
|
|
|
|
}
|
|
|
|
if (*Param == Quote)
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
{
|
|
|
|
/* Save where the delimiters specification string ends */
|
|
|
|
DelimsEndPtr = Param++;
|
|
|
|
}
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
else if (_tcsnicmp(Param, _T("eol="), 4) == 0)
|
|
|
|
{
|
|
|
|
Param += 4;
|
|
|
|
/* eol=c: Lines starting with this character (may be
|
|
|
|
* preceded by delimiters) are skipped. */
|
|
|
|
Eol = *Param;
|
|
|
|
if (Eol != _T('\0'))
|
|
|
|
Param++;
|
|
|
|
}
|
|
|
|
else if (_tcsnicmp(Param, _T("skip="), 5) == 0)
|
|
|
|
{
|
|
|
|
/* skip=n: Number of lines to skip at the beginning of each file */
|
|
|
|
SkipLines = _tcstol(Param + 5, &Param, 0);
|
|
|
|
if (SkipLines <= 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
else if (_tcsnicmp(Param, _T("tokens="), 7) == 0)
|
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
DWORD NumToksInSpec = 0; // Number of tokens in this specification.
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
Param += 7;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
/*
|
|
|
|
* tokens=x,y,m-n: List of token numbers (must be between 1 and 31)
|
|
|
|
* that will be assigned into variables. This option does not cumulate:
|
|
|
|
* only the latest 'tokens=' specification is taken into account.
|
|
|
|
*
|
|
|
|
* NOTE: In MSCMD_FOR_QUIRKS mode, for Windows' CMD compatibility,
|
|
|
|
* not all the tokens-state is reset. This leads to subtle bugs.
|
|
|
|
*/
|
|
|
|
TokensMask = 0;
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
NumToksInSpec = 0;
|
|
|
|
// Windows' CMD compatibility: bug: the asterisk-token's position is not reset!
|
|
|
|
// RemainderVar = 0;
|
|
|
|
#else
|
|
|
|
NumTokens = 0;
|
|
|
|
#endif
|
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
while (*Param && *Param != Quote && *Param != _T('*'))
|
|
|
|
{
|
|
|
|
INT First = _tcstol(Param, &Param, 0);
|
|
|
|
INT Last = First;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
2013-06-30 00:08:43 +00:00
|
|
|
if (First < 1)
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#else
|
|
|
|
if ((First < 1) || (First > 31))
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
goto error;
|
|
|
|
if (*Param == _T('-'))
|
|
|
|
{
|
|
|
|
/* It's a range of tokens */
|
|
|
|
Last = _tcstol(Param + 1, &Param, 0);
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
/* Ignore the range if the endpoints are not in correct order */
|
|
|
|
if (Last < 1)
|
|
|
|
#else
|
|
|
|
if ((Last < First) || (Last > 31))
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
/* Ignore the range if the endpoints are not in correct order */
|
|
|
|
if ((First <= Last) && (Last <= 31))
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
TokensMask |= (2 << Last) - (1 << First);
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
NumToksInSpec += (Last - First + 1);
|
|
|
|
}
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
|
|
|
|
if (*Param != _T(','))
|
|
|
|
break;
|
|
|
|
Param++;
|
|
|
|
}
|
|
|
|
/* With an asterisk at the end, an additional variable
|
|
|
|
* will be created to hold the remainder of the line
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
* (after the last specified token). */
|
2013-06-30 00:08:43 +00:00
|
|
|
if (*Param == _T('*'))
|
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
RemainderVar = ++NumToksInSpec;
|
|
|
|
#else
|
|
|
|
++NumTokens;
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
Param++;
|
|
|
|
}
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
NumTokens = max(NumTokens, NumToksInSpec);
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
else if (_tcsnicmp(Param, _T("useback"), 7) == 0)
|
|
|
|
{
|
|
|
|
Param += 7;
|
|
|
|
/* usebackq: Use alternate quote characters */
|
|
|
|
StringQuote = _T('\'');
|
|
|
|
CommandQuote = _T('`');
|
|
|
|
/* Can be written as either "useback" or "usebackq" */
|
|
|
|
if (_totlower(*Param) == _T('q'))
|
|
|
|
Param++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error:
|
|
|
|
error_syntax(Param);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
/* Windows' CMD compatibility: use the wrongly evaluated number of tokens */
|
|
|
|
fc->varcount = NumTokens;
|
|
|
|
/* Allocate a large enough variables array if needed */
|
|
|
|
if (NumTokens <= ARRAYSIZE(Variables))
|
|
|
|
{
|
|
|
|
fc->values = Variables;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fc->values = cmd_alloc(fc->varcount * sizeof(*fc->values));
|
|
|
|
if (!fc->values)
|
|
|
|
{
|
|
|
|
error_out_of_memory();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2013-06-30 00:08:43 +00:00
|
|
|
/* Count how many variables will be set: one for each token,
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
* plus maybe one for the remainder. */
|
|
|
|
fc->varcount = NumTokens;
|
|
|
|
for (NumTokens = 1; NumTokens < 32; ++NumTokens)
|
|
|
|
fc->varcount += (TokensMask >> NumTokens) & 1;
|
2013-06-30 00:08:43 +00:00
|
|
|
fc->values = Variables;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
|
|
|
|
if (*List == StringQuote || *List == CommandQuote)
|
|
|
|
{
|
|
|
|
/* Treat the entire "list" as one single element */
|
|
|
|
Start = List;
|
|
|
|
End = &List[_tcslen(List)];
|
|
|
|
goto single_element;
|
|
|
|
}
|
|
|
|
|
2020-07-26 18:30:03 +00:00
|
|
|
/* Loop over each file */
|
2013-06-30 00:08:43 +00:00
|
|
|
End = List;
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
while (!ExitingOrGoto(Cmd) && GetNextElement(&Start, &End))
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
FILE* InputFile;
|
2013-06-30 00:08:43 +00:00
|
|
|
LPTSTR FullInput, In, NextLine;
|
|
|
|
INT Skip;
|
|
|
|
single_element:
|
|
|
|
|
|
|
|
if (*Start == StringQuote && End[-1] == StringQuote)
|
|
|
|
{
|
|
|
|
/* Input given directly as a string */
|
|
|
|
End[-1] = _T('\0');
|
|
|
|
FullInput = cmd_dup(Start + 1);
|
|
|
|
}
|
|
|
|
else if (*Start == CommandQuote && End[-1] == CommandQuote)
|
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
/*
|
|
|
|
* Read input from a command. We let the CRT do the ANSI/UNICODE conversion.
|
|
|
|
* NOTE: Should we do that, or instead read in binary mode and
|
|
|
|
* do the conversion by ourselves, using *OUR* current codepage??
|
|
|
|
*/
|
2013-06-30 00:08:43 +00:00
|
|
|
End[-1] = _T('\0');
|
|
|
|
InputFile = _tpopen(Start + 1, _T("r"));
|
|
|
|
if (!InputFile)
|
|
|
|
{
|
|
|
|
error_bad_command(Start + 1);
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
Ret = 1;
|
|
|
|
goto Quit;
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
FullInput = ReadFileContents(InputFile, Buffer);
|
|
|
|
_pclose(InputFile);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Read input from a file */
|
|
|
|
TCHAR Temp = *End;
|
|
|
|
*End = _T('\0');
|
|
|
|
StripQuotes(Start);
|
|
|
|
InputFile = _tfopen(Start, _T("r"));
|
|
|
|
*End = Temp;
|
|
|
|
if (!InputFile)
|
|
|
|
{
|
|
|
|
error_sfile_not_found(Start);
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
Ret = 1;
|
|
|
|
goto Quit;
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
FullInput = ReadFileContents(InputFile, Buffer);
|
|
|
|
fclose(InputFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!FullInput)
|
|
|
|
{
|
|
|
|
error_out_of_memory();
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
Ret = 1;
|
|
|
|
goto Quit;
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
/* Patch the delimiters string */
|
|
|
|
if (DelimsEndPtr)
|
|
|
|
{
|
|
|
|
DelimsEndChr = *DelimsEndPtr;
|
|
|
|
*DelimsEndPtr = _T('\0');
|
|
|
|
}
|
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
/* Loop over the input line by line */
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
for (In = FullInput, Skip = SkipLines;
|
|
|
|
!ExitingOrGoto(Cmd) && (In != NULL);
|
|
|
|
In = NextLine)
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
DWORD RemainingTokens = TokensMask;
|
|
|
|
LPTSTR* CurVar = fc->values;
|
|
|
|
|
|
|
|
ZeroMemory(fc->values, fc->varcount * sizeof(*fc->values));
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
NumTokens = fc->varcount;
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
|
|
|
|
NextLine = _tcschr(In, _T('\n'));
|
|
|
|
if (NextLine)
|
|
|
|
*NextLine++ = _T('\0');
|
|
|
|
|
|
|
|
if (--Skip >= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Ignore lines where the first token starts with the eol character */
|
|
|
|
In += _tcsspn(In, Delims);
|
|
|
|
if (*In == Eol)
|
|
|
|
continue;
|
|
|
|
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
/* Loop as long as we have not reached the end of
|
|
|
|
* the line, and that we have tokens available.
|
|
|
|
* A maximum of 31 tokens will be enumerated. */
|
|
|
|
while (*In && ((RemainingTokens >>= 1) != 0))
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
|
|
|
/* Save pointer to this token in a variable if requested */
|
|
|
|
if (RemainingTokens & 1)
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
{
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
--NumTokens;
|
|
|
|
#endif
|
2013-06-30 00:08:43 +00:00
|
|
|
*CurVar++ = In;
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
}
|
2013-06-30 00:08:43 +00:00
|
|
|
/* Find end of token */
|
|
|
|
In += _tcscspn(In, Delims);
|
2020-07-26 18:30:03 +00:00
|
|
|
/* NULL-terminate it and advance to next token */
|
2013-06-30 00:08:43 +00:00
|
|
|
if (*In)
|
|
|
|
{
|
|
|
|
*In++ = _T('\0');
|
|
|
|
In += _tcsspn(In, Delims);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
/* Save pointer to remainder of the line if we need to do so */
|
|
|
|
if (*In)
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
if (RemainderVar && (fc->varcount - NumTokens + 1 == RemainderVar))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/* NOTE: This sets fc->values[0] at least, if no tokens
|
|
|
|
* were initialized so far, since CurVar is initialized
|
|
|
|
* originally to point to fc->values. */
|
|
|
|
*CurVar = In;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't run unless we have at least one variable filled */
|
|
|
|
if (fc->values[0])
|
2013-06-30 00:08:43 +00:00
|
|
|
Ret = RunInstance(Cmd);
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
}
|
|
|
|
|
[CMD] FOR: Fix a bug when parsing the "delims=" option in FOR loops.
Suppose the following FOR-loop command, to be run from the command-line
(if using a batch file, double each percent '%' sign):
FOR %l IN ("a,b,c,d,e" "f,g,h,i,j") DO (
FOR /F "delims=, tokens=1-3*" %a IN (%l) DO @echo %a-%b-%c-%d
)
The outermost FOR-loop enumerates the two strings "a,b,c,d,e" and
"f,g,h,i,j" (placed in %l), and parse each of these in turn, splitting
them at each specified delimiter (here only one character) ',' and storing
the results in consecutive tokens %a, %b, %c, %d, with the last token %d
containing all the remaining string (non-split).
The expected result is:
a-b-c-d,e
f-g-h-i,j
However, due to the way the delimiters string specified by the "delims="
option is stored (no stack/heap duplication of the FOR-option substring,
but reading from it directly), during the first run of the innermost
FOR-loop, the option string "delims=, tokens=1-3*" was truncated to just
after the ',' due to the erroneous "delims=" parsing, so that when this
FOR-loop ran for a second time (to deal with the second string), the option
string was already erroneously truncated, without the "tokens=..." part,
so that the parsing results were not stored in the tokens and resulting in:
a-b-c-d,e
f-%b-%c-%d
instead. The solution is to save where the "delims=" string needs to be
cut, but wait until running the actual FOR-loop to terminate it (and
saving the original character too), run the FOR-loop body, and then
restore the original character where termination took place. This allows
having the FOR-loop option string valid for the next execution of the
FOR-loop.
2020-07-04 20:22:07 +00:00
|
|
|
/* Restore the delimiters string */
|
|
|
|
if (DelimsEndPtr)
|
|
|
|
*DelimsEndPtr = DelimsEndChr;
|
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
cmd_free(FullInput);
|
|
|
|
}
|
|
|
|
|
[CMD] FOR: Additional Windows' CMD compatibility "fixes" for FOR /F token parsing command.
This compatibility behaviour implements the buggy behaviour of FOR /F
token parsing that can be observed in Windows' CMD, and that is tested
by the cmd_winetests.
It can be disabled at compile time via the MSCMD_FOR_QUIRKS define.
It fixes additional cmd_winetests, in concert with commit cb2a9c31.
Explanation of the implemented buggy behaviour
==============================================
In principle, the "tokens=x,y,m-n[*]" option describes a list of token
numbers (must be between 1 and 31) that will be assigned into variables.
Theoretically this option does not cumulate: only the latest 'tokens='
specification should be taken into account.
However things are not that simple in practice. First, not all of the
"tokens=" option state is reset when more than one specification is
provided. Second, when specifying a token range, e.g. "1-5", Windows'
CMD just ignores without error ranges that are not specified in
increasing order. Thus for example, a range "5-1" is ignored without
error. Then, token numbers strictly greater than 31 are just ignored,
and if they appear in a range, the whole range is ignored.
Another bug is the following one: suppose that the 'tokens'
specification reads:
"tokens=1-5,1-30" , or: "tokens=1-5,3" ,
i.e. more than one range, that overlap partially. Then the actual total
number of variables will not be of the larger range size, but will be
the sum, instead.
Thus, in the first example, a total of 5 + 30 == 35 variables (> 31) is
allocated, while in the second example, a total of 5 + 1 == 6 variables
is allocated, even if they won't all store data !!
In the first example, only the first 30 FOR variables will be used, and
the 5 others will contain an empty string. In the second example, only
the first 5 FOR variables will be used, and the other one will be empty.
We also see that due to that, the "Variables" buffer of fixed size
cannot always be used (since it can contain at most 32 variables).
Last but not least, when more than one "tokens=" specification is
provided, for example:
"tokens=1-31 tokens=1-20"
a total number of 31 FOR variables (because 31 is the max of 31 and 20)
is allocated, **but** only 20 are actually used, and the 11 others
return an empty string.
And in the specification: "tokens=1-31,* tokens=1-20", a total of
31 + 1 + 20 = 52 variables is initialized, but only the first 20 will
be used, and no "remaining-line" token (the '*' one) is used.
2020-07-26 18:15:25 +00:00
|
|
|
Quit:
|
|
|
|
#ifdef MSCMD_FOR_QUIRKS
|
|
|
|
if (fc->values && (fc->values != Variables))
|
|
|
|
cmd_free(fc->values);
|
|
|
|
#endif
|
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
return Ret;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2009-02-24 20:29:18 +00:00
|
|
|
/* FOR /L: Do a numeric loop */
|
2009-04-12 23:51:15 +00:00
|
|
|
static INT ForLoop(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
2009-02-24 20:29:18 +00:00
|
|
|
{
|
2013-06-30 00:08:43 +00:00
|
|
|
enum { START, STEP, END };
|
|
|
|
INT params[3] = { 0, 0, 0 };
|
|
|
|
INT i;
|
|
|
|
INT Ret = 0;
|
|
|
|
TCHAR *Start, *End = List;
|
2020-07-26 18:30:03 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 3 && GetNextElement(&Start, &End); ++i)
|
2013-06-30 00:08:43 +00:00
|
|
|
params[i] = _tcstol(Start, NULL, 0);
|
|
|
|
|
|
|
|
i = params[START];
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
/*
|
|
|
|
* Windows' CMD compatibility:
|
|
|
|
* Contrary to the other FOR-loops, FOR /L does not check
|
|
|
|
* whether a GOTO has been done, and will continue to loop.
|
|
|
|
*/
|
2013-06-30 00:08:43 +00:00
|
|
|
while (!Exiting(Cmd) &&
|
|
|
|
(params[STEP] >= 0 ? (i <= params[END]) : (i >= params[END])))
|
|
|
|
{
|
|
|
|
_itot(i, Buffer, 10);
|
|
|
|
Ret = RunInstance(Cmd);
|
|
|
|
i += params[STEP];
|
|
|
|
}
|
2020-07-26 18:30:03 +00:00
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
return Ret;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
2006-02-16 23:23:37 +00:00
|
|
|
|
2009-02-24 20:29:18 +00:00
|
|
|
/* Process a FOR in one directory. Stored in Buffer (up to BufPos) is a
|
|
|
|
* string which is prefixed to each element of the list. In a normal FOR
|
|
|
|
* it will be empty, but in FOR /R it will be the directory name. */
|
2009-04-12 23:51:15 +00:00
|
|
|
static INT ForDir(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos)
|
2009-02-24 20:29:18 +00:00
|
|
|
{
|
2013-06-30 00:08:43 +00:00
|
|
|
INT Ret = 0;
|
2020-07-26 18:30:03 +00:00
|
|
|
TCHAR *Start, *End = List;
|
|
|
|
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
while (!ExitingOrGoto(Cmd) && GetNextElement(&Start, &End))
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
|
|
|
if (BufPos + (End - Start) > &Buffer[CMDLINE_LENGTH])
|
|
|
|
continue;
|
|
|
|
memcpy(BufPos, Start, (End - Start) * sizeof(TCHAR));
|
|
|
|
BufPos[End - Start] = _T('\0');
|
|
|
|
|
|
|
|
if (_tcschr(BufPos, _T('?')) || _tcschr(BufPos, _T('*')))
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATA w32fd;
|
|
|
|
HANDLE hFind;
|
|
|
|
TCHAR *FilePart;
|
|
|
|
|
|
|
|
StripQuotes(BufPos);
|
|
|
|
hFind = FindFirstFile(Buffer, &w32fd);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
|
|
continue;
|
|
|
|
FilePart = _tcsrchr(BufPos, _T('\\'));
|
|
|
|
FilePart = FilePart ? FilePart + 1 : BufPos;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
|
|
|
continue;
|
|
|
|
if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
!= !(Cmd->For.Switches & FOR_DIRS))
|
|
|
|
continue;
|
|
|
|
if (_tcscmp(w32fd.cFileName, _T(".")) == 0 ||
|
|
|
|
_tcscmp(w32fd.cFileName, _T("..")) == 0)
|
|
|
|
continue;
|
|
|
|
_tcscpy(FilePart, w32fd.cFileName);
|
|
|
|
Ret = RunInstance(Cmd);
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
} while (!ExitingOrGoto(Cmd) && FindNextFile(hFind, &w32fd));
|
2013-06-30 00:08:43 +00:00
|
|
|
FindClose(hFind);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Ret = RunInstance(Cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ret;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
|
|
|
|
2020-07-26 18:30:03 +00:00
|
|
|
/* FOR /R: Process a FOR in each directory of a tree, recursively */
|
2009-04-12 23:51:15 +00:00
|
|
|
static INT ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos)
|
2009-02-24 20:29:18 +00:00
|
|
|
{
|
2020-07-26 18:30:03 +00:00
|
|
|
INT Ret = 0;
|
2013-06-30 00:08:43 +00:00
|
|
|
HANDLE hFind;
|
|
|
|
WIN32_FIND_DATA w32fd;
|
|
|
|
|
|
|
|
if (BufPos[-1] != _T('\\'))
|
|
|
|
{
|
|
|
|
*BufPos++ = _T('\\');
|
|
|
|
*BufPos = _T('\0');
|
|
|
|
}
|
|
|
|
|
|
|
|
Ret = ForDir(Cmd, List, Buffer, BufPos);
|
|
|
|
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
/* NOTE (We don't apply Windows' CMD compatibility here):
|
|
|
|
* Windows' CMD does not check whether a GOTO has been done,
|
|
|
|
* and will continue to loop. */
|
|
|
|
if (ExitingOrGoto(Cmd))
|
|
|
|
return Ret;
|
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
_tcscpy(BufPos, _T("*"));
|
|
|
|
hFind = FindFirstFile(Buffer, &w32fd);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
|
|
return Ret;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
continue;
|
|
|
|
if (_tcscmp(w32fd.cFileName, _T(".")) == 0 ||
|
|
|
|
_tcscmp(w32fd.cFileName, _T("..")) == 0)
|
|
|
|
continue;
|
|
|
|
Ret = ForRecursive(Cmd, List, Buffer, _stpcpy(BufPos, w32fd.cFileName));
|
[CMD] Fixes for Batch error execution control flow.
CORE-13713 CORE-13736
- In case execution of all batch contexts is stopped (by selecting "All"
at the Ctrl-C/Ctrl-Break prompt), notify as well the CheckCtrlBreak()
signal handler once there are no more batch contexts (this in effect
resets the internal 'bLeaveAll' static flag in CheckCtrlBreak).
This is an adaptation of the fix present in FreeCOM 1.5, first
described in https://gcfl.net/FreeDOS/command.com/bugs074g.html .
- Introduce a ParseErrorEx() helper that sets the 'bParseError' flag and
displays a customized syntax-error message, only for the first syntax
error encountered. Implement ParseError() around the *Ex function.
- In batch mode, echo the original pre-parsed batch file line if a parse
error has been encountered.
- When running a compound command - including IF, FOR, command blocks -,
and that control flow is modified by any CALL/GOTO/EXIT command,
detect this while running the compound command so as to stop it and go
back to the main batch execution loop, that will then set up the actual
new command to run.
- In GOTO, do not process any more parts of a compound command only when
we have found a valid label.
2020-05-18 00:05:53 +00:00
|
|
|
|
|
|
|
/* NOTE (We don't apply Windows' CMD compatibility here):
|
|
|
|
* Windows' CMD does not check whether a GOTO has been done,
|
|
|
|
* and will continue to loop. */
|
|
|
|
} while (!ExitingOrGoto(Cmd) && FindNextFile(hFind, &w32fd));
|
2013-06-30 00:08:43 +00:00
|
|
|
FindClose(hFind);
|
2020-07-26 18:30:03 +00:00
|
|
|
|
2013-06-30 00:08:43 +00:00
|
|
|
return Ret;
|
2009-02-24 20:29:18 +00:00
|
|
|
}
|
|
|
|
|
2017-12-03 17:49:41 +00:00
|
|
|
INT
|
2009-02-24 20:29:18 +00:00
|
|
|
ExecuteFor(PARSED_COMMAND *Cmd)
|
|
|
|
{
|
2020-07-26 18:30:03 +00:00
|
|
|
INT Ret;
|
|
|
|
LPTSTR List;
|
|
|
|
PFOR_CONTEXT lpNew;
|
2013-06-30 00:08:43 +00:00
|
|
|
TCHAR Buffer[CMDLINE_LENGTH]; /* Buffer to hold the variable value */
|
|
|
|
LPTSTR BufferPtr = Buffer;
|
|
|
|
|
2020-07-26 18:30:03 +00:00
|
|
|
List = DoDelayedExpansion(Cmd->For.List);
|
2013-06-30 00:08:43 +00:00
|
|
|
if (!List)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Create our FOR context */
|
|
|
|
lpNew = cmd_alloc(sizeof(FOR_CONTEXT));
|
|
|
|
if (!lpNew)
|
|
|
|
{
|
2017-12-03 17:49:41 +00:00
|
|
|
WARN("Cannot allocate memory for lpNew!\n");
|
2013-06-30 00:08:43 +00:00
|
|
|
cmd_free(List);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lpNew->prev = fc;
|
|
|
|
lpNew->firstvar = Cmd->For.Variable;
|
|
|
|
lpNew->varcount = 1;
|
|
|
|
lpNew->values = &BufferPtr;
|
|
|
|
|
|
|
|
Cmd->For.Context = lpNew;
|
|
|
|
fc = lpNew;
|
|
|
|
|
2020-07-12 21:07:23 +00:00
|
|
|
/* Run the extended FOR syntax only if extensions are enabled */
|
|
|
|
if (bEnableExtensions)
|
2013-06-30 00:08:43 +00:00
|
|
|
{
|
2020-07-12 21:07:23 +00:00
|
|
|
if (Cmd->For.Switches & FOR_F)
|
|
|
|
{
|
|
|
|
Ret = ForF(Cmd, List, Buffer);
|
|
|
|
}
|
|
|
|
else if (Cmd->For.Switches & FOR_LOOP)
|
|
|
|
{
|
|
|
|
Ret = ForLoop(Cmd, List, Buffer);
|
|
|
|
}
|
|
|
|
else if (Cmd->For.Switches & FOR_RECURSIVE)
|
|
|
|
{
|
|
|
|
DWORD Len = GetFullPathName(Cmd->For.Params ? Cmd->For.Params : _T("."),
|
|
|
|
MAX_PATH, Buffer, NULL);
|
|
|
|
Ret = ForRecursive(Cmd, List, Buffer, &Buffer[Len]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Ret = ForDir(Cmd, List, Buffer, Buffer);
|
|
|
|
}
|
2013-06-30 00:08:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Ret = ForDir(Cmd, List, Buffer, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove our context, unless someone already did that */
|
|
|
|
if (fc == lpNew)
|
|
|
|
fc = lpNew->prev;
|
|
|
|
|
|
|
|
cmd_free(lpNew);
|
|
|
|
cmd_free(List);
|
|
|
|
return Ret;
|
2006-02-16 23:23:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|