/** @file\r
Provides interface to shell functionality for shell commands and applications.\r
\r
- Copyright 2016 Dell Inc.\r
- Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\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
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+ Copyright 2016-2018 Dell Technologies.<BR>\r
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "UefiShellLib.h"\r
-#include <ShellBase.h>\r
#include <Library/SortLib.h>\r
#include <Library/BaseLib.h>\r
\r
-#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)\r
-\r
//\r
// globals...\r
//\r
EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;\r
EFI_HANDLE mEfiShellEnvironment2Handle;\r
FILE_HANDLE_FUNCTION_MAP FileFunctionMap;\r
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationProtocol;\r
+\r
+/**\r
+ Return a clean, fully-qualified version of an input path. If the return value\r
+ is non-NULL the caller must free the memory when it is no longer needed.\r
+\r
+ If asserts are disabled, and if the input parameter is NULL, NULL is returned.\r
+\r
+ If there is not enough memory available to create the fully-qualified path or\r
+ a copy of the input path, NULL is returned.\r
+\r
+ If there is no working directory, a clean copy of Path is returned.\r
+\r
+ Otherwise, the current file system or working directory (as appropriate) is\r
+ prepended to Path and the resulting path is cleaned and returned.\r
+\r
+ NOTE: If the input path is an empty string, then the current working directory\r
+ (if it exists) is returned. In other words, an empty input path is treated\r
+ exactly the same as ".".\r
+\r
+ @param[in] Path A pointer to some file or directory path.\r
+\r
+ @retval NULL The input path is NULL or out of memory.\r
+\r
+ @retval non-NULL A pointer to a clean, fully-qualified version of Path.\r
+ If there is no working directory, then a pointer to a\r
+ clean, but not necessarily fully-qualified version of\r
+ Path. The caller must free this memory when it is no\r
+ longer needed.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+FullyQualifyPath(\r
+ IN CONST CHAR16 *Path\r
+ )\r
+{\r
+ CONST CHAR16 *WorkingPath;\r
+ CONST CHAR16 *InputPath;\r
+ CHAR16 *CharPtr;\r
+ CHAR16 *InputFileSystem;\r
+ UINTN FileSystemCharCount;\r
+ CHAR16 *FullyQualifiedPath;\r
+ UINTN Size;\r
+\r
+ FullyQualifiedPath = NULL;\r
+\r
+ ASSERT(Path != NULL);\r
+ //\r
+ // Handle erroneous input when asserts are disabled.\r
+ //\r
+ if (Path == NULL) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,\r
+ // we have to consider the file system part separately from the "path" part.\r
+ // If there is a file system in the path, we have to get the current working\r
+ // directory for that file system. Then we need to use the part of the path\r
+ // following the ":". If a path does not contain ":", we use it as given.\r
+ //\r
+ InputPath = StrStr(Path, L":");\r
+ if (InputPath != NULL) {\r
+ InputPath++;\r
+ FileSystemCharCount = ((UINTN)InputPath - (UINTN)Path + sizeof(CHAR16)) / sizeof(CHAR16);\r
+ InputFileSystem = AllocateCopyPool(FileSystemCharCount * sizeof(CHAR16), Path);\r
+ if (InputFileSystem != NULL) {\r
+ InputFileSystem[FileSystemCharCount - 1] = CHAR_NULL;\r
+ }\r
+ WorkingPath = ShellGetCurrentDir(InputFileSystem);\r
+ SHELL_FREE_NON_NULL(InputFileSystem);\r
+ } else {\r
+ InputPath = Path;\r
+ WorkingPath = ShellGetEnvironmentVariable(L"cwd");\r
+ }\r
+\r
+ if (WorkingPath == NULL) {\r
+ //\r
+ // With no working directory, all we can do is copy and clean the input path.\r
+ //\r
+ FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path);\r
+ } else {\r
+ //\r
+ // Allocate space for both strings plus one more character.\r
+ //\r
+ Size = StrSize(WorkingPath) + StrSize(InputPath);\r
+ FullyQualifiedPath = AllocateZeroPool(Size);\r
+ if (FullyQualifiedPath == NULL) {\r
+ //\r
+ // Try to copy and clean just the input. No harm if not enough memory.\r
+ //\r
+ FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path);\r
+ } else {\r
+ if (*InputPath == L'\\' || *InputPath == L'/') {\r
+ //\r
+ // Absolute path: start with the current working directory, then\r
+ // truncate the new path after the file system part.\r
+ //\r
+ StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath);\r
+ CharPtr = StrStr(FullyQualifiedPath, L":");\r
+ if (CharPtr != NULL) {\r
+ *(CharPtr + 1) = CHAR_NULL;\r
+ }\r
+ } else {\r
+ //\r
+ // Relative path: start with the working directory and append "\".\r
+ //\r
+ StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath);\r
+ StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), L"\\");\r
+ }\r
+ //\r
+ // Now append the absolute or relative path.\r
+ //\r
+ StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), InputPath);\r
+ }\r
+ }\r
+\r
+ PathCleanUpDirectories(FullyQualifiedPath);\r
+\r
+ return FullyQualifiedPath;\r
+}\r
\r
/**\r
Check if a Unicode character is a hexadecimal character.\r
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
ShellFindSE2 (\r
IN EFI_HANDLE ImageHandle\r
)\r
@retval EFI_SUCCESS The operationw as successful.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
ShellLibConstructorWorker (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
{\r
EFI_STATUS Status;\r
\r
- //\r
- // UEFI 2.0 shell interfaces (used preferentially)\r
- //\r
- Status = gBS->OpenProtocol(\r
- ImageHandle,\r
- &gEfiShellProtocolGuid,\r
- (VOID **)&gEfiShellProtocol,\r
- ImageHandle,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR(Status)) {\r
+ if (gEfiShellProtocol == NULL) {\r
//\r
- // Search for the shell protocol\r
+ // UEFI 2.0 shell interfaces (used preferentially)\r
//\r
- Status = gBS->LocateProtocol(\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
&gEfiShellProtocolGuid,\r
+ (VOID **)&gEfiShellProtocol,\r
+ ImageHandle,\r
NULL,\r
- (VOID **)&gEfiShellProtocol\r
- );\r
- if (EFI_ERROR(Status)) {\r
- gEfiShellProtocol = NULL;\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Search for the shell protocol\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiShellProtocolGuid,\r
+ NULL,\r
+ (VOID **)&gEfiShellProtocol\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gEfiShellProtocol = NULL;\r
+ }\r
}\r
}\r
- Status = gBS->OpenProtocol(\r
- ImageHandle,\r
- &gEfiShellParametersProtocolGuid,\r
- (VOID **)&gEfiShellParametersProtocol,\r
- ImageHandle,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR(Status)) {\r
- gEfiShellParametersProtocol = NULL;\r
+\r
+ if (gEfiShellParametersProtocol == NULL) {\r
+ Status = gBS->OpenProtocol (\r
+ ImageHandle,\r
+ &gEfiShellParametersProtocolGuid,\r
+ (VOID **)&gEfiShellParametersProtocol,\r
+ ImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gEfiShellParametersProtocol = NULL;\r
+ }\r
}\r
\r
- if (gEfiShellParametersProtocol == NULL || gEfiShellProtocol == NULL) {\r
+ if (gEfiShellProtocol == NULL) {\r
//\r
// Moved to seperate function due to complexity\r
//\r
}\r
\r
//\r
- // only success getting 2 of either the old or new, but no 1/2 and 1/2\r
+ // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol\r
+ // or UEFI Shell's Shell protocol.\r
+ // When ShellLib is linked to a driver producing DynamicCommand protocol,\r
+ // ShellParameters protocol is set by DynamicCommand.Handler().\r
//\r
- if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||\r
- (gEfiShellProtocol != NULL && gEfiShellParametersProtocol != NULL) ) {\r
+ if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||\r
+ (gEfiShellProtocol != NULL)\r
+ ) {\r
if (gEfiShellProtocol != NULL) {\r
FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;\r
FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;\r
gEfiShellParametersProtocol = NULL;\r
mEfiShellInterface = NULL;\r
mEfiShellEnvironment2Handle = NULL;\r
+ mUnicodeCollationProtocol = NULL;\r
\r
//\r
// verify that auto initialize is not set false\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
+ EFI_STATUS Status;\r
+\r
if (mEfiShellEnvironment2 != NULL) {\r
- gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,\r
+ Status = gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,\r
&gEfiShellEnvironment2Guid,\r
ImageHandle,\r
NULL);\r
- mEfiShellEnvironment2 = NULL;\r
+ if (!EFI_ERROR (Status)) {\r
+ mEfiShellEnvironment2 = NULL;\r
+ mEfiShellEnvironment2Handle = NULL;\r
+ }\r
}\r
if (mEfiShellInterface != NULL) {\r
- gBS->CloseProtocol(ImageHandle,\r
+ Status = gBS->CloseProtocol(ImageHandle,\r
&gEfiShellInterfaceGuid,\r
ImageHandle,\r
NULL);\r
- mEfiShellInterface = NULL;\r
+ if (!EFI_ERROR (Status)) {\r
+ mEfiShellInterface = NULL;\r
+ }\r
}\r
if (gEfiShellProtocol != NULL) {\r
- gBS->CloseProtocol(ImageHandle,\r
+ Status = gBS->CloseProtocol(ImageHandle,\r
&gEfiShellProtocolGuid,\r
ImageHandle,\r
NULL);\r
- gEfiShellProtocol = NULL;\r
+ if (!EFI_ERROR (Status)) {\r
+ gEfiShellProtocol = NULL;\r
+ }\r
}\r
if (gEfiShellParametersProtocol != NULL) {\r
- gBS->CloseProtocol(ImageHandle,\r
+ Status = gBS->CloseProtocol(ImageHandle,\r
&gEfiShellParametersProtocolGuid,\r
ImageHandle,\r
NULL);\r
- gEfiShellParametersProtocol = NULL;\r
+ if (!EFI_ERROR (Status)) {\r
+ gEfiShellParametersProtocol = NULL;\r
+ }\r
}\r
- mEfiShellEnvironment2Handle = NULL;\r
\r
return (EFI_SUCCESS);\r
}\r
EFI_STATUS\r
EFIAPI\r
ShellInitialize (\r
+ VOID\r
)\r
{\r
+ EFI_STATUS Status;\r
+\r
//\r
// if auto initialize is not false then skip\r
//\r
//\r
// deinit the current stuff\r
//\r
- ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));\r
+ Status = ShellLibDestructor (gImageHandle, gST);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
//\r
// init the new stuff\r
\r
@param FilePath on input the device path to the file. On output\r
the remaining device path.\r
- @param DeviceHandle pointer to the system device handle.\r
@param FileHandle pointer to the file handle.\r
@param OpenMode the mode to open the file with.\r
@param Attributes the file's file attributes.\r
EFIAPI\r
ShellOpenFileByDevicePath(\r
IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
- OUT EFI_HANDLE *DeviceHandle,\r
OUT SHELL_FILE_HANDLE *FileHandle,\r
IN UINT64 OpenMode,\r
IN UINT64 Attributes\r
{\r
CHAR16 *FileName;\r
EFI_STATUS Status;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;\r
- EFI_FILE_PROTOCOL *Handle1;\r
- EFI_FILE_PROTOCOL *Handle2;\r
- CHAR16 *FnafPathName;\r
- UINTN PathLen;\r
+ EFI_FILE_PROTOCOL *File;\r
\r
- if (FilePath == NULL || FileHandle == NULL || DeviceHandle == NULL) {\r
+ if (FilePath == NULL || FileHandle == NULL) {\r
return (EFI_INVALID_PARAMETER);\r
}\r
\r
//\r
// use old shell method.\r
//\r
- Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,\r
- FilePath,\r
- DeviceHandle);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- Status = gBS->OpenProtocol(*DeviceHandle,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- (VOID**)&EfiSimpleFileSystemProtocol,\r
- gImageHandle,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ Status = EfiOpenFileByDevicePath (FilePath, &File, OpenMode, Attributes);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);\r
- if (EFI_ERROR (Status)) {\r
- FileHandle = NULL;\r
- return Status;\r
- }\r
-\r
- //\r
- // go down directories one node at a time.\r
- //\r
- while (!IsDevicePathEnd (*FilePath)) {\r
- //\r
- // For file system access each node should be a file path component\r
- //\r
- if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||\r
- DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP\r
- ) {\r
- FileHandle = NULL;\r
- return (EFI_INVALID_PARAMETER);\r
- }\r
- //\r
- // Open this file path node\r
- //\r
- Handle2 = Handle1;\r
- Handle1 = NULL;\r
-\r
- //\r
- // File Name Alignment Fix (FNAF)\r
- // Handle2->Open may be incapable of handling a unaligned CHAR16 data.\r
- // The structure pointed to by FilePath may be not CHAR16 aligned.\r
- // This code copies the potentially unaligned PathName data from the\r
- // FilePath structure to the aligned FnafPathName for use in the\r
- // calls to Handl2->Open.\r
- //\r
-\r
- //\r
- // Determine length of PathName, in bytes.\r
- //\r
- PathLen = DevicePathNodeLength (*FilePath) - SIZE_OF_FILEPATH_DEVICE_PATH;\r
-\r
- //\r
- // Allocate memory for the aligned copy of the string Extra allocation is to allow for forced alignment\r
- // Copy bytes from possibly unaligned location to aligned location\r
- //\r
- FnafPathName = AllocateCopyPool(PathLen, (UINT8 *)((FILEPATH_DEVICE_PATH*)*FilePath)->PathName);\r
- if (FnafPathName == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Try to test opening an existing file\r
- //\r
- Status = Handle2->Open (\r
- Handle2,\r
- &Handle1,\r
- FnafPathName,\r
- OpenMode &~EFI_FILE_MODE_CREATE,\r
- 0\r
- );\r
-\r
- //\r
- // see if the error was that it needs to be created\r
- //\r
- if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {\r
- Status = Handle2->Open (\r
- Handle2,\r
- &Handle1,\r
- FnafPathName,\r
- OpenMode,\r
- Attributes\r
- );\r
- }\r
-\r
- //\r
- // Free the alignment buffer\r
- //\r
- FreePool(FnafPathName);\r
-\r
- //\r
- // Close the last node\r
- //\r
- Handle2->Close (Handle2);\r
-\r
- if (EFI_ERROR(Status)) {\r
- return (Status);\r
- }\r
-\r
- //\r
- // Get the next node\r
- //\r
- *FilePath = NextDevicePathNode (*FilePath);\r
- }\r
\r
//\r
// This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!\r
//\r
- *FileHandle = (VOID*)Handle1;\r
+ *FileHandle = (VOID*)File;\r
return (EFI_SUCCESS);\r
}\r
\r
IN UINT64 Attributes\r
)\r
{\r
- EFI_HANDLE DeviceHandle;\r
EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
EFI_STATUS Status;\r
EFI_FILE_INFO *FileInfo;\r
// Create the directory to create the file in\r
//\r
FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);\r
- if (FileName == NULL) {\r
+ if (FileNameCopy == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
PathCleanUpDirectories (FileNameCopy);\r
Status = gEfiShellProtocol->OpenFileByName(FileName,\r
FileHandle,\r
OpenMode);\r
- if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (mUnicodeCollationProtocol == NULL) {\r
+ Status = gBS->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&mUnicodeCollationProtocol);\r
+ if (EFI_ERROR (Status)) {\r
+ gEfiShellProtocol->CloseFile (*FileHandle);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if ((mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NUL") != 0) &&\r
+ (mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NULL") != 0) &&\r
+ !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){\r
FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);\r
ASSERT(FileInfo != NULL);\r
FileInfo->Attribute = Attributes;\r
FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);\r
if (FilePath != NULL) {\r
return (ShellOpenFileByDevicePath(&FilePath,\r
- &DeviceHandle,\r
FileHandle,\r
OpenMode,\r
Attributes));\r
if (mEfiShellEnvironment2 != NULL) {\r
//\r
// Call EFI Shell version.\r
- // Due to oddity in the EFI shell we want to dereference the ParentHandle here\r
//\r
- CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,\r
+ // Due to an unfixable bug in the EdkShell implementation, we must\r
+ // dereference "ParentHandle" here:\r
+ //\r
+ // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol,\r
+ // identified by gEfiShellEnvironment2Guid.\r
+ // 2. The Execute() member function takes "ParentImageHandle" as first\r
+ // parameter, with type (EFI_HANDLE*).\r
+ // 3. In the EdkShell implementation, SEnvExecute() implements the\r
+ // Execute() member function. It passes "ParentImageHandle" correctly to\r
+ // SEnvDoExecute().\r
+ // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly --\r
+ // without de-referencing -- to the HandleProtocol() boot service.\r
+ // 5. But HandleProtocol() takes an EFI_HANDLE.\r
+ //\r
+ // Therefore we must\r
+ // - de-reference "ParentHandle" here, to mask the bug in\r
+ // SEnvDoExecute(), and\r
+ // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*).\r
+ //\r
+ CmdStatus = (mEfiShellEnvironment2->Execute((EFI_HANDLE *)*ParentHandle,\r
CommandLine,\r
Output));\r
//\r
@retval the resultant head of the double linked new format list;\r
**/\r
LIST_ENTRY*\r
-EFIAPI\r
InternalShellConvertFileListType (\r
IN LIST_ENTRY *FileList,\r
IN OUT LIST_ENTRY *ListHead\r
@retval FALSE the Parameter was not found. Type is not valid.\r
**/\r
BOOLEAN\r
-EFIAPI\r
InternalIsOnCheckList (\r
IN CONST CHAR16 *Name,\r
IN CONST SHELL_PARAM_ITEM *CheckList,\r
@retval FALSE the Parameter not a flag.\r
**/\r
BOOLEAN\r
-EFIAPI\r
InternalIsFlag (\r
IN CONST CHAR16 *Name,\r
IN CONST BOOLEAN AlwaysAllowNumbers,\r
ProblemParam if provided.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalCommandLineParse (\r
IN CONST SHELL_PARAM_ITEM *CheckList,\r
OUT LIST_ENTRY **CheckPackage,\r
UINTN Count;\r
CONST CHAR16 *TempPointer;\r
UINTN CurrentValueSize;\r
+ CHAR16 *NewValue;\r
\r
CurrentItemPackage = NULL;\r
GetItemValue = 0;\r
// get the item VALUE for a previous flag\r
//\r
CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
- CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
- ASSERT(CurrentItemPackage->Value != NULL);\r
+ NewValue = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
+ if (NewValue == NULL) {\r
+ SHELL_FREE_NON_NULL (CurrentItemPackage->Value);\r
+ SHELL_FREE_NON_NULL (CurrentItemPackage);\r
+ ShellCommandLineFreeVarList (*CheckPackage);\r
+ *CheckPackage = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CurrentItemPackage->Value = NewValue;\r
if (ValueSize == 0) {\r
- StrCpyS( CurrentItemPackage->Value, \r
- CurrentValueSize/sizeof(CHAR16), \r
+ StrCpyS( CurrentItemPackage->Value,\r
+ CurrentValueSize/sizeof(CHAR16),\r
Argv[LoopCounter]\r
);\r
} else {\r
- StrCatS( CurrentItemPackage->Value, \r
- CurrentValueSize/sizeof(CHAR16), \r
+ StrCatS( CurrentItemPackage->Value,\r
+ CurrentValueSize/sizeof(CHAR16),\r
L" "\r
);\r
- StrCatS( CurrentItemPackage->Value, \r
- CurrentValueSize/sizeof(CHAR16), \r
+ StrCatS( CurrentItemPackage->Value,\r
+ CurrentValueSize/sizeof(CHAR16),\r
Argv[LoopCounter]\r
);\r
}\r
ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
- \r
+\r
GetItemValue--;\r
if (GetItemValue == 0) {\r
InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
@retval !EFI_SUCCESS The operation failed.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalPrintTo (\r
IN CONST CHAR16 *String\r
)\r
return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));\r
}\r
if (mEfiShellInterface != NULL) {\r
- if (mEfiShellInterface->RedirArgc == 0) { \r
+ if (mEfiShellInterface->RedirArgc == 0) {\r
//\r
// Divide in half for old shell. Must be string length not size.\r
- // \r
+ //\r
Size /=2; // Divide in half only when no redirection.\r
}\r
return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));\r
@return EFI_DEVICE_ERROR The console device reported an error.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalShellPrintWorker(\r
IN INT32 Col OPTIONAL,\r
IN INT32 Row OPTIONAL,\r
// update the attribute\r
//\r
if (ResumeLocation != NULL) {\r
- if (*(ResumeLocation-1) == L'^') {\r
+ if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) {\r
//\r
// Move cursor back 1 position to overwrite the ^\r
//\r
gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
break;\r
case (L'B'):\r
- gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
break;\r
case (L'V'):\r
- gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
break;\r
default:\r
//\r
IN INT32 Row OPTIONAL,\r
IN CONST CHAR8 *Language OPTIONAL,\r
IN CONST EFI_STRING_ID HiiFormatStringId,\r
- IN CONST EFI_HANDLE HiiFormatHandle,\r
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,\r
...\r
)\r
{\r
CHAR16 *HiiFormatString;\r
EFI_STATUS RetVal;\r
\r
+ RetVal = EFI_DEVICE_ERROR;\r
+\r
VA_START (Marker, HiiFormatHandle);\r
HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);\r
- ASSERT(HiiFormatString != NULL);\r
-\r
- RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);\r
-\r
- SHELL_FREE_NON_NULL(HiiFormatString);\r
+ if (HiiFormatString != NULL) {\r
+ RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker);\r
+ SHELL_FREE_NON_NULL (HiiFormatString);\r
+ }\r
VA_END(Marker);\r
\r
return (RetVal);\r
@param[in] String String representation of a number.\r
\r
@return The unsigned integer result of the conversion.\r
- @retval (UINTN)(-1) An error occured.\r
+ @retval (UINTN)(-1) An error occurred.\r
**/\r
UINTN\r
EFIAPI\r
if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {\r
return ((UINTN)RetVal);\r
}\r
- \r
+\r
return ((UINTN)(-1));\r
}\r
\r
if (*Destination == NULL) {\r
return (NULL);\r
}\r
- \r
+\r
StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);\r
return *Destination;\r
}\r
Prompt the user and return the resultant answer to the requestor.\r
\r
This function will display the requested question on the shell prompt and then\r
- wait for an apropriate answer to be input from the console.\r
+ wait for an appropriate answer to be input from the console.\r
\r
if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue\r
or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.\r
if (Type != ShellPromptResponseTypeFreeform) {\r
Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));\r
if (Resp == NULL) {\r
+ if (Response != NULL) {\r
+ *Response = NULL;\r
+ }\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
}\r
break;\r
}\r
}\r
- break; case ShellPromptResponseTypeYesNoAllCancel:\r
+ break;\r
+ case ShellPromptResponseTypeYesNoAllCancel:\r
if (Prompt != NULL) {\r
ShellPrintEx(-1, -1, L"%s", Prompt);\r
}\r
if (EFI_ERROR(Status)) {\r
break;\r
}\r
- ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
+\r
+ if (Key.UnicodeChar <= 127 && Key.UnicodeChar >= 32) {\r
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);\r
+ }\r
+\r
switch (Key.UnicodeChar) {\r
case L'Y':\r
case L'y':\r
*Response = Resp;\r
} else if (Buffer != NULL) {\r
*Response = Buffer;\r
+ } else {\r
+ *Response = NULL;\r
}\r
} else {\r
if (Resp != NULL) {\r
ShellPromptForResponseHii (\r
IN SHELL_PROMPT_REQUEST_TYPE Type,\r
IN CONST EFI_STRING_ID HiiFormatStringId,\r
- IN CONST EFI_HANDLE HiiFormatHandle,\r
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,\r
IN OUT VOID **Response\r
)\r
{\r
@retval FALSE There is a non-numeric character.\r
**/\r
BOOLEAN\r
-EFIAPI\r
InternalShellIsHexOrDecimalNumber (\r
IN CONST CHAR16 *String,\r
IN CONST BOOLEAN ForceHex,\r
)\r
{\r
BOOLEAN Hex;\r
+ BOOLEAN LeadingZero;\r
+\r
+ if (String == NULL) {\r
+ return FALSE;\r
+ }\r
\r
//\r
// chop off a single negative sign\r
//\r
- if (String != NULL && *String == L'-') {\r
+ if (*String == L'-') {\r
String++;\r
}\r
\r
- if (String == NULL) {\r
- return (FALSE);\r
+ if (*String == CHAR_NULL) {\r
+ return FALSE;\r
}\r
\r
//\r
// chop leading zeroes\r
//\r
- while(String != NULL && *String == L'0'){\r
+ LeadingZero = FALSE;\r
+ while(*String == L'0'){\r
String++;\r
+ LeadingZero = TRUE;\r
}\r
//\r
// allow '0x' or '0X', but not 'x' or 'X'\r
//\r
- if (String != NULL && (*String == L'x' || *String == L'X')) {\r
- if (*(String-1) != L'0') {\r
+ if (*String == L'x' || *String == L'X') {\r
+ if (!LeadingZero) {\r
//\r
// we got an x without a preceeding 0\r
//\r
//\r
// loop through the remaining characters and use the lib function\r
//\r
- for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){\r
+ for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){\r
if (TimeNumbers && (String[0] == L':')) {\r
continue;\r
}\r
return (EFI_SUCCESS);\r
}\r
\r
-/**\r
- Convert a Unicode character to upper case only if\r
- it maps to a valid small-case ASCII character.\r
-\r
- This internal function only deal with Unicode character\r
- which maps to a valid small-case ASCII character, i.e.\r
- L'a' to L'z'. For other Unicode character, the input character\r
- is returned directly.\r
-\r
- @param Char The character to convert.\r
-\r
- @retval LowerCharacter If the Char is with range L'a' to L'z'.\r
- @retval Unchanged Otherwise.\r
-\r
-**/\r
-CHAR16\r
-EFIAPI\r
-InternalShellCharToUpper (\r
- IN CHAR16 Char\r
- )\r
-{\r
- if (Char >= L'a' && Char <= L'z') {\r
- return (CHAR16) (Char - (L'a' - L'A'));\r
- }\r
-\r
- return Char;\r
-}\r
-\r
/**\r
Convert a Unicode character to numerical value.\r
\r
\r
**/\r
UINTN\r
-EFIAPI\r
InternalShellHexCharToUintn (\r
IN CHAR16 Char\r
)\r
return Char - L'0';\r
}\r
\r
- return (UINTN) (10 + InternalShellCharToUpper (Char) - L'A');\r
+ return (10 + CharToUpper (Char) - L'A');\r
}\r
\r
/**\r
\r
@retval EFI_SUCCESS The conversion was successful.\r
@retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.\r
- @retval EFI_DEVICE_ERROR An overflow occured.\r
+ @retval EFI_DEVICE_ERROR An overflow occurred.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalShellStrHexToUint64 (\r
IN CONST CHAR16 *String,\r
OUT UINT64 *Value,\r
String++;\r
}\r
\r
- if (InternalShellCharToUpper (*String) == L'X') {\r
+ if (CharToUpper (*String) == L'X') {\r
if (*(String - 1) != L'0') {\r
return 0;\r
}\r
\r
@retval EFI_SUCCESS The conversion was successful.\r
@retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.\r
- @retval EFI_DEVICE_ERROR An overflow occured.\r
+ @retval EFI_DEVICE_ERROR An overflow occurred.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalShellStrDecimalToUint64 (\r
IN CONST CHAR16 *String,\r
OUT UINT64 *Value,\r
Result = 0;\r
\r
//\r
- // Stop upon space if requested \r
+ // Stop upon space if requested\r
// (if the whole value was 0)\r
//\r
if (StopAtSpace && *String == L' ') {\r
Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);\r
\r
}\r
+ if (Status == EFI_END_OF_FILE && RetVal != NULL && *RetVal != CHAR_NULL) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
if (EFI_ERROR(Status) && (RetVal != NULL)) {\r
FreePool(RetVal);\r
RetVal = NULL;\r
If the position upon start is 0, then the Ascii Boolean will be set. This should be\r
maintained and not changed for all operations with the same file.\r
\r
+ NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ\r
+ IS IN ASCII FORMAT.\r
+\r
@param[in] Handle SHELL_FILE_HANDLE to read from.\r
- @param[in, out] Buffer The pointer to buffer to read into.\r
- @param[in, out] Size The pointer to number of bytes in Buffer.\r
+ @param[in, out] Buffer The pointer to buffer to read into. If this function\r
+ returns EFI_SUCCESS, then on output Buffer will\r
+ contain a UCS2 string, even if the file being\r
+ read is ASCII.\r
+ @param[in, out] Size On input, pointer to number of bytes in Buffer.\r
+ On output, unchanged unless Buffer is too small\r
+ to contain the next line of the file. In that\r
+ case Size is set to the number of bytes needed\r
+ to hold the next line of the file (as a UCS2\r
+ string, even if it is an ASCII file).\r
@param[in] Truncate If the buffer is large enough, this has no effect.\r
If the buffer is is too small and Truncate is TRUE,\r
the line will be truncated.\r
//\r
// if we have space save it...\r
//\r
- if ((CountSoFar + 1) * CharSize < *Size){\r
+ if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
ASSERT(Buffer != NULL);\r
- if (*Ascii) {\r
- ((CHAR8*)Buffer)[CountSoFar] = (CHAR8) CharBuffer;\r
- ((CHAR8*)Buffer)[CountSoFar+1] = '\0';\r
- }\r
- else {\r
- ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
- ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
- }\r
+ ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
+ ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
}\r
}\r
\r
//\r
// if we ran out of space tell when...\r
//\r
- if (Status != EFI_END_OF_FILE){\r
- if ((CountSoFar + 1) * CharSize > *Size){\r
- *Size = (CountSoFar + 1) * CharSize;\r
- if (!Truncate) {\r
- gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
- } else {\r
- DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
- }\r
- return (EFI_BUFFER_TOO_SMALL);\r
- }\r
-\r
- if (*Ascii) {\r
- if (CountSoFar && ((CHAR8*)Buffer)[CountSoFar - 1] == '\r') {\r
- ((CHAR8*)Buffer)[CountSoFar - 1] = '\0';\r
- }\r
- }\r
- else {\r
- if (CountSoFar && Buffer[CountSoFar - 1] == L'\r') {\r
- Buffer[CountSoFar - 1] = CHAR_NULL;\r
- }\r
+ if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
+ *Size = (CountSoFar+1)*sizeof(CHAR16);\r
+ if (!Truncate) {\r
+ gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
+ } else {\r
+ DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
}\r
+ return (EFI_BUFFER_TOO_SMALL);\r
+ }\r
+ while(Buffer[StrLen(Buffer)-1] == L'\r') {\r
+ Buffer[StrLen(Buffer)-1] = CHAR_NULL;\r
}\r
\r
return (Status);\r
\r
@param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.\r
@param[in] SectionToGetHelpOn Pointer to the section specifier(s).\r
- @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints \r
+ @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints\r
the help content only.\r
@retval EFI_DEVICE_ERROR The help data format was incorrect.\r
@retval EFI_NOT_FOUND The help data could not be found.\r
IN BOOLEAN PrintCommandText\r
)\r
{\r
- EFI_STATUS Status;\r
- CHAR16 *OutText;\r
- \r
- OutText = NULL;\r
- \r
+ EFI_STATUS Status;\r
+ CHAR16 *OutText;\r
+\r
+ OutText = NULL;\r
+\r
//\r
// Get the string to print based\r
//\r
- Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);\r
- \r
+ Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);\r
+\r
//\r
// make sure we got a valid string\r
//\r
if (EFI_ERROR(Status)){\r
return Status;\r
- } \r
+ }\r
if (OutText == NULL || StrLen(OutText) == 0) {\r
- return EFI_NOT_FOUND; \r
- }\r
- \r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
//\r
// Chop off trailing stuff we dont need\r
//\r
while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {\r
OutText[StrLen(OutText)-1] = CHAR_NULL;\r
}\r
- \r
+\r
//\r
// Print this out to the console\r
//\r
} else {\r
ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);\r
}\r
- \r
+\r
SHELL_FREE_NON_NULL(OutText);\r
\r
- return EFI_SUCCESS;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
Function to delete a file by name\r
- \r
+\r
@param[in] FileName Pointer to file name to delete.\r
- \r
+\r
@retval EFI_SUCCESS the file was deleted sucessfully\r
@retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not\r
deleted\r
{\r
EFI_STATUS Status;\r
SHELL_FILE_HANDLE FileHandle;\r
- \r
+\r
Status = ShellFileExists(FileName);\r
- \r
+\r
if (Status == EFI_SUCCESS){\r
Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);\r
if (Status == EFI_SUCCESS){\r
Status = ShellDeleteFile(&FileHandle);\r
}\r
- } \r
+ }\r
\r
return(Status);\r
- \r
+\r
}\r
\r
/**\r
Cleans off all the quotes in the string.\r
\r
@param[in] OriginalString pointer to the string to be cleaned.\r
- @param[out] CleanString The new string with all quotes removed. \r
- Memory allocated in the function and free \r
+ @param[out] CleanString The new string with all quotes removed.\r
+ Memory allocated in the function and free\r
by caller.\r
\r
@retval EFI_SUCCESS The operation was successful.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
InternalShellStripQuotes (\r
IN CONST CHAR16 *OriginalString,\r
OUT CHAR16 **CleanString\r
)\r
{\r
CHAR16 *Walker;\r
- \r
+\r
if (OriginalString == NULL || CleanString == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r