mirror of
https://github.com/reactos/reactos.git
synced 2025-07-29 02:42:21 +00:00
[CMD] GOTO: Fix label parsing.
We note two things, when CMD searches for the corresponding label in the batch file: - the first character of the line is always ignored, unless it's a colon; - the escape caret ^ is supported and interpreted. Fixes some cmd_winetests.
This commit is contained in:
parent
71cd64d66a
commit
2e4c8c019e
4 changed files with 74 additions and 34 deletions
|
@ -131,7 +131,7 @@ static LPTSTR BatchParams(LPTSTR s1, LPTSTR s2)
|
||||||
BOOL inquotes = FALSE;
|
BOOL inquotes = FALSE;
|
||||||
|
|
||||||
/* Find next parameter */
|
/* Find next parameter */
|
||||||
while (_istspace(*s2) || (*s2 && _tcschr(_T(",;="), *s2)))
|
while (_istspace(*s2) || (*s2 && _tcschr(STANDARD_SEPS, *s2)))
|
||||||
s2++;
|
s2++;
|
||||||
if (!*s2)
|
if (!*s2)
|
||||||
break;
|
break;
|
||||||
|
@ -139,7 +139,7 @@ static LPTSTR BatchParams(LPTSTR s1, LPTSTR s2)
|
||||||
/* Copy it */
|
/* Copy it */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!inquotes && (_istspace(*s2) || _tcschr(_T(",;="), *s2)))
|
if (!inquotes && (_istspace(*s2) || _tcschr(STANDARD_SEPS, *s2)))
|
||||||
break;
|
break;
|
||||||
inquotes ^= (*s2 == _T('"'));
|
inquotes ^= (*s2 == _T('"'));
|
||||||
*s1++ = *s2++;
|
*s1++ = *s2++;
|
||||||
|
|
|
@ -301,6 +301,10 @@ INT cmd_move (LPTSTR);
|
||||||
INT CommandMsgbox (LPTSTR);
|
INT CommandMsgbox (LPTSTR);
|
||||||
|
|
||||||
/* Prototypes from PARSER.C */
|
/* Prototypes from PARSER.C */
|
||||||
|
|
||||||
|
/* These three characters act like spaces to the parser in most contexts */
|
||||||
|
#define STANDARD_SEPS _T(",;=")
|
||||||
|
|
||||||
enum { C_COMMAND, C_QUIET, C_BLOCK, C_MULTI, C_OR, C_AND, C_PIPE, C_IF, C_FOR };
|
enum { C_COMMAND, C_QUIET, C_BLOCK, C_MULTI, C_OR, C_AND, C_PIPE, C_IF, C_FOR };
|
||||||
typedef struct _PARSED_COMMAND
|
typedef struct _PARSED_COMMAND
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
*/
|
*/
|
||||||
INT cmd_goto(LPTSTR param)
|
INT cmd_goto(LPTSTR param)
|
||||||
{
|
{
|
||||||
LPTSTR tmp, tmp2;
|
LPTSTR label, tmp;
|
||||||
DWORD dwCurrPos;
|
DWORD dwCurrPos;
|
||||||
BOOL bRetry;
|
BOOL bRetry;
|
||||||
|
|
||||||
|
@ -59,11 +59,9 @@ INT cmd_goto(LPTSTR param)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminate label at first space char */
|
/* Strip leading whitespace */
|
||||||
tmp = param + 1;
|
while (_istspace(*param))
|
||||||
while (!_istcntrl(*tmp) && !_istspace(*tmp) && (*tmp != _T(':')))
|
++param;
|
||||||
++tmp;
|
|
||||||
*tmp = _T('\0');
|
|
||||||
|
|
||||||
/* Support jumping to the end of the file, only if extensions are enabled */
|
/* Support jumping to the end of the file, only if extensions are enabled */
|
||||||
if (bEnableExtensions &&
|
if (bEnableExtensions &&
|
||||||
|
@ -78,6 +76,23 @@ INT cmd_goto(LPTSTR param)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Skip the first colon or plus sign */
|
||||||
|
if (*param == _T(':') || *param == _T('+'))
|
||||||
|
++param;
|
||||||
|
/* Terminate the label at the first delimiter character */
|
||||||
|
tmp = param;
|
||||||
|
while (!_istcntrl(*tmp) && !_istspace(*tmp) &&
|
||||||
|
!_tcschr(_T(":+"), *tmp) && !_tcschr(STANDARD_SEPS, *tmp) /* &&
|
||||||
|
!_tcschr(_T("&|<>"), *tmp) */)
|
||||||
|
{
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
*tmp = _T('\0');
|
||||||
|
|
||||||
|
/* If we don't have any label, bail out */
|
||||||
|
if (!*param)
|
||||||
|
goto NotFound;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search the next label starting our position, until the end of the file.
|
* Search the next label starting our position, until the end of the file.
|
||||||
* If none has been found, restart at the beginning of the file, and continue
|
* If none has been found, restart at the beginning of the file, and continue
|
||||||
|
@ -89,36 +104,59 @@ INT cmd_goto(LPTSTR param)
|
||||||
retry:
|
retry:
|
||||||
while (BatchGetString(textline, ARRAYSIZE(textline)))
|
while (BatchGetString(textline, ARRAYSIZE(textline)))
|
||||||
{
|
{
|
||||||
INT pos;
|
|
||||||
INT_PTR size;
|
|
||||||
|
|
||||||
if (bRetry && (bc->mempos >= dwCurrPos))
|
if (bRetry && (bc->mempos >= dwCurrPos))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Strip out any trailing spaces or control chars */
|
#if 0
|
||||||
tmp = textline + _tcslen(textline) - 1;
|
/* If this is not a label, continue searching */
|
||||||
while (tmp > textline && (_istcntrl(*tmp) || _istspace(*tmp) || (*tmp == _T(':'))))
|
if (!_tcschr(textline, _T(':')))
|
||||||
--tmp;
|
continue;
|
||||||
*(tmp + 1) = _T('\0');
|
#endif
|
||||||
|
|
||||||
/* Then leading spaces... */
|
label = textline;
|
||||||
tmp = textline;
|
|
||||||
while (_istspace(*tmp))
|
|
||||||
++tmp;
|
|
||||||
|
|
||||||
/* All space after leading space terminate the string */
|
/* A bug in Windows' CMD makes it always ignore the
|
||||||
size = _tcslen(tmp) - 1;
|
* first character of the line, unless it's a colon. */
|
||||||
pos = 0;
|
if (*label != _T(':'))
|
||||||
while (tmp + pos < tmp + size)
|
++label;
|
||||||
|
|
||||||
|
/* Strip any leading whitespace */
|
||||||
|
while (_istspace(*label))
|
||||||
|
++label;
|
||||||
|
|
||||||
|
/* If this is not a label, continue searching */
|
||||||
|
if (*label != _T(':'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip the first colon or plus sign */
|
||||||
|
#if 0
|
||||||
|
if (*label == _T(':') || *label == _T('+'))
|
||||||
|
++label;
|
||||||
|
#endif
|
||||||
|
++label;
|
||||||
|
/* Strip any whitespace between the colon and the label */
|
||||||
|
while (_istspace(*label))
|
||||||
|
++label;
|
||||||
|
/* Terminate the label at the first delimiter character */
|
||||||
|
tmp = label;
|
||||||
|
while (!_istcntrl(*tmp) && !_istspace(*tmp) &&
|
||||||
|
!_tcschr(_T(":+"), *tmp) && !_tcschr(STANDARD_SEPS, *tmp) &&
|
||||||
|
!_tcschr(_T("&|<>"), *tmp))
|
||||||
{
|
{
|
||||||
if (_istspace(tmp[pos]))
|
/* Support the escape caret */
|
||||||
tmp[pos]=_T('\0');
|
if (*tmp == _T('^'))
|
||||||
++pos;
|
{
|
||||||
|
/* Move the buffer back one character */
|
||||||
|
memmove(tmp, tmp + 1, (_tcslen(tmp + 1) + 1) * sizeof(TCHAR));
|
||||||
|
/* We will ignore the new character */
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp2 = param;
|
++tmp;
|
||||||
/* Use whole label name */
|
}
|
||||||
if ((*tmp == _T(':')) && ((_tcsicmp(++tmp, param) == 0) || (_tcsicmp(tmp, ++tmp2) == 0)))
|
*tmp = _T('\0');
|
||||||
|
|
||||||
|
/* Jump if the labels are identical */
|
||||||
|
if (_tcsicmp(label, param) == 0)
|
||||||
{
|
{
|
||||||
/* Do not process any more parts of a compound command */
|
/* Do not process any more parts of a compound command */
|
||||||
bc->current = NULL;
|
bc->current = NULL;
|
||||||
|
@ -132,6 +170,7 @@ retry:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotFound:
|
||||||
ConErrResPrintf(STRING_GOTO_ERROR2, param);
|
ConErrResPrintf(STRING_GOTO_ERROR2, param);
|
||||||
ExitBatch();
|
ExitBatch();
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -39,9 +39,6 @@ static const TCHAR *const IfOperatorString[] =
|
||||||
#define IF_MAX_COMPARISON IF_NEQ
|
#define IF_MAX_COMPARISON IF_NEQ
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These three characters act like spaces to the parser in most contexts */
|
|
||||||
#define STANDARD_SEPS _T(",;=")
|
|
||||||
|
|
||||||
static BOOL IsSeparator(TCHAR Char)
|
static BOOL IsSeparator(TCHAR Char)
|
||||||
{
|
{
|
||||||
return _istspace(Char) || (Char && _tcschr(STANDARD_SEPS, Char));
|
return _istspace(Char) || (Char && _tcschr(STANDARD_SEPS, Char));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue