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