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