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