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