/** @file
Main file for If and else shell level 1 function.
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiShellLevel1CommandsLib.h"
#include
typedef enum {
EndTagOr,
EndTagAnd,
EndTagThen,
EndTagMax
} END_TAG_TYPE;
typedef enum {
OperatorGreaterThan,
OperatorLessThan,
OperatorEqual,
OperatorNotEqual,
OperatorGreatorOrEqual,
OperatorLessOrEqual,
OperatorUnisgnedGreaterThan,
OperatorUnsignedLessThan,
OperatorUnsignedGreaterOrEqual,
OperatorUnsignedLessOrEqual,
OperatorMax
} BIN_OPERATOR_TYPE;
/**
Extract the next fragment, if there is one.
@param[in, out] Statement The current remaining statement.
@param[in] Fragment The current fragment.
@param[out] Match TRUE when there is another Fragment in Statement,
FALSE otherwise.
@retval EFI_SUCCESS The match operation is performed successfully.
@retval EFI_OUT_OF_RESOURCES Out of resources.
**/
EFI_STATUS
IsNextFragment (
IN OUT CONST CHAR16 **Statement,
IN CONST CHAR16 *Fragment,
OUT BOOLEAN *Match
)
{
CHAR16 *Tester;
Tester = NULL;
Tester = StrnCatGrow (&Tester, NULL, *Statement, StrLen (Fragment));
if (Tester == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Tester[StrLen (Fragment)] = CHAR_NULL;
if (gUnicodeCollation->StriColl (
gUnicodeCollation,
(CHAR16 *)Fragment,
Tester
) == 0)
{
//
// increment the string pointer to the end of what we found and then chop off spaces...
//
*Statement += StrLen (Fragment);
while (*Statement[0] == L' ') {
(*Statement)++;
}
*Match = TRUE;
} else {
*Match = FALSE;
}
FreePool (Tester);
return EFI_SUCCESS;
}
/**
Determine if String represents a valid profile.
@param[in] String The pointer to the string to test.
@retval TRUE String is a valid profile.
@retval FALSE String is not a valid profile.
**/
BOOLEAN
IsValidProfile (
IN CONST CHAR16 *String
)
{
CONST CHAR16 *ProfilesString;
CONST CHAR16 *TempLocation;
ProfilesString = ShellGetEnvironmentVariable (L"profiles");
ASSERT (ProfilesString != NULL);
TempLocation = StrStr (ProfilesString, String);
if ((TempLocation != NULL) && (*(TempLocation-1) == L';') && (*(TempLocation+StrLen (String)) == L';')) {
return (TRUE);
}
return (FALSE);
}
/**
Do a comparison between 2 things.
@param[in] Compare1 The first item to compare.
@param[in] Compare2 The second item to compare.
@param[in] BinOp The type of comparison to perform.
@param[in] CaseInsensitive TRUE to do non-case comparison, FALSE otherwise.
@param[in] ForceStringCompare TRUE to force string comparison, FALSE otherwise.
@return The result of the comparison.
**/
BOOLEAN
TestOperation (
IN CONST CHAR16 *Compare1,
IN CONST CHAR16 *Compare2,
IN CONST BIN_OPERATOR_TYPE BinOp,
IN CONST BOOLEAN CaseInsensitive,
IN CONST BOOLEAN ForceStringCompare
)
{
INTN Cmp1;
INTN Cmp2;
//
// "Compare1 BinOp Compare2"
//
switch (BinOp) {
case OperatorUnisgnedGreaterThan:
case OperatorGreaterThan:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) > 0)) || (StringCompare (&Compare1, &Compare2) > 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (BinOp == OperatorGreaterThan) {
if (Cmp1 > Cmp2) {
return (TRUE);
}
} else {
if ((UINTN)Cmp1 > (UINTN)Cmp2) {
return (TRUE);
}
}
}
return (FALSE);
case OperatorUnsignedLessThan:
case OperatorLessThan:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) < 0)) || (StringCompare (&Compare1, &Compare2) < 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (BinOp == OperatorLessThan) {
if (Cmp1 < Cmp2) {
return (TRUE);
}
} else {
if ((UINTN)Cmp1 < (UINTN)Cmp2) {
return (TRUE);
}
}
}
return (FALSE);
case OperatorEqual:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) == 0)) || (StringCompare (&Compare1, &Compare2) == 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (Cmp1 == Cmp2) {
return (TRUE);
}
}
return (FALSE);
case OperatorNotEqual:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) != 0)) || (StringCompare (&Compare1, &Compare2) != 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (Cmp1 != Cmp2) {
return (TRUE);
}
}
return (FALSE);
case OperatorUnsignedGreaterOrEqual:
case OperatorGreatorOrEqual:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) >= 0)) || (StringCompare (&Compare1, &Compare2) >= 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (BinOp == OperatorGreatorOrEqual) {
if (Cmp1 >= Cmp2) {
return (TRUE);
}
} else {
if ((UINTN)Cmp1 >= (UINTN)Cmp2) {
return (TRUE);
}
}
}
return (FALSE);
case OperatorLessOrEqual:
case OperatorUnsignedLessOrEqual:
if (ForceStringCompare || !ShellIsHexOrDecimalNumber (Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber (Compare2, FALSE, FALSE)) {
//
// string compare
//
if ((CaseInsensitive && (StringNoCaseCompare (&Compare1, &Compare2) <= 0)) || (StringCompare (&Compare1, &Compare2) <= 0)) {
return (TRUE);
}
} else {
//
// numeric compare
//
if (Compare1[0] == L'-') {
Cmp1 = 0 - (INTN)ShellStrToUintn (Compare1+1);
} else {
Cmp1 = (INTN)ShellStrToUintn (Compare1);
}
if (Compare2[0] == L'-') {
Cmp2 = 0 - (INTN)ShellStrToUintn (Compare2+1);
} else {
Cmp2 = (INTN)ShellStrToUintn (Compare2);
}
if (BinOp == OperatorLessOrEqual) {
if (Cmp1 <= Cmp2) {
return (TRUE);
}
} else {
if ((UINTN)Cmp1 <= (UINTN)Cmp2) {
return (TRUE);
}
}
}
return (FALSE);
default:
ASSERT (FALSE);
return (FALSE);
}
}
/**
Process an if statement and determine if its is valid or not.
@param[in, out] PassingState Opon entry, the current state. Upon exit,
the new state.
@param[in] StartParameterNumber The number of the first parameter of
this statement.
@param[in] EndParameterNumber The number of the final parameter of
this statement.
@param[in] OperatorToUse The type of termination operator.
@param[in] CaseInsensitive TRUE for case insensitive, FALSE otherwise.
@param[in] ForceStringCompare TRUE for all string based, FALSE otherwise.
@retval EFI_INVALID_PARAMETER A parameter was invalid.
@retval EFI_SUCCESS The operation was successful.
**/
EFI_STATUS
ProcessStatement (
IN OUT BOOLEAN *PassingState,
IN UINTN StartParameterNumber,
IN UINTN EndParameterNumber,
IN CONST END_TAG_TYPE OperatorToUse,
IN CONST BOOLEAN CaseInsensitive,
IN CONST BOOLEAN ForceStringCompare
)
{
EFI_STATUS Status;
BOOLEAN OperationResult;
BOOLEAN NotPresent;
CHAR16 *StatementWalker;
BIN_OPERATOR_TYPE BinOp;
CHAR16 *Compare1;
CHAR16 *Compare2;
CHAR16 HexString[20];
CHAR16 *TempSpot;
BOOLEAN Match;
ASSERT ((END_TAG_TYPE)OperatorToUse != EndTagThen);
Status = EFI_SUCCESS;
BinOp = OperatorMax;
OperationResult = FALSE;
Match = FALSE;
StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"not", &Match)) && Match) {
NotPresent = TRUE;
StatementWalker = gEfiShellParametersProtocol->Argv[++StartParameterNumber];
} else {
NotPresent = FALSE;
}
//
// now check for 'boolfunc' operators
//
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"isint", &Match)) && Match) {
if ( !EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match
&& (StatementWalker[StrLen (StatementWalker)-1] == L')'))
{
StatementWalker[StrLen (StatementWalker)-1] = CHAR_NULL;
OperationResult = ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE);
} else {
Status = EFI_INVALID_PARAMETER;
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"isint");
}
} else if ((!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"exists", &Match)) && Match) ||
(!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"exist", &Match)) && Match))
{
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match &&
(StatementWalker[StrLen (StatementWalker)-1] == L')'))
{
StatementWalker[StrLen (StatementWalker)-1] = CHAR_NULL;
//
// is what remains a file in CWD???
//
OperationResult = (BOOLEAN)(ShellFileExists (StatementWalker) == EFI_SUCCESS);
} else if ((StatementWalker[0] == CHAR_NULL) && (StartParameterNumber+1 == EndParameterNumber)) {
OperationResult = (BOOLEAN)(ShellFileExists (gEfiShellParametersProtocol->Argv[++StartParameterNumber]) == EFI_SUCCESS);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"exist(s)");
Status = EFI_INVALID_PARAMETER;
}
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"available", &Match)) && Match) {
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match &&
(StatementWalker[StrLen (StatementWalker)-1] == L')'))
{
StatementWalker[StrLen (StatementWalker)-1] = CHAR_NULL;
//
// is what remains a file in the CWD or path???
//
OperationResult = (BOOLEAN)(ShellIsFileInPath (StatementWalker) == EFI_SUCCESS);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"available");
Status = EFI_INVALID_PARAMETER;
}
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"profile", &Match)) && Match) {
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match &&
(StatementWalker[StrLen (StatementWalker)-1] == L')'))
{
//
// Chop off that ')'
//
StatementWalker[StrLen (StatementWalker)-1] = CHAR_NULL;
OperationResult = IsValidProfile (StatementWalker);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"profile");
Status = EFI_INVALID_PARAMETER;
}
} else if (StartParameterNumber+1 >= EndParameterNumber) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber]);
Status = EFI_INVALID_PARAMETER;
} else {
//
// must be 'item binop item' style
//
Compare1 = NULL;
Compare2 = NULL;
BinOp = OperatorMax;
//
// get the first item
//
StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"efierror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
*TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT);
ASSERT (Compare1 == NULL);
Compare1 = StrnCatGrow (&Compare1, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
Status = EFI_INVALID_PARAMETER;
}
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"pierror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
*TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT|(MAX_BIT>>2));
ASSERT (Compare1 == NULL);
Compare1 = StrnCatGrow (&Compare1, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
Status = EFI_INVALID_PARAMETER;
}
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"oemerror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT|(MAX_BIT>>1));
ASSERT (Compare1 == NULL);
Compare1 = StrnCatGrow (&Compare1, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ASSERT (Compare1 == NULL);
if (EndParameterNumber - StartParameterNumber > 2) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber+2]);
Status = EFI_INVALID_PARAMETER;
} else {
//
// must be a raw string
//
Compare1 = StrnCatGrow (&Compare1, NULL, StatementWalker, 0);
}
}
//
// get the operator
//
ASSERT (StartParameterNumber+1 < EndParameterNumber);
StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+1];
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"gt", &Match)) && Match) {
BinOp = OperatorGreaterThan;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"lt", &Match)) && Match) {
BinOp = OperatorLessThan;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"eq", &Match)) && Match) {
BinOp = OperatorEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"ne", &Match)) && Match) {
BinOp = OperatorNotEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"ge", &Match)) && Match) {
BinOp = OperatorGreatorOrEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"le", &Match)) && Match) {
BinOp = OperatorLessOrEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"==", &Match)) && Match) {
BinOp = OperatorEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"ugt", &Match)) && Match) {
BinOp = OperatorUnisgnedGreaterThan;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"ult", &Match)) && Match) {
BinOp = OperatorUnsignedLessThan;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"uge", &Match)) && Match) {
BinOp = OperatorUnsignedGreaterOrEqual;
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"ule", &Match)) && Match) {
BinOp = OperatorUnsignedLessOrEqual;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_INVALID_BINOP), gShellLevel1HiiHandle, StatementWalker);
Status = EFI_INVALID_PARAMETER;
}
//
// get the second item
//
ASSERT (StartParameterNumber+2 <= EndParameterNumber);
StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+2];
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"efierror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT);
ASSERT (Compare2 == NULL);
Compare2 = StrnCatGrow (&Compare2, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
Status = EFI_INVALID_PARAMETER;
}
//
// can this be collapsed into the above?
//
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"pierror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT|(MAX_BIT>>2));
ASSERT (Compare2 == NULL);
Compare2 = StrnCatGrow (&Compare2, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
Status = EFI_INVALID_PARAMETER;
}
} else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"oemerror", &Match)) && Match) {
TempSpot = StrStr (StatementWalker, L")");
if (!EFI_ERROR (IsNextFragment ((CONST CHAR16 **)(&StatementWalker), L"(", &Match)) && Match && (TempSpot != NULL)) {
TempSpot = CHAR_NULL;
if (ShellIsHexOrDecimalNumber (StatementWalker, FALSE, FALSE)) {
UnicodeSPrint (HexString, sizeof (HexString), L"0x%x", ShellStrToUintn (StatementWalker)|MAX_BIT|(MAX_BIT>>1));
ASSERT (Compare2 == NULL);
Compare2 = StrnCatGrow (&Compare2, NULL, HexString, 0);
StatementWalker += StrLen (StatementWalker) + 1;
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
Status = EFI_INVALID_PARAMETER;
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
Status = EFI_INVALID_PARAMETER;
}
} else {
//
// must be a raw string
//
ASSERT (Compare2 == NULL);
Compare2 = StrnCatGrow (&Compare2, NULL, StatementWalker, 0);
}
if ((Compare1 != NULL) && (Compare2 != NULL) && (BinOp != OperatorMax)) {
OperationResult = TestOperation (Compare1, Compare2, BinOp, CaseInsensitive, ForceStringCompare);
}
SHELL_FREE_NON_NULL (Compare1);
SHELL_FREE_NON_NULL (Compare2);
}
//
// done processing do result...
//
if (!EFI_ERROR (Status)) {
if (NotPresent) {
OperationResult = (BOOLEAN)(!OperationResult);
}
switch (OperatorToUse) {
case EndTagOr:
*PassingState = (BOOLEAN)(*PassingState || OperationResult);
break;
case EndTagAnd:
*PassingState = (BOOLEAN)(*PassingState && OperationResult);
break;
case EndTagMax:
*PassingState = (BOOLEAN)(OperationResult);
break;
default:
ASSERT (FALSE);
}
}
return (Status);
}
/**
Break up the next part of the if statement (until the next 'and', 'or', or 'then').
@param[in] ParameterNumber The current parameter number.
@param[out] EndParameter Upon successful return, will point to the
parameter to start the next iteration with.
@param[out] EndTag Upon successful return, will point to the
type that was found at the end of this statement.
@retval TRUE A valid statement was found.
@retval FALSE A valid statement was not found.
**/
BOOLEAN
BuildNextStatement (
IN UINTN ParameterNumber,
OUT UINTN *EndParameter,
OUT END_TAG_TYPE *EndTag
)
{
*EndTag = EndTagMax;
for (
; ParameterNumber < gEfiShellParametersProtocol->Argc
; ParameterNumber++
)
{
if (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[ParameterNumber],
L"or"
) == 0)
{
*EndParameter = ParameterNumber - 1;
*EndTag = EndTagOr;
break;
} else if (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[ParameterNumber],
L"and"
) == 0)
{
*EndParameter = ParameterNumber - 1;
*EndTag = EndTagAnd;
break;
} else if (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[ParameterNumber],
L"then"
) == 0)
{
*EndParameter = ParameterNumber - 1;
*EndTag = EndTagThen;
break;
}
}
if (*EndTag == EndTagMax) {
return (FALSE);
}
return (TRUE);
}
/**
Move the script file pointer to a different place in the script file.
This one is special since it handles the if/else/endif syntax.
@param[in] ScriptFile The script file from GetCurrnetScriptFile().
@retval TRUE The move target was found and the move was successful.
@retval FALSE Something went wrong.
**/
BOOLEAN
MoveToTagSpecial (
IN SCRIPT_FILE *ScriptFile
)
{
SCRIPT_COMMAND_LIST *CommandNode;
BOOLEAN Found;
UINTN TargetCount;
CHAR16 *CommandName;
CHAR16 *CommandWalker;
CHAR16 *TempLocation;
TargetCount = 1;
Found = FALSE;
if (ScriptFile == NULL) {
return FALSE;
}
for (CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode (&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE
; !IsNull (&ScriptFile->CommandList, &CommandNode->Link) && !Found
; CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode (&ScriptFile->CommandList, &CommandNode->Link)
)
{
//
// get just the first part of the command line...
//
CommandName = NULL;
CommandName = StrnCatGrow (&CommandName, NULL, CommandNode->Cl, 0);
if (CommandName == NULL) {
continue;
}
CommandWalker = CommandName;
//
// Skip leading spaces and tabs.
//
while ((CommandWalker[0] == L' ') || (CommandWalker[0] == L'\t')) {
CommandWalker++;
}
TempLocation = StrStr (CommandWalker, L" ");
if (TempLocation != NULL) {
*TempLocation = CHAR_NULL;
}
//
// did we find a nested item ?
//
if (gUnicodeCollation->StriColl (
gUnicodeCollation,
(CHAR16 *)CommandWalker,
L"If"
) == 0)
{
TargetCount++;
} else if ((TargetCount == 1) && (gUnicodeCollation->StriColl (
gUnicodeCollation,
(CHAR16 *)CommandWalker,
(CHAR16 *)L"else"
) == 0))
{
//
// else can only decrement the last part... not an nested if
// hence the TargetCount compare added
//
TargetCount--;
} else if (gUnicodeCollation->StriColl (
gUnicodeCollation,
(CHAR16 *)CommandWalker,
(CHAR16 *)L"endif"
) == 0)
{
TargetCount--;
}
if (TargetCount == 0) {
ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode (&ScriptFile->CommandList, &CommandNode->Link);
Found = TRUE;
}
//
// Free the memory for this loop...
//
SHELL_FREE_NON_NULL (CommandName);
}
return (Found);
}
/**
Deal with the result of the if operation.
@param[in] Result The result of the if.
@retval EFI_SUCCESS The operation was successful.
@retval EFI_NOT_FOUND The ending tag could not be found.
**/
EFI_STATUS
PerformResultOperation (
IN CONST BOOLEAN Result
)
{
if (Result || MoveToTagSpecial (ShellCommandGetCurrentScriptFile ())) {
return (EFI_SUCCESS);
}
return (EFI_NOT_FOUND);
}
/**
Function for 'if' command.
@param[in] ImageHandle Handle to the Image (NULL if Internal).
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunIf (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SHELL_STATUS ShellStatus;
BOOLEAN CaseInsensitive;
BOOLEAN ForceString;
UINTN CurrentParameter;
UINTN EndParameter;
BOOLEAN CurrentValue;
END_TAG_TYPE Ending;
END_TAG_TYPE PreviousEnding;
SCRIPT_FILE *CurrentScriptFile;
Status = CommandInit ();
ASSERT_EFI_ERROR (Status);
if (!gEfiShellProtocol->BatchIsActive ()) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"if");
return (SHELL_UNSUPPORTED);
}
if (gEfiShellParametersProtocol->Argc < 3) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"if");
return (SHELL_INVALID_PARAMETER);
}
//
// Make sure that an End exists.
//
CurrentScriptFile = ShellCommandGetCurrentScriptFile ();
if (!MoveToTag (GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"EndIf",
L"If",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
return (SHELL_DEVICE_ERROR);
}
//
// initialize the shell lib (we must be in non-auto-init...)
//
Status = ShellInitialize ();
ASSERT_EFI_ERROR (Status);
CurrentParameter = 1;
EndParameter = 0;
if ((gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[1],
L"/i"
) == 0) ||
(gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[2],
L"/i"
) == 0) ||
((gEfiShellParametersProtocol->Argc > 3) && (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[3],
L"/i"
) == 0)))
{
CaseInsensitive = TRUE;
CurrentParameter++;
} else {
CaseInsensitive = FALSE;
}
if ((gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[1],
L"/s"
) == 0) ||
(gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[2],
L"/s"
) == 0) ||
((gEfiShellParametersProtocol->Argc > 3) && (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[3],
L"/s"
) == 0)))
{
ForceString = TRUE;
CurrentParameter++;
} else {
ForceString = FALSE;
}
for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = EndTagMax
; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS
; CurrentParameter++)
{
if (gUnicodeCollation->StriColl (
gUnicodeCollation,
gEfiShellParametersProtocol->Argv[CurrentParameter],
L"then"
) == 0)
{
//
// we are at the then
//
if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle, L"if");
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
Status = PerformResultOperation (CurrentValue);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
ShellStatus = SHELL_INVALID_PARAMETER;
}
}
} else {
PreviousEnding = Ending;
//
// build up the next statement for analysis
//
if (!BuildNextStatement (CurrentParameter, &EndParameter, &Ending)) {
CurrentScriptFile = ShellCommandGetCurrentScriptFile ();
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"Then",
L"If",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
//
// Analyze the statement
//
Status = ProcessStatement (&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString);
if (EFI_ERROR (Status)) {
// ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
//
// Optomize to get out of the loop early...
//
if (((Ending == EndTagOr) && CurrentValue) || ((Ending == EndTagAnd) && !CurrentValue)) {
Status = PerformResultOperation (CurrentValue);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
ShellStatus = SHELL_INVALID_PARAMETER;
}
break;
}
}
}
if (ShellStatus == SHELL_SUCCESS) {
CurrentParameter = EndParameter;
//
// Skip over the or or and parameter.
//
if ((Ending == EndTagOr) || (Ending == EndTagAnd)) {
CurrentParameter++;
}
}
}
}
return (ShellStatus);
}
/**
Function for 'else' command.
@param[in] ImageHandle Handle to the Image (NULL if Internal).
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunElse (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SCRIPT_FILE *CurrentScriptFile;
Status = CommandInit ();
ASSERT_EFI_ERROR (Status);
if (gEfiShellParametersProtocol->Argc > 1) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
return (SHELL_INVALID_PARAMETER);
}
if (!gEfiShellProtocol->BatchIsActive ()) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else");
return (SHELL_UNSUPPORTED);
}
CurrentScriptFile = ShellCommandGetCurrentScriptFile ();
if (!MoveToTag (GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"If",
L"Else",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
return (SHELL_DEVICE_ERROR);
}
if (!MoveToTag (GetPreviousNode, L"if", L"else", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"If",
L"Else",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
return (SHELL_DEVICE_ERROR);
}
if (!MoveToTag (GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, FALSE, FALSE, FALSE)) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"EndIf",
"Else",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
return (SHELL_DEVICE_ERROR);
}
return (SHELL_SUCCESS);
}
/**
Function for 'endif' command.
@param[in] ImageHandle Handle to the Image (NULL if Internal).
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunEndIf (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SCRIPT_FILE *CurrentScriptFile;
Status = CommandInit ();
ASSERT_EFI_ERROR (Status);
if (gEfiShellParametersProtocol->Argc > 1) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
return (SHELL_INVALID_PARAMETER);
}
if (!gEfiShellProtocol->BatchIsActive ()) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif");
return (SHELL_UNSUPPORTED);
}
CurrentScriptFile = ShellCommandGetCurrentScriptFile ();
if (!MoveToTag (GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
gShellLevel1HiiHandle,
L"If",
L"EndIf",
CurrentScriptFile != NULL
&& CurrentScriptFile->CurrentCommand != NULL
? CurrentScriptFile->CurrentCommand->Line : 0
);
return (SHELL_DEVICE_ERROR);
}
return (SHELL_SUCCESS);
}