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