1 /** @file 2 Main file for If and else shell level 1 function. 3 4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR> 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, L"if"); 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, L"if"); 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, L"if", 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, L"if", 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, L"if"); 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, L"if"); 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 } 1100