blob: a1abb5feaa0e8fc5de245d14596345cf3fcce150 [file] [log] [blame]
/** @file
Main file for If and else shell level 1 function.
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiShellLevel1CommandsLib.h"
#include <Library/PrintLib.h>
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);
}