]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel1CommandsLib/If.c
MdeModulePkg, MdePkg, NetworkPkg, OvmfPkg, PerformancePkg, ShellPkg: Library Migration.
[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 - 2014, 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
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
738 //
739 // Skip leading spaces and tabs.
740 //
741 while ((CommandWalker[0] == L' ') || (CommandWalker[0] == L'\t')) {
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"EndIf",
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 }