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