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