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