Home | History | Annotate | Download | only in UefiShellLevel1CommandsLib
      1 /** @file
      2   Main file for If and else shell level 1 function.
      3 
      4   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UefiShellLevel1CommandsLib.h"
     17 #include <Library/PrintLib.h>
     18 
     19 typedef enum {
     20   EndTagOr,
     21   EndTagAnd,
     22   EndTagThen,
     23   EndTagMax
     24 } END_TAG_TYPE;
     25 
     26 typedef enum {
     27   OperatorGreaterThan,
     28   OperatorLessThan,
     29   OperatorEqual,
     30   OperatorNotEqual,
     31   OperatorGreatorOrEqual,
     32   OperatorLessOrEqual,
     33   OperatorUnisgnedGreaterThan,
     34   OperatorUnsignedLessThan,
     35   OperatorUnsignedGreaterOrEqual,
     36   OperatorUnsignedLessOrEqual,
     37   OperatorMax
     38 } BIN_OPERATOR_TYPE;
     39 
     40 /**
     41   Extract the next fragment, if there is one.
     42 
     43   @param[in, out] Statement    The current remaining statement.
     44   @param[in] Fragment          The current fragment.
     45   @param[out] Match            TRUE when there is another Fragment in Statement,
     46                                FALSE otherwise.
     47 
     48   @retval EFI_SUCCESS          The match operation is performed successfully.
     49   @retval EFI_OUT_OF_RESOURCES Out of resources.
     50 **/
     51 EFI_STATUS
     52 IsNextFragment (
     53   IN OUT CONST CHAR16     **Statement,
     54   IN CONST CHAR16         *Fragment,
     55   OUT BOOLEAN             *Match
     56   )
     57 {
     58   CHAR16                  *Tester;
     59 
     60   Tester = NULL;
     61 
     62   Tester = StrnCatGrow(&Tester, NULL, *Statement, StrLen(Fragment));
     63   if (Tester == NULL) {
     64     return EFI_OUT_OF_RESOURCES;
     65   }
     66   Tester[StrLen(Fragment)] = CHAR_NULL;
     67   if (gUnicodeCollation->StriColl(
     68         gUnicodeCollation,
     69         (CHAR16*)Fragment,
     70         Tester) == 0) {
     71     //
     72     // increment the string pointer to the end of what we found and then chop off spaces...
     73     //
     74     *Statement+=StrLen(Fragment);
     75     while (*Statement[0] == L' ') {
     76       (*Statement)++;
     77     }
     78     *Match = TRUE;
     79   } else {
     80     *Match = FALSE;
     81   }
     82   FreePool(Tester);
     83   return EFI_SUCCESS;
     84 }
     85 
     86 /**
     87   Determine if String represents a valid profile.
     88 
     89   @param[in] String     The pointer to the string to test.
     90 
     91   @retval TRUE    String is a valid profile.
     92   @retval FALSE   String is not a valid profile.
     93 **/
     94 BOOLEAN
     95 IsValidProfile (
     96   IN CONST CHAR16 *String
     97   )
     98 {
     99   CONST CHAR16  *ProfilesString;
    100   CONST CHAR16  *TempLocation;
    101 
    102   ProfilesString = ShellGetEnvironmentVariable(L"profiles");
    103   ASSERT(ProfilesString != NULL);
    104   TempLocation = StrStr(ProfilesString, String);
    105   if ((TempLocation != NULL) && (*(TempLocation-1) == L';') && (*(TempLocation+StrLen(String)) == L';')) {
    106     return (TRUE);
    107   }
    108   return (FALSE);
    109 }
    110 
    111 /**
    112   Do a comparison between 2 things.
    113 
    114   @param[in] Compare1           The first item to compare.
    115   @param[in] Compare2           The second item to compare.
    116   @param[in] BinOp              The type of comparison to perform.
    117   @param[in] CaseInsensitive    TRUE to do non-case comparison, FALSE otherwise.
    118   @param[in] ForceStringCompare TRUE to force string comparison, FALSE otherwise.
    119 
    120   @return     The result of the comparison.
    121 **/
    122 BOOLEAN
    123 TestOperation (
    124   IN CONST CHAR16             *Compare1,
    125   IN CONST CHAR16             *Compare2,
    126   IN CONST BIN_OPERATOR_TYPE  BinOp,
    127   IN CONST BOOLEAN            CaseInsensitive,
    128   IN CONST BOOLEAN            ForceStringCompare
    129   )
    130 {
    131   INTN Cmp1;
    132   INTN Cmp2;
    133 
    134   //
    135   // "Compare1 BinOp Compare2"
    136   //
    137   switch (BinOp) {
    138   case OperatorUnisgnedGreaterThan:
    139   case OperatorGreaterThan:
    140     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    141       //
    142       // string compare
    143       //
    144       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) > 0) || (StringCompare(&Compare1, &Compare2) > 0)) {
    145         return (TRUE);
    146       }
    147     } else {
    148       //
    149       // numeric compare
    150       //
    151       if (Compare1[0] == L'-') {
    152         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    153       } else {
    154         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    155       }
    156       if (Compare2[0] == L'-') {
    157         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    158       } else {
    159         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    160       }
    161       if (BinOp == OperatorGreaterThan) {
    162         if (Cmp1 > Cmp2) {
    163           return (TRUE);
    164         }
    165       } else {
    166         if ((UINTN)Cmp1 > (UINTN)Cmp2) {
    167           return (TRUE);
    168         }
    169       }
    170     }
    171     return (FALSE);
    172   case OperatorUnsignedLessThan:
    173   case OperatorLessThan:
    174     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    175       //
    176       // string compare
    177       //
    178       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) < 0) || (StringCompare(&Compare1, &Compare2) < 0)) {
    179         return (TRUE);
    180       }
    181     } else {
    182       //
    183       // numeric compare
    184       //
    185       if (Compare1[0] == L'-') {
    186         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    187       } else {
    188         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    189       }
    190       if (Compare2[0] == L'-') {
    191         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    192       } else {
    193         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    194       }
    195       if (BinOp == OperatorLessThan) {
    196         if (Cmp1 < Cmp2) {
    197           return (TRUE);
    198         }
    199       } else {
    200         if ((UINTN)Cmp1 < (UINTN)Cmp2) {
    201           return (TRUE);
    202         }
    203       }
    204 
    205     }
    206     return (FALSE);
    207   case OperatorEqual:
    208     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    209       //
    210       // string compare
    211       //
    212       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) == 0) || (StringCompare(&Compare1, &Compare2) == 0)) {
    213         return (TRUE);
    214       }
    215     } else {
    216       //
    217       // numeric compare
    218       //
    219       if (Compare1[0] == L'-') {
    220         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    221       } else {
    222         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    223       }
    224       if (Compare2[0] == L'-') {
    225         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    226       } else {
    227         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    228       }
    229       if (Cmp1 == Cmp2) {
    230         return (TRUE);
    231       }
    232     }
    233     return (FALSE);
    234   case OperatorNotEqual:
    235     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    236       //
    237       // string compare
    238       //
    239       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) != 0) || (StringCompare(&Compare1, &Compare2) != 0)) {
    240         return (TRUE);
    241       }
    242     } else {
    243       //
    244       // numeric compare
    245       //
    246       if (Compare1[0] == L'-') {
    247         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    248       } else {
    249         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    250       }
    251       if (Compare2[0] == L'-') {
    252         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    253       } else {
    254         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    255       }
    256       if (Cmp1 != Cmp2) {
    257         return (TRUE);
    258       }
    259     }
    260     return (FALSE);
    261   case OperatorUnsignedGreaterOrEqual:
    262   case OperatorGreatorOrEqual:
    263     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    264       //
    265       // string compare
    266       //
    267       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) >= 0) || (StringCompare(&Compare1, &Compare2) >= 0)) {
    268         return (TRUE);
    269       }
    270     } else {
    271       //
    272       // numeric compare
    273       //
    274       if (Compare1[0] == L'-') {
    275         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    276       } else {
    277         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    278       }
    279       if (Compare2[0] == L'-') {
    280         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    281       } else {
    282         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    283       }
    284       if (BinOp == OperatorGreatorOrEqual) {
    285         if (Cmp1 >= Cmp2) {
    286           return (TRUE);
    287         }
    288       } else {
    289         if ((UINTN)Cmp1 >= (UINTN)Cmp2) {
    290           return (TRUE);
    291         }
    292       }
    293     }
    294     return (FALSE);
    295   case OperatorLessOrEqual:
    296   case OperatorUnsignedLessOrEqual:
    297     if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) {
    298       //
    299       // string compare
    300       //
    301       if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) <= 0) || (StringCompare(&Compare1, &Compare2) <= 0)) {
    302         return (TRUE);
    303       }
    304     } else {
    305       //
    306       // numeric compare
    307       //
    308       if (Compare1[0] == L'-') {
    309         Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1);
    310       } else {
    311         Cmp1 = (INTN)ShellStrToUintn(Compare1);
    312       }
    313       if (Compare2[0] == L'-') {
    314         Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1);
    315       } else {
    316         Cmp2 = (INTN)ShellStrToUintn(Compare2);
    317       }
    318       if (BinOp == OperatorLessOrEqual) {
    319         if (Cmp1 <= Cmp2) {
    320           return (TRUE);
    321         }
    322       } else {
    323         if ((UINTN)Cmp1 <= (UINTN)Cmp2) {
    324           return (TRUE);
    325         }
    326       }
    327     }
    328     return (FALSE);
    329   default:
    330     ASSERT(FALSE);
    331     return (FALSE);
    332   }
    333 }
    334 
    335 /**
    336   Process an if statement and determine if its is valid or not.
    337 
    338   @param[in, out] PassingState     Opon entry, the current state.  Upon exit,
    339                                    the new state.
    340   @param[in] StartParameterNumber  The number of the first parameter of
    341                                    this statement.
    342   @param[in] EndParameterNumber    The number of the final parameter of
    343                                    this statement.
    344   @param[in] OperatorToUse         The type of termination operator.
    345   @param[in] CaseInsensitive       TRUE for case insensitive, FALSE otherwise.
    346   @param[in] ForceStringCompare    TRUE for all string based, FALSE otherwise.
    347 
    348   @retval EFI_INVALID_PARAMETER   A parameter was invalid.
    349   @retval EFI_SUCCESS             The operation was successful.
    350 **/
    351 EFI_STATUS
    352 ProcessStatement (
    353   IN OUT BOOLEAN          *PassingState,
    354   IN UINTN                StartParameterNumber,
    355   IN UINTN                EndParameterNumber,
    356   IN CONST END_TAG_TYPE   OperatorToUse,
    357   IN CONST BOOLEAN        CaseInsensitive,
    358   IN CONST BOOLEAN        ForceStringCompare
    359   )
    360 {
    361   EFI_STATUS              Status;
    362   BOOLEAN                 OperationResult;
    363   BOOLEAN                 NotPresent;
    364   CHAR16                  *StatementWalker;
    365   BIN_OPERATOR_TYPE       BinOp;
    366   CHAR16                  *Compare1;
    367   CHAR16                  *Compare2;
    368   CHAR16                  HexString[20];
    369   CHAR16                  *TempSpot;
    370   BOOLEAN                 Match;
    371 
    372   ASSERT((END_TAG_TYPE)OperatorToUse != EndTagThen);
    373 
    374   Status          = EFI_SUCCESS;
    375   BinOp           = OperatorMax;
    376   OperationResult = FALSE;
    377   Match           = FALSE;
    378   StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
    379   if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"not", &Match)) && Match) {
    380     NotPresent      = TRUE;
    381     StatementWalker = gEfiShellParametersProtocol->Argv[++StartParameterNumber];
    382   } else {
    383     NotPresent = FALSE;
    384   }
    385 
    386   //
    387   // now check for 'boolfunc' operators
    388   //
    389   if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"isint", &Match)) && Match) {
    390     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match
    391         && StatementWalker[StrLen(StatementWalker)-1] == L')') {
    392       StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
    393       OperationResult = ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE);
    394     } else {
    395       Status = EFI_INVALID_PARAMETER;
    396       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"isint");
    397     }
    398   } else if ((!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exists", &Match)) && Match) ||
    399              (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exist", &Match)) && Match)) {
    400     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
    401         StatementWalker[StrLen(StatementWalker)-1] == L')') {
    402       StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
    403       //
    404       // is what remains a file in CWD???
    405       //
    406       OperationResult = (BOOLEAN)(ShellFileExists(StatementWalker)==EFI_SUCCESS);
    407     } else if (StatementWalker[0] == CHAR_NULL && StartParameterNumber+1 == EndParameterNumber) {
    408       OperationResult = (BOOLEAN)(ShellFileExists(gEfiShellParametersProtocol->Argv[++StartParameterNumber])==EFI_SUCCESS);
    409     } else {
    410       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"exist(s)");
    411       Status = EFI_INVALID_PARAMETER;
    412     }
    413   } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"available", &Match)) && Match) {
    414     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
    415         StatementWalker[StrLen(StatementWalker)-1] == L')') {
    416       StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
    417       //
    418       // is what remains a file in the CWD or path???
    419       //
    420       OperationResult = (BOOLEAN)(ShellIsFileInPath(StatementWalker)==EFI_SUCCESS);
    421     } else {
    422       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"available");
    423       Status = EFI_INVALID_PARAMETER;
    424     }
    425   } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"profile", &Match)) && Match) {
    426     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match &&
    427         StatementWalker[StrLen(StatementWalker)-1] == L')') {
    428       //
    429       // Chop off that ')'
    430       //
    431       StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL;
    432       OperationResult = IsValidProfile(StatementWalker);
    433     } else {
    434       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"profile");
    435       Status = EFI_INVALID_PARAMETER;
    436     }
    437   } else if (StartParameterNumber+1 >= EndParameterNumber) {
    438       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber]);
    439       Status = EFI_INVALID_PARAMETER;
    440   } else {
    441     //
    442     // must be 'item binop item' style
    443     //
    444     Compare1 = NULL;
    445     Compare2 = NULL;
    446     BinOp    = OperatorMax;
    447 
    448     //
    449     // get the first item
    450     //
    451     StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber];
    452     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) {
    453       TempSpot = StrStr(StatementWalker, L")");
    454       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    455         *TempSpot = CHAR_NULL;
    456         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    457           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT);
    458           ASSERT(Compare1 == NULL);
    459           Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
    460           StatementWalker += StrLen(StatementWalker) + 1;
    461         } else {
    462           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
    463           Status = EFI_INVALID_PARAMETER;
    464         }
    465       } else {
    466         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
    467         Status = EFI_INVALID_PARAMETER;
    468       }
    469     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) {
    470       TempSpot = StrStr(StatementWalker, L")");
    471       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    472         *TempSpot = CHAR_NULL;
    473         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    474           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2));
    475           ASSERT(Compare1 == NULL);
    476           Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
    477           StatementWalker += StrLen(StatementWalker) + 1;
    478         } else {
    479           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
    480           Status = EFI_INVALID_PARAMETER;
    481         }
    482       } else {
    483         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
    484         Status = EFI_INVALID_PARAMETER;
    485       }
    486     } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) {
    487       TempSpot = StrStr(StatementWalker, L")");
    488       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    489         TempSpot = CHAR_NULL;
    490         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    491           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1));
    492           ASSERT(Compare1 == NULL);
    493           Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0);
    494           StatementWalker += StrLen(StatementWalker) + 1;
    495         } else {
    496           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
    497           Status = EFI_INVALID_PARAMETER;
    498         }
    499       } else {
    500         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
    501         Status = EFI_INVALID_PARAMETER;
    502       }
    503     } else {
    504       ASSERT(Compare1 == NULL);
    505       if (EndParameterNumber - StartParameterNumber > 2) {
    506           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber+2]);
    507           Status = EFI_INVALID_PARAMETER;
    508       } else {
    509         //
    510         // must be a raw string
    511         //
    512         Compare1 = StrnCatGrow(&Compare1, NULL, StatementWalker, 0);
    513       }
    514     }
    515 
    516     //
    517     // get the operator
    518     //
    519     ASSERT(StartParameterNumber+1<EndParameterNumber);
    520     StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+1];
    521     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"gt", &Match)) && Match) {
    522       BinOp = OperatorGreaterThan;
    523     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"lt", &Match)) && Match) {
    524       BinOp = OperatorLessThan;
    525     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"eq", &Match)) && Match) {
    526       BinOp = OperatorEqual;
    527     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ne", &Match)) && Match) {
    528       BinOp = OperatorNotEqual;
    529     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ge", &Match)) && Match) {
    530       BinOp = OperatorGreatorOrEqual;
    531     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"le", &Match)) && Match) {
    532       BinOp = OperatorLessOrEqual;
    533     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"==", &Match)) && Match) {
    534       BinOp = OperatorEqual;
    535     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ugt", &Match)) && Match) {
    536       BinOp = OperatorUnisgnedGreaterThan;
    537     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ult", &Match)) && Match) {
    538       BinOp = OperatorUnsignedLessThan;
    539     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"uge", &Match)) && Match) {
    540       BinOp = OperatorUnsignedGreaterOrEqual;
    541     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ule", &Match)) && Match) {
    542       BinOp = OperatorUnsignedLessOrEqual;
    543     } else {
    544       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_INVALID_BINOP), gShellLevel1HiiHandle, StatementWalker);
    545       Status = EFI_INVALID_PARAMETER;
    546     }
    547 
    548     //
    549     // get the second item
    550     //
    551     ASSERT(StartParameterNumber+2<=EndParameterNumber);
    552     StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+2];
    553     if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror", &Match)) && Match) {
    554       TempSpot = StrStr(StatementWalker, L")");
    555       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    556         TempSpot = CHAR_NULL;
    557         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    558           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT);
    559           ASSERT(Compare2 == NULL);
    560           Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
    561           StatementWalker += StrLen(StatementWalker) + 1;
    562         } else {
    563           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
    564           Status = EFI_INVALID_PARAMETER;
    565         }
    566       } else {
    567         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror");
    568         Status = EFI_INVALID_PARAMETER;
    569       }
    570     //
    571     // can this be collapsed into the above?
    572     //
    573     } else if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror", &Match)) && Match) {
    574       TempSpot = StrStr(StatementWalker, L")");
    575       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    576         TempSpot = CHAR_NULL;
    577         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    578           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2));
    579           ASSERT(Compare2 == NULL);
    580           Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
    581           StatementWalker += StrLen(StatementWalker) + 1;
    582         } else {
    583           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
    584           Status = EFI_INVALID_PARAMETER;
    585         }
    586       } else {
    587         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror");
    588         Status = EFI_INVALID_PARAMETER;
    589       }
    590     } else if (!EFI_ERROR (IsNextFragment ((CONST CHAR16**)(&StatementWalker), L"oemerror", &Match)) && Match) {
    591       TempSpot = StrStr(StatementWalker, L")");
    592       if (!EFI_ERROR (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(", &Match)) && Match && TempSpot != NULL) {
    593         TempSpot = CHAR_NULL;
    594         if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) {
    595           UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1));
    596           ASSERT(Compare2 == NULL);
    597           Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0);
    598           StatementWalker += StrLen(StatementWalker) + 1;
    599         } else {
    600           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
    601           Status = EFI_INVALID_PARAMETER;
    602         }
    603       } else {
    604         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror");
    605         Status = EFI_INVALID_PARAMETER;
    606       }
    607     } else {
    608       //
    609       // must be a raw string
    610       //
    611       ASSERT(Compare2 == NULL);
    612       Compare2 = StrnCatGrow(&Compare2, NULL, StatementWalker, 0);
    613     }
    614 
    615     if (Compare1 != NULL && Compare2 != NULL && BinOp != OperatorMax) {
    616       OperationResult = TestOperation(Compare1, Compare2, BinOp, CaseInsensitive, ForceStringCompare);
    617     }
    618 
    619     SHELL_FREE_NON_NULL(Compare1);
    620     SHELL_FREE_NON_NULL(Compare2);
    621   }
    622 
    623   //
    624   // done processing do result...
    625   //
    626 
    627   if (!EFI_ERROR(Status)) {
    628     if (NotPresent) {
    629       OperationResult = (BOOLEAN)(!OperationResult);
    630     }
    631     switch(OperatorToUse) {
    632       case EndTagOr:
    633         *PassingState = (BOOLEAN)(*PassingState || OperationResult);
    634         break;
    635       case EndTagAnd:
    636         *PassingState = (BOOLEAN)(*PassingState && OperationResult);
    637         break;
    638       case EndTagMax:
    639         *PassingState = (BOOLEAN)(OperationResult);
    640         break;
    641       default:
    642         ASSERT(FALSE);
    643     }
    644   }
    645   return (Status);
    646 }
    647 
    648 /**
    649   Break up the next part of the if statement (until the next 'and', 'or', or 'then').
    650 
    651   @param[in] ParameterNumber      The current parameter number.
    652   @param[out] EndParameter        Upon successful return, will point to the
    653                                   parameter to start the next iteration with.
    654   @param[out] EndTag              Upon successful return, will point to the
    655                                   type that was found at the end of this statement.
    656 
    657   @retval TRUE    A valid statement was found.
    658   @retval FALSE   A valid statement was not found.
    659 **/
    660 BOOLEAN
    661 BuildNextStatement (
    662   IN UINTN          ParameterNumber,
    663   OUT UINTN         *EndParameter,
    664   OUT END_TAG_TYPE  *EndTag
    665   )
    666 {
    667   *EndTag = EndTagMax;
    668 
    669   for(
    670     ; ParameterNumber < gEfiShellParametersProtocol->Argc
    671     ; ParameterNumber++
    672    ) {
    673     if (gUnicodeCollation->StriColl(
    674           gUnicodeCollation,
    675           gEfiShellParametersProtocol->Argv[ParameterNumber],
    676           L"or") == 0) {
    677       *EndParameter = ParameterNumber - 1;
    678       *EndTag = EndTagOr;
    679       break;
    680     } else if (gUnicodeCollation->StriColl(
    681           gUnicodeCollation,
    682           gEfiShellParametersProtocol->Argv[ParameterNumber],
    683           L"and") == 0) {
    684       *EndParameter = ParameterNumber - 1;
    685       *EndTag = EndTagAnd;
    686       break;
    687     } else if (gUnicodeCollation->StriColl(
    688           gUnicodeCollation,
    689           gEfiShellParametersProtocol->Argv[ParameterNumber],
    690           L"then") == 0) {
    691       *EndParameter = ParameterNumber - 1;
    692       *EndTag = EndTagThen;
    693       break;
    694     }
    695   }
    696   if (*EndTag == EndTagMax) {
    697     return (FALSE);
    698   }
    699   return (TRUE);
    700 }
    701 
    702 /**
    703   Move the script file pointer to a different place in the script file.
    704   This one is special since it handles the if/else/endif syntax.
    705 
    706   @param[in] ScriptFile     The script file from GetCurrnetScriptFile().
    707 
    708   @retval TRUE     The move target was found and the move was successful.
    709   @retval FALSE    Something went wrong.
    710 **/
    711 BOOLEAN
    712 MoveToTagSpecial (
    713   IN SCRIPT_FILE                *ScriptFile
    714   )
    715 {
    716   SCRIPT_COMMAND_LIST *CommandNode;
    717   BOOLEAN             Found;
    718   UINTN               TargetCount;
    719   CHAR16              *CommandName;
    720   CHAR16              *CommandWalker;
    721   CHAR16              *TempLocation;
    722 
    723   TargetCount         = 1;
    724   Found               = FALSE;
    725 
    726   if (ScriptFile == NULL) {
    727     return FALSE;
    728   }
    729 
    730   for (CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE
    731     ;  !IsNull(&ScriptFile->CommandList, &CommandNode->Link) && !Found
    732     ;  CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link)
    733    ){
    734 
    735     //
    736     // get just the first part of the command line...
    737     //
    738     CommandName   = NULL;
    739     CommandName   = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0);
    740     if (CommandName == NULL) {
    741       continue;
    742     }
    743     CommandWalker = CommandName;
    744 
    745     //
    746     // Skip leading spaces and tabs.
    747     //
    748     while ((CommandWalker[0] == L' ') || (CommandWalker[0] == L'\t')) {
    749       CommandWalker++;
    750     }
    751     TempLocation  = StrStr(CommandWalker, L" ");
    752 
    753     if (TempLocation != NULL) {
    754       *TempLocation = CHAR_NULL;
    755     }
    756 
    757     //
    758     // did we find a nested item ?
    759     //
    760     if (gUnicodeCollation->StriColl(
    761         gUnicodeCollation,
    762         (CHAR16*)CommandWalker,
    763         L"If") == 0) {
    764       TargetCount++;
    765     } else if (TargetCount == 1 && gUnicodeCollation->StriColl(
    766         gUnicodeCollation,
    767         (CHAR16*)CommandWalker,
    768         (CHAR16*)L"else") == 0) {
    769       //
    770       // else can only decrement the last part... not an nested if
    771       // hence the TargetCount compare added
    772       //
    773       TargetCount--;
    774     } else if (gUnicodeCollation->StriColl(
    775         gUnicodeCollation,
    776         (CHAR16*)CommandWalker,
    777         (CHAR16*)L"endif") == 0) {
    778       TargetCount--;
    779     }
    780     if (TargetCount == 0) {
    781       ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link);
    782       Found = TRUE;
    783     }
    784 
    785     //
    786     // Free the memory for this loop...
    787     //
    788     SHELL_FREE_NON_NULL(CommandName);
    789   }
    790   return (Found);
    791 }
    792 
    793 /**
    794   Deal with the result of the if operation.
    795 
    796   @param[in] Result     The result of the if.
    797 
    798   @retval EFI_SUCCESS       The operation was successful.
    799   @retval EFI_NOT_FOUND     The ending tag could not be found.
    800 **/
    801 EFI_STATUS
    802 PerformResultOperation (
    803   IN CONST BOOLEAN Result
    804   )
    805 {
    806   if (Result || MoveToTagSpecial(ShellCommandGetCurrentScriptFile())) {
    807     return (EFI_SUCCESS);
    808   }
    809   return (EFI_NOT_FOUND);
    810 }
    811 
    812 /**
    813   Function for 'if' command.
    814 
    815   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    816   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    817 **/
    818 SHELL_STATUS
    819 EFIAPI
    820 ShellCommandRunIf (
    821   IN EFI_HANDLE        ImageHandle,
    822   IN EFI_SYSTEM_TABLE  *SystemTable
    823   )
    824 {
    825   EFI_STATUS          Status;
    826   SHELL_STATUS        ShellStatus;
    827   BOOLEAN             CaseInsensitive;
    828   BOOLEAN             ForceString;
    829   UINTN               CurrentParameter;
    830   UINTN               EndParameter;
    831   BOOLEAN             CurrentValue;
    832   END_TAG_TYPE        Ending;
    833   END_TAG_TYPE        PreviousEnding;
    834   SCRIPT_FILE         *CurrentScriptFile;
    835 
    836   Status = CommandInit();
    837   ASSERT_EFI_ERROR(Status);
    838 
    839   if (!gEfiShellProtocol->BatchIsActive()) {
    840     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"if");
    841     return (SHELL_UNSUPPORTED);
    842   }
    843 
    844   if (gEfiShellParametersProtocol->Argc < 3) {
    845     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle, L"if");
    846     return (SHELL_INVALID_PARAMETER);
    847   }
    848 
    849   //
    850   // Make sure that an End exists.
    851   //
    852   CurrentScriptFile = ShellCommandGetCurrentScriptFile();
    853   if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {
    854     ShellPrintHiiEx(
    855       -1,
    856       -1,
    857       NULL,
    858       STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
    859       gShellLevel1HiiHandle,
    860       L"EndIf",
    861       L"If",
    862       CurrentScriptFile!=NULL
    863         && CurrentScriptFile->CurrentCommand!=NULL
    864         ? CurrentScriptFile->CurrentCommand->Line:0);
    865     return (SHELL_DEVICE_ERROR);
    866   }
    867 
    868   //
    869   // initialize the shell lib (we must be in non-auto-init...)
    870   //
    871   Status = ShellInitialize();
    872   ASSERT_EFI_ERROR(Status);
    873 
    874   CurrentParameter    = 1;
    875   EndParameter        = 0;
    876 
    877   if (gUnicodeCollation->StriColl(
    878         gUnicodeCollation,
    879         gEfiShellParametersProtocol->Argv[1],
    880         L"/i") == 0 ||
    881       gUnicodeCollation->StriColl(
    882         gUnicodeCollation,
    883         gEfiShellParametersProtocol->Argv[2],
    884         L"/i") == 0 ||
    885       (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
    886         gUnicodeCollation,
    887         gEfiShellParametersProtocol->Argv[3],
    888         L"/i") == 0)) {
    889     CaseInsensitive = TRUE;
    890     CurrentParameter++;
    891   } else {
    892     CaseInsensitive = FALSE;
    893   }
    894   if (gUnicodeCollation->StriColl(
    895         gUnicodeCollation,
    896         gEfiShellParametersProtocol->Argv[1],
    897         L"/s") == 0 ||
    898       gUnicodeCollation->StriColl(
    899         gUnicodeCollation,
    900         gEfiShellParametersProtocol->Argv[2],
    901         L"/s") == 0 ||
    902       (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
    903         gUnicodeCollation,
    904         gEfiShellParametersProtocol->Argv[3],
    905         L"/s") == 0)) {
    906     ForceString     = TRUE;
    907     CurrentParameter++;
    908   } else {
    909     ForceString     = FALSE;
    910   }
    911 
    912   for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = EndTagMax
    913       ; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS
    914       ; CurrentParameter++) {
    915     if (gUnicodeCollation->StriColl(
    916           gUnicodeCollation,
    917           gEfiShellParametersProtocol->Argv[CurrentParameter],
    918           L"then") == 0) {
    919       //
    920       // we are at the then
    921       //
    922       if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) {
    923         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle, L"if");
    924         ShellStatus = SHELL_INVALID_PARAMETER;
    925       } else {
    926         Status = PerformResultOperation(CurrentValue);
    927         if (EFI_ERROR(Status)) {
    928           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
    929           ShellStatus = SHELL_INVALID_PARAMETER;
    930         }
    931       }
    932     } else {
    933       PreviousEnding = Ending;
    934       //
    935       // build up the next statement for analysis
    936       //
    937       if (!BuildNextStatement(CurrentParameter, &EndParameter, &Ending)) {
    938         CurrentScriptFile = ShellCommandGetCurrentScriptFile();
    939         ShellPrintHiiEx(
    940           -1,
    941           -1,
    942           NULL,
    943           STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
    944           gShellLevel1HiiHandle,
    945           L"Then",
    946           L"If",
    947           CurrentScriptFile!=NULL
    948             && CurrentScriptFile->CurrentCommand!=NULL
    949             ? CurrentScriptFile->CurrentCommand->Line:0);
    950         ShellStatus = SHELL_INVALID_PARAMETER;
    951       } else {
    952         //
    953         // Analyze the statement
    954         //
    955         Status = ProcessStatement(&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString);
    956         if (EFI_ERROR(Status)) {
    957 //          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
    958           ShellStatus = SHELL_INVALID_PARAMETER;
    959         } else {
    960           //
    961           // Optomize to get out of the loop early...
    962           //
    963           if ((Ending == EndTagOr && CurrentValue) || (Ending == EndTagAnd && !CurrentValue)) {
    964             Status = PerformResultOperation(CurrentValue);
    965             if (EFI_ERROR(Status)) {
    966               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, L"if", gEfiShellParametersProtocol->Argv[CurrentParameter]);
    967               ShellStatus = SHELL_INVALID_PARAMETER;
    968             }
    969             break;
    970           }
    971         }
    972       }
    973       if (ShellStatus == SHELL_SUCCESS){
    974         CurrentParameter = EndParameter;
    975         //
    976         // Skip over the or or and parameter.
    977         //
    978         if (Ending == EndTagOr || Ending == EndTagAnd) {
    979           CurrentParameter++;
    980         }
    981       }
    982     }
    983   }
    984   return (ShellStatus);
    985 }
    986 
    987 /**
    988   Function for 'else' command.
    989 
    990   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    991   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    992 **/
    993 SHELL_STATUS
    994 EFIAPI
    995 ShellCommandRunElse (
    996   IN EFI_HANDLE        ImageHandle,
    997   IN EFI_SYSTEM_TABLE  *SystemTable
    998   )
    999 {
   1000   EFI_STATUS  Status;
   1001   SCRIPT_FILE *CurrentScriptFile;
   1002 
   1003   Status = CommandInit ();
   1004   ASSERT_EFI_ERROR (Status);
   1005 
   1006   if (gEfiShellParametersProtocol->Argc > 1) {
   1007     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
   1008     return (SHELL_INVALID_PARAMETER);
   1009   }
   1010 
   1011   if (!gEfiShellProtocol->BatchIsActive()) {
   1012     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else");
   1013     return (SHELL_UNSUPPORTED);
   1014   }
   1015 
   1016   CurrentScriptFile = ShellCommandGetCurrentScriptFile();
   1017 
   1018   if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
   1019     ShellPrintHiiEx(
   1020       -1,
   1021       -1,
   1022       NULL,
   1023       STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
   1024       gShellLevel1HiiHandle,
   1025       L"If",
   1026       L"Else",
   1027       CurrentScriptFile!=NULL
   1028         && CurrentScriptFile->CurrentCommand!=NULL
   1029         ? CurrentScriptFile->CurrentCommand->Line:0);
   1030     return (SHELL_DEVICE_ERROR);
   1031   }
   1032   if (!MoveToTag(GetPreviousNode, L"if", L"else", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
   1033     ShellPrintHiiEx(
   1034       -1,
   1035       -1,
   1036       NULL,
   1037       STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
   1038       gShellLevel1HiiHandle,
   1039       L"If",
   1040       L"Else",
   1041       CurrentScriptFile!=NULL
   1042         && CurrentScriptFile->CurrentCommand!=NULL
   1043         ? CurrentScriptFile->CurrentCommand->Line:0);
   1044     return (SHELL_DEVICE_ERROR);
   1045   }
   1046 
   1047   if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, FALSE, FALSE, FALSE)) {
   1048     ShellPrintHiiEx(
   1049       -1,
   1050       -1,
   1051       NULL,
   1052       STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
   1053       gShellLevel1HiiHandle,
   1054       L"EndIf",
   1055       "Else",
   1056       CurrentScriptFile!=NULL
   1057         && CurrentScriptFile->CurrentCommand!=NULL
   1058         ? CurrentScriptFile->CurrentCommand->Line:0);
   1059     return (SHELL_DEVICE_ERROR);
   1060   }
   1061 
   1062   return (SHELL_SUCCESS);
   1063 }
   1064 
   1065 /**
   1066   Function for 'endif' command.
   1067 
   1068   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
   1069   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
   1070 **/
   1071 SHELL_STATUS
   1072 EFIAPI
   1073 ShellCommandRunEndIf (
   1074   IN EFI_HANDLE        ImageHandle,
   1075   IN EFI_SYSTEM_TABLE  *SystemTable
   1076   )
   1077 {
   1078   EFI_STATUS  Status;
   1079   SCRIPT_FILE *CurrentScriptFile;
   1080 
   1081   Status = CommandInit ();
   1082   ASSERT_EFI_ERROR (Status);
   1083 
   1084   if (gEfiShellParametersProtocol->Argc > 1) {
   1085     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle, L"if");
   1086     return (SHELL_INVALID_PARAMETER);
   1087   }
   1088 
   1089   if (!gEfiShellProtocol->BatchIsActive()) {
   1090     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif");
   1091     return (SHELL_UNSUPPORTED);
   1092   }
   1093 
   1094   CurrentScriptFile = ShellCommandGetCurrentScriptFile();
   1095   if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
   1096     ShellPrintHiiEx(
   1097       -1,
   1098       -1,
   1099       NULL,
   1100       STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
   1101       gShellLevel1HiiHandle,
   1102       L"If",
   1103       L"EndIf",
   1104       CurrentScriptFile!=NULL
   1105         && CurrentScriptFile->CurrentCommand!=NULL
   1106         ? CurrentScriptFile->CurrentCommand->Line:0);
   1107     return (SHELL_DEVICE_ERROR);
   1108   }
   1109 
   1110   return (SHELL_SUCCESS);
   1111 }
   1112