/** @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+1Argv[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); }