/** @file\r
This is THE shell (application)\r
\r
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
- Copyright (c) 2013, Hewlett-Packard Development Company, L.P.\r
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
}\r
\r
/**\r
- Find a command line contains a split operation\r
+ Check whether the string between a pair of % is a valid envifronment variable name.\r
\r
- @param[in] CmdLine The command line to parse.\r
+ @param[in] BeginPercent pointer to the first percent.\r
+ @param[in] EndPercent pointer to the last percent.\r
\r
- @retval A pointer to the | character in CmdLine or NULL if not present.\r
+ @retval TRUE is a valid environment variable name.\r
+ @retval FALSE is NOT a valid environment variable name.\r
**/\r
-CONST CHAR16*\r
-EFIAPI\r
-FindSplit(\r
- IN CONST CHAR16 *CmdLine\r
+BOOLEAN\r
+IsValidEnvironmentVariableName(\r
+ IN CONST CHAR16 *BeginPercent,\r
+ IN CONST CHAR16 *EndPercent\r
)\r
{\r
- CONST CHAR16 *TempSpot;\r
- TempSpot = NULL;\r
- if (StrStr(CmdLine, L"|") != NULL) {\r
- for (TempSpot = CmdLine ; TempSpot != NULL && *TempSpot != CHAR_NULL ; TempSpot++) {\r
- if (*TempSpot == L'^' && *(TempSpot+1) == L'|') {\r
- TempSpot++;\r
- } else if (*TempSpot == L'|') {\r
- break;\r
+ CONST CHAR16 *Walker;\r
+ \r
+ Walker = NULL;\r
+\r
+ ASSERT (BeginPercent != NULL);\r
+ ASSERT (EndPercent != NULL);\r
+ ASSERT (BeginPercent < EndPercent);\r
+ \r
+ if ((BeginPercent + 1) == EndPercent) {\r
+ return FALSE;\r
+ }\r
+\r
+ for (Walker = BeginPercent + 1; Walker < EndPercent; Walker++) {\r
+ if (\r
+ (*Walker >= L'0' && *Walker <= L'9') ||\r
+ (*Walker >= L'A' && *Walker <= L'Z') ||\r
+ (*Walker >= L'a' && *Walker <= L'z') ||\r
+ (*Walker == L'_')\r
+ ) {\r
+ if (Walker == BeginPercent + 1 && (*Walker >= L'0' && *Walker <= L'9')) {\r
+ return FALSE;\r
+ } else {\r
+ continue;\r
}\r
+ } else {\r
+ return FALSE;\r
}\r
}\r
- return (TempSpot);\r
+\r
+ return TRUE;\r
}\r
\r
/**\r
)\r
{\r
CONST CHAR16 *TempSpot;\r
- TempSpot = FindSplit(CmdLine);\r
+ CONST CHAR16 *FirstQuote;\r
+ CONST CHAR16 *SecondQuote;\r
+\r
+ FirstQuote = FindFirstCharacter (CmdLine, L"\"", L'^');\r
+ SecondQuote = NULL;\r
+ TempSpot = FindFirstCharacter(CmdLine, L"|", L'^');\r
+\r
+ if (FirstQuote == NULL || \r
+ TempSpot == NULL || \r
+ TempSpot == CHAR_NULL || \r
+ FirstQuote > TempSpot\r
+ ) {\r
+ return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
+ }\r
+\r
+ while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) {\r
+ if (FirstQuote == NULL || FirstQuote > TempSpot) {\r
+ break;\r
+ } \r
+ SecondQuote = FindFirstCharacter (FirstQuote + 1, L"\"", L'^');\r
+ if (SecondQuote == NULL) {\r
+ break;\r
+ }\r
+ if (SecondQuote < TempSpot) {\r
+ FirstQuote = FindFirstCharacter (SecondQuote + 1, L"\"", L'^');\r
+ continue;\r
+ } else {\r
+ FirstQuote = FindFirstCharacter (SecondQuote + 1, L"\"", L'^');\r
+ TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');\r
+ continue;\r
+ } \r
+ }\r
+ \r
return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
}\r
\r
UINTN Size;\r
EFI_HANDLE ConInHandle;\r
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn;\r
- UINTN ExitDataSize;\r
- CHAR16 *ExitData;\r
- SHELL_STATUS ExitStatus;\r
\r
if (PcdGet8(PcdShellSupportLevel) > 3) {\r
return (EFI_UNSUPPORTED);\r
// install our console logger. This will keep a log of the output for back-browsing\r
//\r
Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo);\r
- if(EFI_ERROR (Status)) {\r
- ExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
- } else {\r
- ExitStatus = SHELL_SUCCESS;\r
- }\r
- \r
if (!EFI_ERROR(Status)) {\r
//\r
// Enable the cursor to be visible\r
// Display the mapping\r
//\r
if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {\r
- Status = RunCommand(L"map", NULL);\r
+ Status = RunCommand(L"map");\r
ASSERT_EFI_ERROR(Status);\r
}\r
\r
//\r
// process the startup script or launch the called app.\r
//\r
- Status = DoStartupScript(\r
- ShellInfoObject.ImageDevPath,\r
- ShellInfoObject.FileDevPath,\r
- &ExitStatus\r
- );\r
+ Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
}\r
\r
if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
// Reset page break back to default.\r
//\r
ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
+ ASSERT (ShellInfoObject.ConsoleInfo != NULL);\r
ShellInfoObject.ConsoleInfo->Enabled = TRUE;\r
ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
\r
//\r
Status = DoShellPrompt();\r
} while (!ShellCommandGetExit());\r
- ExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
}\r
if (OldConIn != NULL && ConInHandle != NULL) {\r
CloseSimpleTextInOnFile (gST->ConIn);\r
DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
}\r
\r
- if (!EFI_ERROR (Status)) {\r
- // If the command exited with an error, we pass this error out in the ExitData\r
- // so that it can be retrieved by the EfiShellExecute function (which may\r
- // start the shell with gBS->StartImage)\r
- if (ExitStatus != SHELL_SUCCESS) {\r
- // Allocate a buffer for exit data to pass to gBS->Exit().\r
- // This buffer will contain the empty string immediately followed by\r
- // the shell's exit status. (The empty string is required by the UEFI spec)\r
- ExitDataSize = (sizeof (CHAR16) + sizeof (SHELL_STATUS));\r
- ExitData = AllocatePool (ExitDataSize);\r
- if (ExitData == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ExitData[0] = '\0';\r
- // Use CopyMem to avoid alignment faults\r
- CopyMem ((ExitData + 1), &ExitStatus, sizeof (ExitStatus));\r
-\r
- gBS->Exit (ImageHandle, EFI_ABORTED, ExitDataSize, ExitData);\r
-\r
- ASSERT (FALSE);\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_SUCCESS;\r
- }\r
- } else {\r
- return Status;\r
+ if (ShellCommandGetExit()) {\r
+ return ((EFI_STATUS)ShellCommandGetExitCode());\r
}\r
+ return (Status);\r
}\r
\r
/**\r
ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = FALSE;\r
ShellInfoObject.ShellInitSettings.Delay = 5;\r
\r
- // Start LoopVar at 1 to ignore Argv[0] which is the name of this binary\r
- // (probably "Shell.efi")\r
- for (LoopVar = 1 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
+ //\r
+ // Start LoopVar at 0 to parse only optional arguments at Argv[0]\r
+ // and parse other parameters from Argv[1]. This is for use case that\r
+ // UEFI Shell boot option is created, and OptionalData is provided\r
+ // that starts with shell command-line options.\r
+ //\r
+ for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
CurrentArg = gEfiShellParametersProtocol->Argv[LoopVar];\r
if (UnicodeCollation->StriColl (\r
UnicodeCollation,\r
);\r
return EFI_INVALID_PARAMETER;\r
} else {\r
- ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(CurrentArg));\r
+ //\r
+ // First argument should be Shell.efi image name\r
+ //\r
+ if (LoopVar == 0) {\r
+ continue;\r
+ }\r
+\r
+ ShellInfoObject.ShellInitSettings.FileName = AllocateCopyPool(StrSize(CurrentArg), CurrentArg);\r
if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
// We found `file-name`.\r
//\r
ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
-\r
- StrCpy (ShellInfoObject.ShellInitSettings.FileName, CurrentArg);\r
LoopVar++;\r
\r
// Add `file-name-options`\r
@param ImagePath the path to the image for shell. first place to look for the startup script\r
@param FilePath the path to the file for shell. second place to look for the startup script.\r
\r
- @param[out] ExitStatus The exit code of the script. Ignored if NULL.\r
-\r
@retval EFI_SUCCESS the variable is initialized.\r
**/\r
EFI_STATUS\r
EFIAPI\r
DoStartupScript(\r
- IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
if (FileStringPath == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
+ StrnCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName, NewSize/sizeof(CHAR16) -1);\r
if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
- StrCat(FileStringPath, L" ");\r
- StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);\r
+ StrnCat(FileStringPath, L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
+ StrnCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
}\r
- Status = RunCommand(FileStringPath, ExitStatus);\r
+ Status = RunCommand(FileStringPath);\r
FreePool(FileStringPath);\r
return (Status);\r
\r
// If we got a file, run it\r
//\r
if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
- Status = RunScriptFile (\r
- mStartupScript,\r
- FileHandle,\r
- L"",\r
- ShellInfoObject.NewShellParametersProtocol,\r
- ExitStatus\r
- );\r
+ Status = RunScriptFile (mStartupScript, FileHandle, L"", ShellInfoObject.NewShellParametersProtocol);\r
ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
} else {\r
FileStringPath = ShellFindFilePath(mStartupScript);\r
Status = EFI_SUCCESS;\r
ASSERT(FileHandle == NULL);\r
} else {\r
- Status = RunScriptFile(\r
- FileStringPath,\r
- NULL,\r
- L"",\r
- ShellInfoObject.NewShellParametersProtocol,\r
- ExitStatus\r
- );\r
+ Status = RunScriptFile(FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
FreePool(FileStringPath);\r
}\r
}\r
//\r
if (!EFI_ERROR (Status)) {\r
CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
- Status = RunCommand(CmdLine, NULL);\r
+ Status = RunCommand(CmdLine);\r
}\r
\r
//\r
\r
Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ASSERT(Node != NULL);\r
- Node->Buffer = AllocateZeroPool(StrSize(Buffer));\r
+ Node->Buffer = AllocateCopyPool(StrSize(Buffer), Buffer);\r
ASSERT(Node->Buffer != NULL);\r
- StrCpy(Node->Buffer, Buffer);\r
\r
InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
}\r
return (EFI_SUCCESS);\r
}\r
FreePool(*CommandString);\r
- *CommandString = AllocateZeroPool(StrSize(NewString));\r
+ *CommandString = AllocateCopyPool(StrSize(NewString), NewString);\r
if (*CommandString == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(*CommandString, NewString);\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ This function will eliminate unreplaced (and therefore non-found) environment variables.\r
+\r
+ @param[in,out] CmdLine The command line to update.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StripUnreplacedEnvironmentVariables(\r
+ IN OUT CHAR16 *CmdLine\r
+ )\r
+{\r
+ CHAR16 *FirstPercent;\r
+ CHAR16 *FirstQuote;\r
+ CHAR16 *SecondPercent;\r
+ CHAR16 *SecondQuote;\r
+ CHAR16 *CurrentLocator;\r
+\r
+ for (CurrentLocator = CmdLine ; CurrentLocator != NULL ; ) {\r
+ FirstQuote = FindFirstCharacter(CurrentLocator, L"\"", L'^');\r
+ FirstPercent = FindFirstCharacter(CurrentLocator, L"%", L'^');\r
+ SecondPercent = FirstPercent!=NULL?FindFirstCharacter(FirstPercent+1, L"%", L'^'):NULL;\r
+ if (FirstPercent == NULL || SecondPercent == NULL) {\r
+ //\r
+ // If we ever dont have 2 % we are done.\r
+ //\r
+ break;\r
+ }\r
+\r
+ if (FirstQuote!= NULL && FirstQuote < FirstPercent) {\r
+ SecondQuote = FindFirstCharacter(FirstQuote+1, L"\"", L'^');\r
+ //\r
+ // Quote is first found\r
+ //\r
+ if (SecondQuote < FirstPercent) {\r
+ //\r
+ // restart after the pair of "\r
+ //\r
+ CurrentLocator = SecondQuote + 1;\r
+ } else /* FirstPercent < SecondQuote */{\r
+ //\r
+ // Restart on the first percent\r
+ //\r
+ CurrentLocator = FirstPercent;\r
+ }\r
+ continue;\r
+ }\r
+ \r
+ if (FirstQuote == NULL || SecondPercent < FirstQuote) {\r
+ if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) {\r
+ //\r
+ // We need to remove from FirstPercent to SecondPercent\r
+ //\r
+ CopyMem(FirstPercent, SecondPercent + 1, StrSize(SecondPercent + 1));\r
+ //\r
+ // dont need to update the locator. both % characters are gone.\r
+ //\r
+ } else {\r
+ CurrentLocator = SecondPercent + 1;\r
+ }\r
+ continue;\r
+ }\r
+ CurrentLocator = FirstQuote;\r
+ }\r
return (EFI_SUCCESS);\r
}\r
\r
CHAR16 *NewCommandLine1;\r
CHAR16 *NewCommandLine2;\r
CHAR16 *Temp;\r
- CHAR16 *Temp2;\r
UINTN ItemSize;\r
CHAR16 *ItemTemp;\r
SCRIPT_FILE *CurrentScriptFile;\r
//\r
// now do the replacements...\r
//\r
- NewCommandLine1 = AllocateZeroPool(NewSize);\r
+ NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\r
NewCommandLine2 = AllocateZeroPool(NewSize);\r
ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
SHELL_FREE_NON_NULL(ItemTemp);\r
return (NULL);\r
}\r
- StrCpy(NewCommandLine1, OriginalCommandLine);\r
for (MasterEnvList = EfiShellGetEnv(NULL)\r
- ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
+ ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
; MasterEnvList += StrLen(MasterEnvList) + 1\r
){\r
- StrCpy(ItemTemp, L"%");\r
- StrCat(ItemTemp, MasterEnvList);\r
- StrCat(ItemTemp, L"%");\r
+ StrnCpy(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1);\r
+ StrnCat(ItemTemp, MasterEnvList, ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\r
+ StrnCat(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
}\r
if (CurrentScriptFile != NULL) {\r
for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
){\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
- }\r
-\r
- //\r
- // Remove non-existant environment variables in scripts only\r
- //\r
- for (Temp = NewCommandLine1 ; Temp != NULL ; ) {\r
- Temp = StrStr(Temp, L"%");\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- while (*(Temp - 1) == L'^') {\r
- Temp = StrStr(Temp + 1, L"%");\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- }\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- \r
- Temp2 = StrStr(Temp + 1, L"%");\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- while (*(Temp2 - 1) == L'^') {\r
- Temp2 = StrStr(Temp2 + 1, L"%");\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- }\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- \r
- Temp2++;\r
- CopyMem(Temp, Temp2, StrSize(Temp2));\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
}\r
-\r
}\r
\r
+ //\r
+ // Remove non-existant environment variables\r
+ //\r
+ StripUnreplacedEnvironmentVariables(NewCommandLine1);\r
+\r
//\r
// Now cleanup any straggler intentionally ignored "%" characters\r
//\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
\r
FreePool(NewCommandLine2);\r
FreePool(ItemTemp);\r
@param[in] StdIn The pointer to the Standard input.\r
@param[in] StdOut The pointer to the Standard output.\r
\r
- @param[out] ExitStatus The exit code of the last command in the pipeline.\r
- Ignored if NULL.\r
-\r
@retval EFI_SUCCESS The split command is executed successfully.\r
@retval other Some error occurs when executing the split command.\r
**/\r
RunSplitCommand(\r
IN CONST CHAR16 *CmdLine,\r
IN SHELL_FILE_HANDLE *StdIn,\r
- IN SHELL_FILE_HANDLE *StdOut,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN SHELL_FILE_HANDLE *StdOut\r
)\r
{\r
EFI_STATUS Status;\r
ASSERT(Split->SplitStdOut != NULL);\r
InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);\r
\r
- Status = RunCommand(OurCommandLine, NULL);\r
+ Status = RunCommand(OurCommandLine);\r
\r
//\r
// move the output from the first to the in to the second.\r
ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
\r
if (!EFI_ERROR(Status)) {\r
- Status = RunCommand(NextCommandLine, ExitStatus);\r
+ Status = RunCommand(NextCommandLine);\r
}\r
\r
//\r
}\r
\r
//\r
- // Test for file system change request. anything ending with : and cant have spaces.\r
+ // Test for file system change request. anything ending with first : and cant have spaces.\r
//\r
if (CmdName[(StrLen(CmdName)-1)] == L':') {\r
- if (StrStr(CmdName, L" ") != NULL) {\r
+ if ( StrStr(CmdName, L" ") != NULL \r
+ || StrLen(StrStr(CmdName, L":")) > 1\r
+ ) {\r
return (Unknown_Invalid);\r
}\r
return (File_Sys_Change);\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
TempWalker = (CHAR16*)Temp;\r
- GetNextParameter(&TempWalker, &FirstParameter);\r
-\r
- if (GetOperationType(FirstParameter) == Unknown_Invalid) {\r
- ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
- SetLastError(SHELL_NOT_FOUND);\r
- Status = EFI_NOT_FOUND;\r
+ if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine)))) {\r
+ if (GetOperationType(FirstParameter) == Unknown_Invalid) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+ SetLastError(SHELL_NOT_FOUND);\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
}\r
}\r
\r
//\r
// recurse to verify the next item\r
//\r
- TempSpot = FindSplit(CmdLine)+1;\r
+ TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;\r
return (VerifySplit(TempSpot));\r
}\r
\r
/**\r
Process a split based operation.\r
\r
- @param[in] CmdLine Pointer to the command line to process\r
- @param[out] ExitStatus The exit status of the command. Ignored if NULL.\r
- Invalid if this function returns an error.\r
+ @param[in] CmdLine pointer to the command line to process\r
\r
@retval EFI_SUCCESS The operation was successful\r
@return an error occured.\r
EFI_STATUS\r
EFIAPI\r
ProcessNewSplitCommandLine(\r
- IN CONST CHAR16 *CmdLine,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN CONST CHAR16 *CmdLine\r
)\r
{\r
SPLIT_LIST *Split;\r
}\r
\r
if (Split == NULL) {\r
- Status = RunSplitCommand(CmdLine, NULL, NULL, ExitStatus);\r
+ Status = RunSplitCommand(CmdLine, NULL, NULL);\r
} else {\r
- Status = RunSplitCommand(\r
- CmdLine,\r
- Split->SplitStdIn,\r
- Split->SplitStdOut,\r
- ExitStatus\r
- );\r
+ Status = RunSplitCommand(CmdLine, Split->SplitStdIn, Split->SplitStdOut);\r
}\r
if (EFI_ERROR(Status)) {\r
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, CmdLine);\r
Walker = *CmdLine;\r
while(Walker != NULL && *Walker != CHAR_NULL) {\r
LastWalker = Walker;\r
- GetNextParameter(&Walker, &CurrentParameter);\r
- if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {\r
- LastWalker[0] = L' ';\r
- LastWalker[1] = L' ';\r
- NewCommandLine = AllocateZeroPool(StrSize(L"help ") + StrSize(*CmdLine));\r
- if (NewCommandLine == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine)))) {\r
+ if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {\r
+ LastWalker[0] = L' ';\r
+ LastWalker[1] = L' ';\r
+ NewCommandLine = AllocateZeroPool(StrSize(L"help ") + StrSize(*CmdLine));\r
+ if (NewCommandLine == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // We know the space is sufficient since we just calculated it.\r
+ //\r
+ StrnCpy(NewCommandLine, L"help ", 5);\r
+ StrnCat(NewCommandLine, *CmdLine, StrLen(*CmdLine));\r
+ SHELL_FREE_NON_NULL(*CmdLine);\r
+ *CmdLine = NewCommandLine;\r
break;\r
}\r
- StrCpy(NewCommandLine, L"help ");\r
- StrCat(NewCommandLine, *CmdLine);\r
- SHELL_FREE_NON_NULL(*CmdLine);\r
- *CmdLine = NewCommandLine;\r
- break;\r
}\r
}\r
\r
if (EFI_ERROR(Status)) {\r
return (Status);\r
}\r
+ ASSERT (*CmdLine != NULL);\r
\r
TrimSpaces(CmdLine);\r
\r
@param[in] FirstParameter the first parameter on the command line\r
@param[in] ParamProtocol the shell parameters protocol pointer\r
\r
- @param[out] ExitStatus The exit code of the command. Ignored if NULL.\r
-\r
@retval EFI_SUCCESS The command was completed.\r
@retval EFI_ABORTED The command's operation was aborted.\r
**/\r
RunInternalCommand(\r
IN CONST CHAR16 *CmdLine,\r
IN CHAR16 *FirstParameter,\r
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
- OUT SHELL_STATUS *ExitStatus OPTIONAL\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol\r
)\r
{\r
EFI_STATUS Status;\r
CHAR16 **Argv;\r
SHELL_STATUS CommandReturnedStatus;\r
BOOLEAN LastError;\r
+ CHAR16 *Walker;\r
+ CHAR16 *NewCmdLine; \r
+\r
+ NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
+ if (NewCmdLine == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+ if (*Walker == L'^' && *(Walker+1) == L'#') {\r
+ CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+ }\r
+ }\r
\r
//\r
// get the argc and argv updated for internal commands\r
//\r
- Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc);\r
+ Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, &Argv, &Argc);\r
if (!EFI_ERROR(Status)) {\r
//\r
// Run the internal command.\r
if (LastError) {\r
SetLastError(CommandReturnedStatus);\r
}\r
- if (ExitStatus != NULL) {\r
- *ExitStatus = CommandReturnedStatus;\r
- }\r
\r
//\r
// Pass thru the exitcode from the app.\r
Status = EFI_SUCCESS;\r
}\r
\r
+ FreePool (NewCmdLine);\r
return (Status);\r
}\r
\r
@param[in] FirstParameter the first parameter on the command line\r
@param[in] ParamProtocol the shell parameters protocol pointer\r
\r
- @param[out] ExitStatus The exit code of the command or file.\r
- Ignored if NULL.\r
-\r
@retval EFI_SUCCESS The command was completed.\r
@retval EFI_ABORTED The command's operation was aborted.\r
**/\r
IN SHELL_OPERATION_TYPES Type,\r
IN CONST CHAR16 *CmdLine,\r
IN CHAR16 *FirstParameter,\r
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol\r
)\r
{\r
EFI_STATUS Status;\r
+ EFI_STATUS StartStatus;\r
CHAR16 *CommandWithPath;\r
EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
SHELL_STATUS CalleeExitStatus;\r
\r
switch (Type) {\r
case Internal_Command:\r
- Status = RunInternalCommand(\r
- CmdLine,\r
- FirstParameter,\r
- ParamProtocol,\r
- &CalleeExitStatus\r
- );\r
+ Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol);\r
break;\r
case Script_File_Name:\r
case Efi_Application:\r
}\r
switch (Type) {\r
case Script_File_Name:\r
- Status = RunScriptFile (\r
- CommandWithPath,\r
- NULL,\r
- CmdLine,\r
- ParamProtocol,\r
- &CalleeExitStatus\r
- );\r
+ Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
break;\r
case Efi_Application:\r
//\r
DevPath,\r
CmdLine,\r
NULL,\r
- NULL,\r
- NULL\r
+ &StartStatus\r
);\r
\r
SHELL_FREE_NON_NULL(DevPath);\r
if(EFI_ERROR (Status)) {\r
CalleeExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
} else {\r
- CalleeExitStatus = SHELL_SUCCESS;\r
+ CalleeExitStatus = (SHELL_STATUS) StartStatus;\r
}\r
\r
//\r
\r
SHELL_FREE_NON_NULL(CommandWithPath);\r
\r
- if (ExitStatus != NULL) {\r
- *ExitStatus = CalleeExitStatus;\r
- }\r
-\r
return (Status);\r
}\r
\r
@param[in] FirstParameter the first parameter on the command line.\r
@param[in] ParamProtocol the shell parameters protocol pointer\r
\r
- @param[out] ExitStatus The exit code of the command or file.\r
- Ignored if NULL.\r
-\r
@retval EFI_SUCCESS The command was completed.\r
@retval EFI_ABORTED The command's operation was aborted.\r
**/\r
EFI_STATUS\r
EFIAPI\r
SetupAndRunCommandOrFile(\r
- IN SHELL_OPERATION_TYPES Type,\r
- IN CHAR16 *CmdLine,\r
- IN CHAR16 *FirstParameter,\r
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN SHELL_OPERATION_TYPES Type,\r
+ IN CHAR16 *CmdLine,\r
+ IN CHAR16 *FirstParameter,\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol\r
)\r
{\r
EFI_STATUS Status;\r
// Now run the command, script, or application\r
//\r
if (!EFI_ERROR(Status)) {\r
- Status = RunCommandOrFile(\r
- Type,\r
- CmdLine,\r
- FirstParameter,\r
- ParamProtocol,\r
- ExitStatus\r
- );\r
+ TrimSpaces(&CmdLine);\r
+ Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol);\r
}\r
\r
//\r
command or dispatch an external application.\r
\r
@param[in] CmdLine The command line to parse.\r
- @param[out] ExitStatus The exit code of the command. Ignored if NULL.\r
\r
@retval EFI_SUCCESS The command was completed.\r
@retval EFI_ABORTED The command's operation was aborted.\r
EFI_STATUS\r
EFIAPI\r
RunCommand(\r
- IN CONST CHAR16 *CmdLine,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN CONST CHAR16 *CmdLine\r
)\r
{\r
EFI_STATUS Status;\r
\r
TrimSpaces(&CleanOriginal);\r
\r
+ //\r
+ // NULL out comments (leveraged from RunScriptFileHandle() ).\r
+ // The # character on a line is used to denote that all characters on the same line\r
+ // and to the right of the # are to be ignored by the shell.\r
+ // Afterward, again remove spaces, in case any were between the last command-parameter and '#'.\r
+ //\r
+ for (TempWalker = CleanOriginal; TempWalker != NULL && *TempWalker != CHAR_NULL; TempWalker++) {\r
+ if (*TempWalker == L'^') {\r
+ if (*(TempWalker + 1) == L'#') {\r
+ TempWalker++;\r
+ }\r
+ } else if (*TempWalker == L'#') {\r
+ *TempWalker = CHAR_NULL;\r
+ }\r
+ }\r
+\r
+ TrimSpaces(&CleanOriginal);\r
+\r
//\r
// Handle case that passed in command line is just 1 or more " " characters.\r
//\r
// We dont do normal processing with a split command line (output from one command input to another)\r
//\r
if (ContainsSplit(CleanOriginal)) {\r
- Status = ProcessNewSplitCommandLine(CleanOriginal, ExitStatus);\r
+ Status = ProcessNewSplitCommandLine(CleanOriginal);\r
SHELL_FREE_NON_NULL(CleanOriginal);\r
return (Status);\r
} \r
return (EFI_OUT_OF_RESOURCES);\r
}\r
TempWalker = CleanOriginal;\r
- GetNextParameter(&TempWalker, &FirstParameter);\r
-\r
- //\r
- // Depending on the first parameter we change the behavior\r
- //\r
- switch (Type = GetOperationType(FirstParameter)) {\r
- case File_Sys_Change:\r
- Status = ChangeMappedDrive(CleanOriginal);\r
- break;\r
- case Internal_Command:\r
- case Script_File_Name:\r
- case Efi_Application:\r
- Status = SetupAndRunCommandOrFile(\r
- Type,\r
- CleanOriginal,\r
- FirstParameter,\r
- ShellInfoObject.NewShellParametersProtocol,\r
- ExitStatus\r
- );\r
- break;\r
- default:\r
- //\r
- // Whatever was typed, it was invalid.\r
- //\r
- ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
- SetLastError(SHELL_NOT_FOUND);\r
- break;\r
+ if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal)))) {\r
+ //\r
+ // Depending on the first parameter we change the behavior\r
+ //\r
+ switch (Type = GetOperationType(FirstParameter)) {\r
+ case File_Sys_Change:\r
+ Status = ChangeMappedDrive (FirstParameter);\r
+ break;\r
+ case Internal_Command:\r
+ case Script_File_Name:\r
+ case Efi_Application:\r
+ Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol);\r
+ break;\r
+ default:\r
+ //\r
+ // Whatever was typed, it was invalid.\r
+ //\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+ SetLastError(SHELL_NOT_FOUND);\r
+ break;\r
+ }\r
+ } else {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+ SetLastError(SHELL_NOT_FOUND);\r
}\r
\r
SHELL_FREE_NON_NULL(CleanOriginal);\r
@param[in] Handle The handle to the already opened file.\r
@param[in] Name The name of the script file.\r
\r
- @param[out] ExitStatus The exit code of the script. Ignored if NULL.\r
-\r
@retval EFI_SUCCESS the script completed sucessfully\r
**/\r
EFI_STATUS\r
EFIAPI\r
RunScriptFileHandle (\r
- IN SHELL_FILE_HANDLE Handle,\r
- IN CONST CHAR16 *Name,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN SHELL_FILE_HANDLE Handle,\r
+ IN CONST CHAR16 *Name\r
)\r
{\r
EFI_STATUS Status;\r
CONST CHAR16 *CurDir;\r
UINTN LineCount;\r
CHAR16 LeString[50];\r
- SHELL_STATUS CalleeExitStatus;\r
\r
ASSERT(!ShellCommandGetScriptExit());\r
- \r
- CalleeExitStatus = SHELL_SUCCESS;\r
\r
PreScriptEchoState = ShellCommandGetEchoState();\r
\r
; // conditional increment in the body of the loop\r
){\r
ASSERT(CommandLine2 != NULL);\r
- StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
+ StrnCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
//\r
// NULL out comments\r
//\r
for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
if (*CommandLine3 == L'^') {\r
- if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
+ if ( *(CommandLine3+1) == L':') {\r
CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
+ } else if (*(CommandLine3+1) == L'#') {\r
+ CommandLine3++;\r
}\r
} else if (*CommandLine3 == L'#') {\r
*CommandLine3 = CHAR_NULL;\r
//\r
// Due to variability in starting the find and replace action we need to have both buffers the same.\r
//\r
- StrCpy(CommandLine, CommandLine2);\r
+ StrnCpy(CommandLine, CommandLine2, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
//\r
// Remove the %0 to %9 from the command line (if we have some arguments)\r
Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
\r
- StrCpy(CommandLine2, CommandLine);\r
+ StrnCpy(CommandLine2, CommandLine, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
LastCommand = NewScriptFile->CurrentCommand;\r
\r
//\r
PreCommandEchoState = ShellCommandGetEchoState();\r
ShellCommandSetEchoState(FALSE);\r
- Status = RunCommand(CommandLine3+1, NULL);\r
+ Status = RunCommand(CommandLine3+1);\r
\r
//\r
// If command was "@echo -off" or "@echo -on" then don't restore echo state\r
}\r
ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);\r
}\r
- Status = RunCommand(CommandLine3, NULL);\r
+ Status = RunCommand(CommandLine3);\r
}\r
}\r
\r
//\r
// ShellCommandGetExitCode() always returns a UINT64\r
//\r
- CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
- UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", CalleeExitStatus);\r
+ UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode());\r
DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
\r
break;\r
}\r
if (EFI_ERROR(Status)) {\r
- CalleeExitStatus = (SHELL_STATUS) Status;\r
break;\r
}\r
if (ShellCommandGetExit()) {\r
- CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
break;\r
}\r
}\r
if (ShellCommandGetCurrentScriptFile()==NULL) {\r
ShellCommandSetEchoState(PreScriptEchoState);\r
}\r
-\r
- if (ExitStatus != NULL) {\r
- *ExitStatus = CalleeExitStatus;\r
- }\r
-\r
return (EFI_SUCCESS);\r
}\r
\r
@param[in] CmdLine the command line to run.\r
@param[in] ParamProtocol the shell parameters protocol pointer\r
\r
- @param[out] ExitStatus The exit code of the script. Ignored if NULL.\r
-\r
@retval EFI_SUCCESS the script completed sucessfully\r
**/\r
EFI_STATUS\r
EFIAPI\r
RunScriptFile (\r
- IN CONST CHAR16 *ScriptPath,\r
- IN SHELL_FILE_HANDLE Handle OPTIONAL,\r
- IN CONST CHAR16 *CmdLine,\r
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
- OUT SHELL_STATUS *ExitStatus\r
+ IN CONST CHAR16 *ScriptPath,\r
+ IN SHELL_FILE_HANDLE Handle OPTIONAL,\r
+ IN CONST CHAR16 *CmdLine,\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol\r
)\r
{\r
EFI_STATUS Status;\r
//\r
// run it\r
//\r
- Status = RunScriptFileHandle(FileHandle, ScriptPath, ExitStatus);\r
+ Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
\r
//\r
// now close the file\r
ShellCloseFile(&FileHandle);\r
}\r
} else {\r
- Status = RunScriptFileHandle(Handle, ScriptPath, ExitStatus);\r
+ Status = RunScriptFileHandle(Handle, ScriptPath);\r
}\r
}\r
\r
\r
return (Status);\r
}\r
+\r
+/**\r
+ Return the pointer to the first occurance of any character from a list of characters.\r
+\r
+ @param[in] String the string to parse\r
+ @param[in] CharacterList the list of character to look for\r
+ @param[in] EscapeCharacter An escape character to skip\r
+\r
+ @return the location of the first character in the string\r
+ @retval CHAR_NULL no instance of any character in CharacterList was found in String\r
+**/\r
+CONST CHAR16*\r
+EFIAPI\r
+FindFirstCharacter(\r
+ IN CONST CHAR16 *String,\r
+ IN CONST CHAR16 *CharacterList,\r
+ IN CONST CHAR16 EscapeCharacter\r
+ )\r
+{\r
+ UINT32 WalkChar;\r
+ UINT32 WalkStr;\r
+\r
+ for (WalkStr = 0; WalkStr < StrLen(String); WalkStr++) {\r
+ if (String[WalkStr] == EscapeCharacter) {\r
+ WalkStr++;\r
+ continue;\r
+ }\r
+ for (WalkChar = 0; WalkChar < StrLen(CharacterList); WalkChar++) {\r
+ if (String[WalkStr] == CharacterList[WalkChar]) {\r
+ return (&String[WalkStr]);\r
+ }\r
+ }\r
+ }\r
+ return (String + StrLen(String));\r
+}
\ No newline at end of file