]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel1CommandsLib/If.c
d305306124e29b3bdd3df5db54ab011d924e8842
[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 CommandWalker = CommandName;
743 while (CommandWalker[0] == L' ') {
744 CommandWalker++;
745 }
746 TempLocation = StrStr(CommandWalker, L" ");
747
748 if (TempLocation != NULL) {
749 *TempLocation = CHAR_NULL;
750 }
751
752 //
753 // did we find a nested item ?
754 //
755 if (gUnicodeCollation->StriColl(
756 gUnicodeCollation,
757 (CHAR16*)CommandWalker,
758 L"If") == 0) {
759 TargetCount++;
760 } else if (TargetCount == 1 && gUnicodeCollation->StriColl(
761 gUnicodeCollation,
762 (CHAR16*)CommandWalker,
763 (CHAR16*)L"else") == 0) {
764 //
765 // else can only decrement the last part... not an nested if
766 // hence the TargetCount compare added
767 //
768 TargetCount--;
769 } else if (gUnicodeCollation->StriColl(
770 gUnicodeCollation,
771 (CHAR16*)CommandWalker,
772 (CHAR16*)L"endif") == 0) {
773 TargetCount--;
774 }
775 if (TargetCount == 0) {
776 ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link);
777 Found = TRUE;
778 }
779
780 //
781 // Free the memory for this loop...
782 //
783 SHELL_FREE_NON_NULL(CommandName);
784 }
785 return (Found);
786 }
787
788 /**
789 Deal with the result of the if operation.
790
791 @param[in] Result The result of the if.
792
793 @retval EFI_SUCCESS The operation was successful.
794 @retval EFI_NOT_FOUND The ending tag could not be found.
795 **/
796 EFI_STATUS
797 EFIAPI
798 PerformResultOperation (
799 IN CONST BOOLEAN Result
800 )
801 {
802 if (Result || MoveToTagSpecial(ShellCommandGetCurrentScriptFile())) {
803 return (EFI_SUCCESS);
804 }
805 return (EFI_NOT_FOUND);
806 }
807
808 /**
809 Function for 'if' command.
810
811 @param[in] ImageHandle Handle to the Image (NULL if Internal).
812 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
813 **/
814 SHELL_STATUS
815 EFIAPI
816 ShellCommandRunIf (
817 IN EFI_HANDLE ImageHandle,
818 IN EFI_SYSTEM_TABLE *SystemTable
819 )
820 {
821 EFI_STATUS Status;
822 SHELL_STATUS ShellStatus;
823 BOOLEAN CaseInsensitive;
824 BOOLEAN ForceString;
825 UINTN CurrentParameter;
826 UINTN EndParameter;
827 BOOLEAN CurrentValue;
828 END_TAG_TYPE Ending;
829 END_TAG_TYPE PreviousEnding;
830 SCRIPT_FILE *CurrentScriptFile;
831
832 Status = CommandInit();
833 ASSERT_EFI_ERROR(Status);
834
835 if (!gEfiShellProtocol->BatchIsActive()) {
836 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"If");
837 return (SHELL_UNSUPPORTED);
838 }
839
840 if (gEfiShellParametersProtocol->Argc < 3) {
841 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle);
842 return (SHELL_INVALID_PARAMETER);
843 }
844
845 //
846 // Make sure that an End exists.
847 //
848 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
849 if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) {
850 ShellPrintHiiEx(
851 -1,
852 -1,
853 NULL,
854 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
855 gShellLevel1HiiHandle,
856 L"EnfIf",
857 L"If",
858 CurrentScriptFile!=NULL
859 && CurrentScriptFile->CurrentCommand!=NULL
860 ? CurrentScriptFile->CurrentCommand->Line:0);
861 return (SHELL_DEVICE_ERROR);
862 }
863
864 //
865 // initialize the shell lib (we must be in non-auto-init...)
866 //
867 Status = ShellInitialize();
868 ASSERT_EFI_ERROR(Status);
869
870 CurrentParameter = 1;
871 EndParameter = 0;
872
873 if (gUnicodeCollation->StriColl(
874 gUnicodeCollation,
875 gEfiShellParametersProtocol->Argv[1],
876 L"/i") == 0 ||
877 gUnicodeCollation->StriColl(
878 gUnicodeCollation,
879 gEfiShellParametersProtocol->Argv[2],
880 L"/i") == 0 ||
881 (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
882 gUnicodeCollation,
883 gEfiShellParametersProtocol->Argv[3],
884 L"/i") == 0)) {
885 CaseInsensitive = TRUE;
886 CurrentParameter++;
887 } else {
888 CaseInsensitive = FALSE;
889 }
890 if (gUnicodeCollation->StriColl(
891 gUnicodeCollation,
892 gEfiShellParametersProtocol->Argv[1],
893 L"/s") == 0 ||
894 gUnicodeCollation->StriColl(
895 gUnicodeCollation,
896 gEfiShellParametersProtocol->Argv[2],
897 L"/s") == 0 ||
898 (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl(
899 gUnicodeCollation,
900 gEfiShellParametersProtocol->Argv[3],
901 L"/s") == 0)) {
902 ForceString = TRUE;
903 CurrentParameter++;
904 } else {
905 ForceString = FALSE;
906 }
907
908 for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = EndTagMax
909 ; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS
910 ; CurrentParameter++) {
911 if (gUnicodeCollation->StriColl(
912 gUnicodeCollation,
913 gEfiShellParametersProtocol->Argv[CurrentParameter],
914 L"then") == 0) {
915 //
916 // we are at the then
917 //
918 if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) {
919 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle);
920 ShellStatus = SHELL_INVALID_PARAMETER;
921 } else {
922 Status = PerformResultOperation(CurrentValue);
923 if (EFI_ERROR(Status)) {
924 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
925 ShellStatus = SHELL_INVALID_PARAMETER;
926 }
927 }
928 } else {
929 PreviousEnding = Ending;
930 //
931 // build up the next statement for analysis
932 //
933 if (!BuildNextStatement(CurrentParameter, &EndParameter, &Ending)) {
934 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
935 ShellPrintHiiEx(
936 -1,
937 -1,
938 NULL,
939 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
940 gShellLevel1HiiHandle,
941 L"Then",
942 L"If",
943 CurrentScriptFile!=NULL
944 && CurrentScriptFile->CurrentCommand!=NULL
945 ? CurrentScriptFile->CurrentCommand->Line:0);
946 ShellStatus = SHELL_INVALID_PARAMETER;
947 } else {
948 //
949 // Analyze the statement
950 //
951 Status = ProcessStatement(&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString);
952 if (EFI_ERROR(Status)) {
953 // ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
954 ShellStatus = SHELL_INVALID_PARAMETER;
955 } else {
956 //
957 // Optomize to get out of the loop early...
958 //
959 if ((Ending == EndTagOr && CurrentValue) || (Ending == EndTagAnd && !CurrentValue)) {
960 Status = PerformResultOperation(CurrentValue);
961 if (EFI_ERROR(Status)) {
962 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]);
963 ShellStatus = SHELL_INVALID_PARAMETER;
964 }
965 break;
966 }
967 }
968 }
969 if (ShellStatus == SHELL_SUCCESS){
970 CurrentParameter = EndParameter;
971 //
972 // Skip over the or or and parameter.
973 //
974 if (Ending == EndTagOr || Ending == EndTagAnd) {
975 CurrentParameter++;
976 }
977 }
978 }
979 }
980 return (ShellStatus);
981 }
982
983 /**
984 Function for 'else' command.
985
986 @param[in] ImageHandle Handle to the Image (NULL if Internal).
987 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
988 **/
989 SHELL_STATUS
990 EFIAPI
991 ShellCommandRunElse (
992 IN EFI_HANDLE ImageHandle,
993 IN EFI_SYSTEM_TABLE *SystemTable
994 )
995 {
996 SCRIPT_FILE *CurrentScriptFile;
997 ASSERT_EFI_ERROR(CommandInit());
998
999 if (gEfiShellParametersProtocol->Argc > 1) {
1000 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle);
1001 return (SHELL_INVALID_PARAMETER);
1002 }
1003
1004 if (!gEfiShellProtocol->BatchIsActive()) {
1005 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else");
1006 return (SHELL_UNSUPPORTED);
1007 }
1008
1009 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
1010
1011 if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1012 ShellPrintHiiEx(
1013 -1,
1014 -1,
1015 NULL,
1016 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1017 gShellLevel1HiiHandle,
1018 L"If",
1019 L"Else",
1020 CurrentScriptFile!=NULL
1021 && CurrentScriptFile->CurrentCommand!=NULL
1022 ? CurrentScriptFile->CurrentCommand->Line:0);
1023 return (SHELL_DEVICE_ERROR);
1024 }
1025 if (!MoveToTag(GetPreviousNode, L"if", L"else", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1026 ShellPrintHiiEx(
1027 -1,
1028 -1,
1029 NULL,
1030 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1031 gShellLevel1HiiHandle,
1032 L"If",
1033 L"Else",
1034 CurrentScriptFile!=NULL
1035 && CurrentScriptFile->CurrentCommand!=NULL
1036 ? CurrentScriptFile->CurrentCommand->Line:0);
1037 return (SHELL_DEVICE_ERROR);
1038 }
1039
1040 if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, CurrentScriptFile, FALSE, FALSE, FALSE)) {
1041 ShellPrintHiiEx(
1042 -1,
1043 -1,
1044 NULL,
1045 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1046 gShellLevel1HiiHandle,
1047 L"EndIf",
1048 "Else",
1049 CurrentScriptFile!=NULL
1050 && CurrentScriptFile->CurrentCommand!=NULL
1051 ? CurrentScriptFile->CurrentCommand->Line:0);
1052 return (SHELL_DEVICE_ERROR);
1053 }
1054
1055 return (SHELL_SUCCESS);
1056 }
1057
1058 /**
1059 Function for 'endif' command.
1060
1061 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1062 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1063 **/
1064 SHELL_STATUS
1065 EFIAPI
1066 ShellCommandRunEndIf (
1067 IN EFI_HANDLE ImageHandle,
1068 IN EFI_SYSTEM_TABLE *SystemTable
1069 )
1070 {
1071 SCRIPT_FILE *CurrentScriptFile;
1072 ASSERT_EFI_ERROR(CommandInit());
1073
1074 if (gEfiShellParametersProtocol->Argc > 1) {
1075 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle);
1076 return (SHELL_INVALID_PARAMETER);
1077 }
1078
1079 if (!gEfiShellProtocol->BatchIsActive()) {
1080 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif");
1081 return (SHELL_UNSUPPORTED);
1082 }
1083
1084 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
1085 if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, CurrentScriptFile, FALSE, TRUE, FALSE)) {
1086 ShellPrintHiiEx(
1087 -1,
1088 -1,
1089 NULL,
1090 STRING_TOKEN (STR_SYNTAX_NO_MATCHING),
1091 gShellLevel1HiiHandle,
1092 L"If",
1093 L"EndIf",
1094 CurrentScriptFile!=NULL
1095 && CurrentScriptFile->CurrentCommand!=NULL
1096 ? CurrentScriptFile->CurrentCommand->Line:0);
1097 return (SHELL_DEVICE_ERROR);
1098 }
1099
1100 return (SHELL_SUCCESS);
1101 }