mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +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.
This commit is contained in:
parent
5cf0517be1
commit
5d5a1a455c
1 changed files with 27 additions and 3 deletions
|
@ -121,6 +121,8 @@ static LPTSTR ReadFileContents(FILE *InputFile, TCHAR *Buffer)
|
|||
static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
||||
{
|
||||
LPTSTR Delims = _T(" \t");
|
||||
LPTSTR DelimsEndPtr = NULL;
|
||||
TCHAR DelimsEndChr = _T('\0');
|
||||
TCHAR Eol = _T(';');
|
||||
INT SkipLines = 0;
|
||||
DWORD Tokens = (1 << 1);
|
||||
|
@ -148,8 +150,13 @@ static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
|||
else if (_tcsnicmp(Param, _T("delims="), 7) == 0)
|
||||
{
|
||||
Param += 7;
|
||||
/* delims=xxx: Specifies the list of characters that separate tokens */
|
||||
/*
|
||||
* delims=xxx: Specifies the list of characters that separate tokens.
|
||||
* This option does not cumulate: only the latest 'delims=' specification
|
||||
* is taken into account.
|
||||
*/
|
||||
Delims = Param;
|
||||
DelimsEndPtr = NULL;
|
||||
while (*Param && *Param != Quote)
|
||||
{
|
||||
if (*Param == _T(' '))
|
||||
|
@ -158,13 +165,19 @@ static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
|||
Param += _tcsspn(Param, _T(" "));
|
||||
/* Exclude trailing spaces if this is not the last parameter */
|
||||
if (*Param && *Param != Quote)
|
||||
*FirstSpace = _T('\0');
|
||||
{
|
||||
/* Save where the delimiters specification string ends */
|
||||
DelimsEndPtr = FirstSpace;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Param++;
|
||||
}
|
||||
if (*Param == Quote)
|
||||
*Param++ = _T('\0');
|
||||
{
|
||||
/* Save where the delimiters specification string ends */
|
||||
DelimsEndPtr = Param++;
|
||||
}
|
||||
}
|
||||
else if (_tcsnicmp(Param, _T("eol="), 4) == 0)
|
||||
{
|
||||
|
@ -301,6 +314,13 @@ static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Patch the delimiters string */
|
||||
if (DelimsEndPtr)
|
||||
{
|
||||
DelimsEndChr = *DelimsEndPtr;
|
||||
*DelimsEndPtr = _T('\0');
|
||||
}
|
||||
|
||||
/* Loop over the input line by line */
|
||||
for (In = FullInput, Skip = SkipLines;
|
||||
!ExitingOrGoto(Cmd) && (In != NULL);
|
||||
|
@ -343,6 +363,10 @@ static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer)
|
|||
Ret = RunInstance(Cmd);
|
||||
}
|
||||
|
||||
/* Restore the delimiters string */
|
||||
if (DelimsEndPtr)
|
||||
*DelimsEndPtr = DelimsEndChr;
|
||||
|
||||
cmd_free(FullInput);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue