reactos/base/shell/cmd/if.c
Hermès Bélusca-Maïto 6e09a6a3ff
[CMD] Use kernel32!lstrcmp(i) when comparing strings with the IF command.
Use kernel32!lstrcmp(i) instead of CRT!_tcs(i)cmp, so as to use the correct
current thread locale information when comparing user-specific strings.
As a result, the following comparison: 'b LSS B' will return TRUE,
instead of FALSE as it would be by using the CRT functions (and by
naively considering the lexicographical order in ANSI).
This behaviour has been introduced in Windows 2000 onwards.
2020-08-19 20:36:05 +02:00

201 lines
5 KiB
C

/*
* IF.C - if internal batch command.
*
*
* History:
*
* 16 Jul 1998 (Hans B Pufal)
* started.
*
* 16 Jul 1998 (John P Price)
* Separated commands into individual files.
*
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* added config.h include
*
* 07-Jan-1999 (Eric Kohl)
* Added help text ("if /?") and cleaned up.
*
* 21-Jan-1999 (Eric Kohl)
* Unicode and redirection ready!
*
* 01-Sep-1999 (Eric Kohl)
* Fixed help text.
*
* 17-Feb-2001 (ea)
* IF DEFINED variable command
*
* 28-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>
* Remove all hardcoded strings in En.rc
*
*/
#include "precomp.h"
static INT GenericCmp(INT (WINAPI *StringCmp)(LPCTSTR, LPCTSTR),
LPCTSTR Left, LPCTSTR Right)
{
TCHAR *end;
INT nLeft = _tcstol(Left, &end, 0);
if (*end == _T('\0'))
{
INT nRight = _tcstol(Right, &end, 0);
if (*end == _T('\0'))
{
/* both arguments are numeric */
return (nLeft < nRight) ? -1 : (nLeft > nRight);
}
}
return StringCmp(Left, Right);
}
INT cmd_if(LPTSTR param)
{
TRACE("cmd_if(\'%s\')\n", debugstr_aw(param));
if (!_tcsncmp (param, _T("/?"), 2))
{
ConOutResPaging(TRUE, STRING_IF_HELP1);
return 0;
}
ParseErrorEx(param);
return 1;
}
INT ExecuteIf(PARSED_COMMAND *Cmd)
{
INT result = FALSE; /* when set cause 'then' clause to be executed */
LPTSTR param;
LPTSTR Left = NULL, Right;
if (Cmd->If.LeftArg)
{
Left = DoDelayedExpansion(Cmd->If.LeftArg);
if (!Left)
return 1;
}
Right = DoDelayedExpansion(Cmd->If.RightArg);
if (!Right)
{
cmd_free(Left);
return 1;
}
if (Cmd->If.Operator == IF_CMDEXTVERSION)
{
/* IF CMDEXTVERSION n: check if Command Extensions version
* is greater or equal to n */
DWORD n = _tcstoul(Right, &param, 10);
if (*param != _T('\0'))
{
error_syntax(Right);
cmd_free(Right);
return 1;
}
result = (2 >= n);
}
else if (Cmd->If.Operator == IF_DEFINED)
{
/* IF DEFINED var: check if environment variable exists */
result = (GetEnvVarOrSpecial(Right) != NULL);
}
else if (Cmd->If.Operator == IF_ERRORLEVEL)
{
/* IF ERRORLEVEL n: check if last exit code is greater or equal to n */
INT n = _tcstol(Right, &param, 10);
if (*param != _T('\0'))
{
error_syntax(Right);
cmd_free(Right);
return 1;
}
result = (nErrorLevel >= n);
}
else if (Cmd->If.Operator == IF_EXIST)
{
BOOL IsDir;
INT Size;
WIN32_FIND_DATA f;
HANDLE hFind;
DWORD attrs;
/* IF EXIST filename: check if file exists (wildcards allowed) */
StripQuotes(Right);
Size = _tcslen(Right);
IsDir = (Right[Size - 1] == '\\');
if (IsDir)
Right[Size - 1] = 0;
hFind = FindFirstFile(Right, &f);
if (hFind != INVALID_HANDLE_VALUE)
{
attrs = f.dwFileAttributes;
FindClose(hFind);
}
else
{
/* FindFirstFile fails at the root directory. */
attrs = GetFileAttributes(Right);
}
if (attrs == 0xFFFFFFFF)
result = FALSE;
else if (IsDir)
result = ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
else
result = TRUE;
if (IsDir)
Right[Size - 1] = '\\';
}
else
{
/*
* Do case-insensitive string comparisons if /I specified.
*
* Since both strings are user-specific, use kernel32!lstrcmp(i)
* instead of CRT!_tcs(i)cmp, so as to use the correct
* current thread locale information.
*/
INT (WINAPI *StringCmp)(LPCTSTR, LPCTSTR) =
(Cmd->If.Flags & IFFLAG_IGNORECASE) ? lstrcmpi : lstrcmp;
if (Cmd->If.Operator == IF_STRINGEQ)
{
/* IF str1 == str2 */
result = (StringCmp(Left, Right) == 0);
}
else
{
result = GenericCmp(StringCmp, Left, Right);
switch (Cmd->If.Operator)
{
case IF_EQU: result = (result == 0); break;
case IF_NEQ: result = (result != 0); break;
case IF_LSS: result = (result < 0); break;
case IF_LEQ: result = (result <= 0); break;
case IF_GTR: result = (result > 0); break;
case IF_GEQ: result = (result >= 0); break;
}
}
}
cmd_free(Left);
cmd_free(Right);
if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0))
{
/* Full condition was true, do the command */
return ExecuteCommand(Cmd->Subcommands);
}
else
{
/* Full condition was false, do the "else" command if there is one */
return ExecuteCommand(Cmd->Subcommands->Next);
}
}
/* EOF */