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
IsNextFragment(IN OUT CONST CHAR16 ** Statement,IN CONST CHAR16 * Fragment,OUT BOOLEAN * Match)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
IsValidProfile(IN CONST CHAR16 * String)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
TestOperation(IN CONST CHAR16 * Compare1,IN CONST CHAR16 * Compare2,IN CONST BIN_OPERATOR_TYPE BinOp,IN CONST BOOLEAN CaseInsensitive,IN CONST BOOLEAN ForceStringCompare)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
ProcessStatement(IN OUT BOOLEAN * PassingState,IN UINTN StartParameterNumber,IN UINTN EndParameterNumber,IN CONST END_TAG_TYPE OperatorToUse,IN CONST BOOLEAN CaseInsensitive,IN CONST BOOLEAN ForceStringCompare)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
BuildNextStatement(IN UINTN ParameterNumber,OUT UINTN * EndParameter,OUT END_TAG_TYPE * EndTag)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
MoveToTagSpecial(IN SCRIPT_FILE * ScriptFile)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
PerformResultOperation(IN CONST BOOLEAN Result)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
ShellCommandRunIf(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
ShellCommandRunElse(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
ShellCommandRunEndIf(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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