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