summaryrefslogtreecommitdiff
path: root/ShellPkg/Library/UefiShellLib
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /ShellPkg/Library/UefiShellLib
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'ShellPkg/Library/UefiShellLib')
-rw-r--r--ShellPkg/Library/UefiShellLib/UefiShellLib.c9184
-rw-r--r--ShellPkg/Library/UefiShellLib/UefiShellLib.h176
-rw-r--r--ShellPkg/Library/UefiShellLib/UefiShellLib.inf130
3 files changed, 4745 insertions, 4745 deletions
diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.c b/ShellPkg/Library/UefiShellLib/UefiShellLib.c
index 93e36197b2..f75903663e 100644
--- a/ShellPkg/Library/UefiShellLib/UefiShellLib.c
+++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.c
@@ -1,4592 +1,4592 @@
-/** @file
- Provides interface to shell functionality for shell commands and applications.
-
- (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
- Copyright 2016-2018 Dell Technologies.<BR>
- Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (C) 2023, Apple Inc. All rights reserved.<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include "UefiShellLib.h"
-#include <Library/SortLib.h>
-#include <Library/BaseLib.h>
-
-//
-// globals...
-//
-SHELL_PARAM_ITEM EmptyParamList[] = {
- { NULL, TypeMax }
-};
-SHELL_PARAM_ITEM SfoParamList[] = {
- { L"-sfo", TypeFlag },
- { NULL, TypeMax }
-};
-EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
-EFI_SHELL_INTERFACE *mEfiShellInterface;
-EFI_SHELL_PROTOCOL *gEfiShellProtocol;
-EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
-EFI_HANDLE mEfiShellEnvironment2Handle;
-FILE_HANDLE_FUNCTION_MAP FileFunctionMap;
-EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationProtocol;
-
-/**
- Return a clean, fully-qualified version of an input path. If the return value
- is non-NULL the caller must free the memory when it is no longer needed.
-
- If asserts are disabled, and if the input parameter is NULL, NULL is returned.
-
- If there is not enough memory available to create the fully-qualified path or
- a copy of the input path, NULL is returned.
-
- If there is no working directory, a clean copy of Path is returned.
-
- Otherwise, the current file system or working directory (as appropriate) is
- prepended to Path and the resulting path is cleaned and returned.
-
- NOTE: If the input path is an empty string, then the current working directory
- (if it exists) is returned. In other words, an empty input path is treated
- exactly the same as ".".
-
- @param[in] Path A pointer to some file or directory path.
-
- @retval NULL The input path is NULL or out of memory.
-
- @retval non-NULL A pointer to a clean, fully-qualified version of Path.
- If there is no working directory, then a pointer to a
- clean, but not necessarily fully-qualified version of
- Path. The caller must free this memory when it is no
- longer needed.
-**/
-CHAR16 *
-EFIAPI
-FullyQualifyPath (
- IN CONST CHAR16 *Path
- )
-{
- CONST CHAR16 *WorkingPath;
- CONST CHAR16 *InputPath;
- CHAR16 *CharPtr;
- CHAR16 *InputFileSystem;
- UINTN FileSystemCharCount;
- CHAR16 *FullyQualifiedPath;
- UINTN Size;
-
- FullyQualifiedPath = NULL;
-
- ASSERT (Path != NULL);
- //
- // Handle erroneous input when asserts are disabled.
- //
- if (Path == NULL) {
- return NULL;
- }
-
- //
- // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,
- // we have to consider the file system part separately from the "path" part.
- // If there is a file system in the path, we have to get the current working
- // directory for that file system. Then we need to use the part of the path
- // following the ":". If a path does not contain ":", we use it as given.
- //
- InputPath = StrStr (Path, L":");
- if (InputPath != NULL) {
- InputPath++;
- FileSystemCharCount = ((UINTN)InputPath - (UINTN)Path + sizeof (CHAR16)) / sizeof (CHAR16);
- InputFileSystem = AllocateCopyPool (FileSystemCharCount * sizeof (CHAR16), Path);
- if (InputFileSystem != NULL) {
- InputFileSystem[FileSystemCharCount - 1] = CHAR_NULL;
- }
-
- WorkingPath = ShellGetCurrentDir (InputFileSystem);
- SHELL_FREE_NON_NULL (InputFileSystem);
- } else {
- InputPath = Path;
- WorkingPath = ShellGetEnvironmentVariable (L"cwd");
- }
-
- if (WorkingPath == NULL) {
- //
- // With no working directory, all we can do is copy and clean the input path.
- //
- FullyQualifiedPath = AllocateCopyPool (StrSize (Path), Path);
- } else {
- //
- // Allocate space for both strings plus one more character.
- //
- Size = StrSize (WorkingPath) + StrSize (InputPath);
- FullyQualifiedPath = AllocateZeroPool (Size);
- if (FullyQualifiedPath == NULL) {
- //
- // Try to copy and clean just the input. No harm if not enough memory.
- //
- FullyQualifiedPath = AllocateCopyPool (StrSize (Path), Path);
- } else {
- if ((*InputPath == L'\\') || (*InputPath == L'/')) {
- //
- // Absolute path: start with the current working directory, then
- // truncate the new path after the file system part.
- //
- StrCpyS (FullyQualifiedPath, Size/sizeof (CHAR16), WorkingPath);
- CharPtr = StrStr (FullyQualifiedPath, L":");
- if (CharPtr != NULL) {
- *(CharPtr + 1) = CHAR_NULL;
- }
- } else {
- //
- // Relative path: start with the working directory and append "\".
- //
- StrCpyS (FullyQualifiedPath, Size/sizeof (CHAR16), WorkingPath);
- StrCatS (FullyQualifiedPath, Size/sizeof (CHAR16), L"\\");
- }
-
- //
- // Now append the absolute or relative path.
- //
- StrCatS (FullyQualifiedPath, Size/sizeof (CHAR16), InputPath);
- }
- }
-
- PathCleanUpDirectories (FullyQualifiedPath);
-
- return FullyQualifiedPath;
-}
-
-/**
- Check if a Unicode character is a hexadecimal character.
-
- This internal function checks if a Unicode character is a
- numeric character. The valid hexadecimal characters are
- L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
-
- @param Char The character to check against.
-
- @retval TRUE If the Char is a hexadecmial character.
- @retval FALSE If the Char is not a hexadecmial character.
-
-**/
-BOOLEAN
-EFIAPI
-ShellIsHexaDecimalDigitCharacter (
- IN CHAR16 Char
- )
-{
- return (BOOLEAN)((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
-}
-
-/**
- Check if a Unicode character is a decimal character.
-
- This internal function checks if a Unicode character is a
- decimal character. The valid characters are
- L'0' to L'9'.
-
-
- @param Char The character to check against.
-
- @retval TRUE If the Char is a hexadecmial character.
- @retval FALSE If the Char is not a hexadecmial character.
-
-**/
-BOOLEAN
-EFIAPI
-ShellIsDecimalDigitCharacter (
- IN CHAR16 Char
- )
-{
- return (BOOLEAN)(Char >= L'0' && Char <= L'9');
-}
-
-/**
- Helper function to find ShellEnvironment2 for constructor.
-
- @param[in] ImageHandle A copy of the calling image's handle.
-
- @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
-**/
-EFI_STATUS
-ShellFindSE2 (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *Buffer;
- UINTN BufferSize;
- UINTN HandleIndex;
-
- BufferSize = 0;
- Buffer = NULL;
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiShellEnvironment2Guid,
- (VOID **)&mEfiShellEnvironment2,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- //
- // look for the mEfiShellEnvironment2 protocol at a higher level
- //
- if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))) {
- //
- // figure out how big of a buffer we need.
- //
- Status = gBS->LocateHandle (
- ByProtocol,
- &gEfiShellEnvironment2Guid,
- NULL, // ignored for ByProtocol
- &BufferSize,
- Buffer
- );
- //
- // maybe it's not there???
- //
- if (Status == EFI_BUFFER_TOO_SMALL) {
- Buffer = (EFI_HANDLE *)AllocateZeroPool (BufferSize);
- if (Buffer == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- Status = gBS->LocateHandle (
- ByProtocol,
- &gEfiShellEnvironment2Guid,
- NULL, // ignored for ByProtocol
- &BufferSize,
- Buffer
- );
- }
-
- if (!EFI_ERROR (Status) && (Buffer != NULL)) {
- //
- // now parse the list of returned handles
- //
- Status = EFI_NOT_FOUND;
- for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof (Buffer[0])); HandleIndex++) {
- Status = gBS->OpenProtocol (
- Buffer[HandleIndex],
- &gEfiShellEnvironment2Guid,
- (VOID **)&mEfiShellEnvironment2,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) {
- mEfiShellEnvironment2Handle = Buffer[HandleIndex];
- Status = EFI_SUCCESS;
- break;
- }
- }
- }
- }
-
- if (Buffer != NULL) {
- FreePool (Buffer);
- }
-
- return (Status);
-}
-
-/**
- Function to do most of the work of the constructor. Allows for calling
- multiple times without complete re-initialization.
-
- @param[in] ImageHandle A copy of the ImageHandle.
- @param[in] SystemTable A pointer to the SystemTable for the application.
-
- @retval EFI_SUCCESS The operationw as successful.
-**/
-EFI_STATUS
-ShellLibConstructorWorker (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- if (gEfiShellProtocol == NULL) {
- //
- // UEFI 2.0 shell interfaces (used preferentially)
- //
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiShellProtocolGuid,
- (VOID **)&gEfiShellProtocol,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- //
- // Search for the shell protocol
- //
- Status = gBS->LocateProtocol (
- &gEfiShellProtocolGuid,
- NULL,
- (VOID **)&gEfiShellProtocol
- );
- if (EFI_ERROR (Status)) {
- gEfiShellProtocol = NULL;
- }
- }
- }
-
- if (gEfiShellParametersProtocol == NULL) {
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiShellParametersProtocolGuid,
- (VOID **)&gEfiShellParametersProtocol,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- gEfiShellParametersProtocol = NULL;
- }
- }
-
- if (gEfiShellProtocol == NULL) {
- //
- // Moved to seperate function due to complexity
- //
- Status = ShellFindSE2 (ImageHandle);
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
- mEfiShellEnvironment2 = NULL;
- }
-
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiShellInterfaceGuid,
- (VOID **)&mEfiShellInterface,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- mEfiShellInterface = NULL;
- }
- }
-
- //
- // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol
- // or UEFI Shell's Shell protocol.
- // When ShellLib is linked to a driver producing DynamicCommand protocol,
- // ShellParameters protocol is set by DynamicCommand.Handler().
- //
- if (((mEfiShellEnvironment2 != NULL) && (mEfiShellInterface != NULL)) ||
- (gEfiShellProtocol != NULL)
- )
- {
- if (gEfiShellProtocol != NULL) {
- FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;
- FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;
- FileFunctionMap.ReadFile = gEfiShellProtocol->ReadFile;
- FileFunctionMap.WriteFile = gEfiShellProtocol->WriteFile;
- FileFunctionMap.CloseFile = gEfiShellProtocol->CloseFile;
- FileFunctionMap.DeleteFile = gEfiShellProtocol->DeleteFile;
- FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition;
- FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition;
- FileFunctionMap.FlushFile = gEfiShellProtocol->FlushFile;
- FileFunctionMap.GetFileSize = gEfiShellProtocol->GetFileSize;
- } else {
- FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo;
- FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo;
- FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead;
- FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite;
- FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose;
- FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete;
- FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition;
- FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition;
- FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush;
- FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize;
- }
-
- return (EFI_SUCCESS);
- }
-
- return (EFI_NOT_FOUND);
-}
-
-/**
- Constructor for the Shell library.
-
- Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
-
- @param ImageHandle the image handle of the process
- @param SystemTable the EFI System Table pointer
-
- @retval EFI_SUCCESS the initialization was complete successfully
- @return others an error ocurred during initialization
-**/
-EFI_STATUS
-EFIAPI
-ShellLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- mEfiShellEnvironment2 = NULL;
- gEfiShellProtocol = NULL;
- gEfiShellParametersProtocol = NULL;
- mEfiShellInterface = NULL;
- mEfiShellEnvironment2Handle = NULL;
- mUnicodeCollationProtocol = NULL;
-
- //
- // verify that auto initialize is not set false
- //
- if (PcdGetBool (PcdShellLibAutoInitialize) == 0) {
- return (EFI_SUCCESS);
- }
-
- return (ShellLibConstructorWorker (ImageHandle, SystemTable));
-}
-
-/**
- Destructor for the library. free any resources.
-
- @param[in] ImageHandle A copy of the ImageHandle.
- @param[in] SystemTable A pointer to the SystemTable for the application.
-
- @retval EFI_SUCCESS The operation was successful.
- @return An error from the CloseProtocol function.
-**/
-EFI_STATUS
-EFIAPI
-ShellLibDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- if (mEfiShellEnvironment2 != NULL) {
- Status = gBS->CloseProtocol (
- mEfiShellEnvironment2Handle == NULL ? ImageHandle : mEfiShellEnvironment2Handle,
- &gEfiShellEnvironment2Guid,
- ImageHandle,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- mEfiShellEnvironment2 = NULL;
- mEfiShellEnvironment2Handle = NULL;
- }
- }
-
- if (mEfiShellInterface != NULL) {
- Status = gBS->CloseProtocol (
- ImageHandle,
- &gEfiShellInterfaceGuid,
- ImageHandle,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- mEfiShellInterface = NULL;
- }
- }
-
- if (gEfiShellProtocol != NULL) {
- Status = gBS->CloseProtocol (
- ImageHandle,
- &gEfiShellProtocolGuid,
- ImageHandle,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- gEfiShellProtocol = NULL;
- }
- }
-
- if (gEfiShellParametersProtocol != NULL) {
- Status = gBS->CloseProtocol (
- ImageHandle,
- &gEfiShellParametersProtocolGuid,
- ImageHandle,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- gEfiShellParametersProtocol = NULL;
- }
- }
-
- return (EFI_SUCCESS);
-}
-
-/**
- This function causes the shell library to initialize itself. If the shell library
- is already initialized it will de-initialize all the current protocol pointers and
- re-populate them again.
-
- When the library is used with PcdShellLibAutoInitialize set to true this function
- will return EFI_SUCCESS and perform no actions.
-
- This function is intended for internal access for shell commands only.
-
- @retval EFI_SUCCESS the initialization was complete successfully
-
-**/
-EFI_STATUS
-EFIAPI
-ShellInitialize (
- VOID
- )
-{
- EFI_STATUS Status;
-
- //
- // if auto initialize is not false then skip
- //
- if (PcdGetBool (PcdShellLibAutoInitialize) != 0) {
- return (EFI_SUCCESS);
- }
-
- //
- // deinit the current stuff
- //
- Status = ShellLibDestructor (gImageHandle, gST);
- ASSERT_EFI_ERROR (Status);
-
- //
- // init the new stuff
- //
- return (ShellLibConstructorWorker (gImageHandle, gST));
-}
-
-/**
- This function will retrieve the information about the file for the handle
- specified and store it in allocated pool memory.
-
- This function allocates a buffer to store the file's information. It is the
- caller's responsibility to free the buffer
-
- @param FileHandle The file handle of the file for which information is
- being requested.
-
- @retval NULL information could not be retrieved.
-
- @return the information about the file
-**/
-EFI_FILE_INFO *
-EFIAPI
-ShellGetFileInfo (
- IN SHELL_FILE_HANDLE FileHandle
- )
-{
- return (FileFunctionMap.GetFileInfo (FileHandle));
-}
-
-/**
- This function sets the information about the file for the opened handle
- specified.
-
- @param[in] FileHandle The file handle of the file for which information
- is being set.
-
- @param[in] FileInfo The information to set.
-
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
- @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_VOLUME_FULL The volume is full.
-**/
-EFI_STATUS
-EFIAPI
-ShellSetFileInfo (
- IN SHELL_FILE_HANDLE FileHandle,
- IN EFI_FILE_INFO *FileInfo
- )
-{
- return (FileFunctionMap.SetFileInfo (FileHandle, FileInfo));
-}
-
-/**
-This function will open a file or directory referenced by DevicePath.
-
-This function opens a file with the open mode according to the file path. The
-Attributes is valid only for EFI_FILE_MODE_CREATE.
-
-@param FilePath on input the device path to the file. On output
- the remaining device path.
-@param FileHandle pointer to the file handle.
-@param OpenMode the mode to open the file with.
-@param Attributes the file's file attributes.
-
-@retval EFI_SUCCESS The information was set.
-@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-@retval EFI_UNSUPPORTED Could not open the file path.
-@retval EFI_NOT_FOUND The specified file could not be found on the
- device or the file system could not be found on
- the device.
-@retval EFI_NO_MEDIA The device has no medium.
-@retval EFI_MEDIA_CHANGED The device has a different medium in it or the
- medium is no longer supported.
-@retval EFI_DEVICE_ERROR The device reported an error.
-@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
-@retval EFI_WRITE_PROTECTED The file or medium is write protected.
-@retval EFI_ACCESS_DENIED The file was opened read only.
-@retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
- file.
-@retval EFI_VOLUME_FULL The volume is full.
-**/
-EFI_STATUS
-EFIAPI
-ShellOpenFileByDevicePath (
- IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
- OUT SHELL_FILE_HANDLE *FileHandle,
- IN UINT64 OpenMode,
- IN UINT64 Attributes
- )
-{
- CHAR16 *FileName;
- EFI_STATUS Status;
- EFI_FILE_PROTOCOL *File;
-
- if ((FilePath == NULL) || (FileHandle == NULL)) {
- return (EFI_INVALID_PARAMETER);
- }
-
- //
- // which shell interface should we use
- //
- if (gEfiShellProtocol != NULL) {
- //
- // use UEFI Shell 2.0 method.
- //
- FileName = gEfiShellProtocol->GetFilePathFromDevicePath (*FilePath);
- if (FileName == NULL) {
- return (EFI_INVALID_PARAMETER);
- }
-
- Status = ShellOpenFileByName (FileName, FileHandle, OpenMode, Attributes);
- FreePool (FileName);
- return (Status);
- }
-
- //
- // use old shell method.
- //
- Status = EfiOpenFileByDevicePath (FilePath, &File, OpenMode, Attributes);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
- //
- *FileHandle = (VOID *)File;
- return (EFI_SUCCESS);
-}
-
-/**
- This function will open a file or directory referenced by filename.
-
- If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
- otherwise, the Filehandle is NULL. The Attributes is valid only for
- EFI_FILE_MODE_CREATE.
-
- if FileName is NULL then ASSERT()
-
- @param FileName pointer to file name
- @param FileHandle pointer to the file handle.
- @param OpenMode the mode to open the file with.
- @param Attributes the file's file attributes.
-
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED Could not open the file path.
- @retval EFI_NOT_FOUND The specified file could not be found on the
- device or the file system could not be found
- on the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
- medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
- file.
- @retval EFI_VOLUME_FULL The volume is full.
-**/
-EFI_STATUS
-EFIAPI
-ShellOpenFileByName (
- IN CONST CHAR16 *FileName,
- OUT SHELL_FILE_HANDLE *FileHandle,
- IN UINT64 OpenMode,
- IN UINT64 Attributes
- )
-{
- EFI_DEVICE_PATH_PROTOCOL *FilePath;
- EFI_STATUS Status;
- EFI_FILE_INFO *FileInfo;
- CHAR16 *FileNameCopy;
- EFI_STATUS Status2;
-
- //
- // ASSERT if FileName is NULL
- //
- ASSERT (FileName != NULL);
-
- if (FileName == NULL) {
- return (EFI_INVALID_PARAMETER);
- }
-
- if (gEfiShellProtocol != NULL) {
- if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
- //
- // Create only a directory
- //
- if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
- return ShellCreateDirectory (FileName, FileHandle);
- }
-
- //
- // Create the directory to create the file in
- //
- FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
- if (FileNameCopy == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- PathCleanUpDirectories (FileNameCopy);
- if (PathRemoveLastItem (FileNameCopy)) {
- if (!EFI_ERROR (ShellCreateDirectory (FileNameCopy, FileHandle))) {
- ShellCloseFile (FileHandle);
- }
- }
-
- SHELL_FREE_NON_NULL (FileNameCopy);
- }
-
- //
- // Use UEFI Shell 2.0 method to create the file
- //
- Status = gEfiShellProtocol->OpenFileByName (
- FileName,
- FileHandle,
- OpenMode
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (mUnicodeCollationProtocol == NULL) {
- Status = gBS->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **)&mUnicodeCollationProtocol);
- if (EFI_ERROR (Status)) {
- gEfiShellProtocol->CloseFile (*FileHandle);
- return Status;
- }
- }
-
- if ((mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16 *)FileName, L"NUL") != 0) &&
- (mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16 *)FileName, L"NULL") != 0) &&
- !EFI_ERROR (Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0))
- {
- FileInfo = FileFunctionMap.GetFileInfo (*FileHandle);
- ASSERT (FileInfo != NULL);
- FileInfo->Attribute = Attributes;
- Status2 = FileFunctionMap.SetFileInfo (*FileHandle, FileInfo);
- FreePool (FileInfo);
- if (EFI_ERROR (Status2)) {
- gEfiShellProtocol->CloseFile (*FileHandle);
- }
-
- Status = Status2;
- }
-
- return (Status);
- }
-
- //
- // Using EFI Shell version
- // this means convert name to path and call that function
- // since this will use EFI method again that will open it.
- //
- ASSERT (mEfiShellEnvironment2 != NULL);
- FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16 *)FileName);
- if (FilePath != NULL) {
- return (ShellOpenFileByDevicePath (
- &FilePath,
- FileHandle,
- OpenMode,
- Attributes
- ));
- }
-
- return (EFI_DEVICE_ERROR);
-}
-
-/**
- This function create a directory
-
- If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
- otherwise, the Filehandle is NULL. If the directory already existed, this
- function opens the existing directory.
-
- @param DirectoryName pointer to directory name
- @param FileHandle pointer to the file handle.
-
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED Could not open the file path.
- @retval EFI_NOT_FOUND The specified file could not be found on the
- device or the file system could not be found
- on the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
- medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
- file.
- @retval EFI_VOLUME_FULL The volume is full.
- @sa ShellOpenFileByName
-**/
-EFI_STATUS
-EFIAPI
-ShellCreateDirectory (
- IN CONST CHAR16 *DirectoryName,
- OUT SHELL_FILE_HANDLE *FileHandle
- )
-{
- if (gEfiShellProtocol != NULL) {
- //
- // Use UEFI Shell 2.0 method
- //
- return (gEfiShellProtocol->CreateFile (
- DirectoryName,
- EFI_FILE_DIRECTORY,
- FileHandle
- ));
- } else {
- return (ShellOpenFileByName (
- DirectoryName,
- FileHandle,
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
- EFI_FILE_DIRECTORY
- ));
- }
-}
-
-/**
- This function reads information from an opened file.
-
- If FileHandle is not a directory, the function reads the requested number of
- bytes from the file at the file's current position and returns them in Buffer.
- If the read goes beyond the end of the file, the read length is truncated to the
- end of the file. The file's current position is increased by the number of bytes
- returned. If FileHandle is a directory, the function reads the directory entry
- at the file's current position and returns the entry in Buffer. If the Buffer
- is not large enough to hold the current directory entry, then
- EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
- BufferSize is set to be the size of the buffer needed to read the entry. On
- success, the current position is updated to the next directory entry. If there
- are no more directory entries, the read returns a zero-length buffer.
- EFI_FILE_INFO is the structure returned as the directory entry.
-
- @param FileHandle the opened file handle
- @param BufferSize on input the size of buffer in bytes. on return
- the number of bytes written.
- @param Buffer the buffer to put read data into.
-
- @retval EFI_SUCCESS Data was read.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
- size.
-
-**/
-EFI_STATUS
-EFIAPI
-ShellReadFile (
- IN SHELL_FILE_HANDLE FileHandle,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
-{
- return (FileFunctionMap.ReadFile (FileHandle, BufferSize, Buffer));
-}
-
-/**
- Write data to a file.
-
- This function writes the specified number of bytes to the file at the current
- file position. The current file position is advanced the actual number of bytes
- written, which is returned in BufferSize. Partial writes only occur when there
- has been a data error during the write attempt (such as "volume space full").
- The file is automatically grown to hold the data if required. Direct writes to
- opened directories are not supported.
-
- @param FileHandle The opened file for writing
- @param BufferSize on input the number of bytes in Buffer. On output
- the number of bytes written.
- @param Buffer the buffer containing data to write is stored.
-
- @retval EFI_SUCCESS Data was written.
- @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The device is write-protected.
- @retval EFI_ACCESS_DENIED The file was open for read only.
- @retval EFI_VOLUME_FULL The volume is full.
-**/
-EFI_STATUS
-EFIAPI
-ShellWriteFile (
- IN SHELL_FILE_HANDLE FileHandle,
- IN OUT UINTN *BufferSize,
- IN VOID *Buffer
- )
-{
- return (FileFunctionMap.WriteFile (FileHandle, BufferSize, Buffer));
-}
-
-/**
- Close an open file handle.
-
- This function closes a specified file handle. All "dirty" cached file data is
- flushed to the device, and the file is closed. In all cases the handle is
- closed.
-
-@param FileHandle the file handle to close.
-
-@retval EFI_SUCCESS the file handle was closed successfully.
-**/
-EFI_STATUS
-EFIAPI
-ShellCloseFile (
- IN SHELL_FILE_HANDLE *FileHandle
- )
-{
- return (FileFunctionMap.CloseFile (*FileHandle));
-}
-
-/**
- Delete a file and close the handle
-
- This function closes and deletes a file. In all cases the file handle is closed.
- If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
- returned, but the handle is still closed.
-
- @param FileHandle the file handle to delete
-
- @retval EFI_SUCCESS the file was closed successfully
- @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
- deleted
- @retval INVALID_PARAMETER One of the parameters has an invalid value.
-**/
-EFI_STATUS
-EFIAPI
-ShellDeleteFile (
- IN SHELL_FILE_HANDLE *FileHandle
- )
-{
- return (FileFunctionMap.DeleteFile (*FileHandle));
-}
-
-/**
- Set the current position in a file.
-
- This function sets the current file position for the handle to the position
- supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
- absolute positioning is supported, and seeking past the end of the file is
- allowed (a subsequent write would grow the file). Seeking to position
- 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
- If FileHandle is a directory, the only position that may be set is zero. This
- has the effect of starting the read process of the directory entries over.
-
- @param FileHandle The file handle on which the position is being set
- @param Position Byte position from beginning of file
-
- @retval EFI_SUCCESS Operation completed successfully.
- @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
- directories.
- @retval INVALID_PARAMETER One of the parameters has an invalid value.
-**/
-EFI_STATUS
-EFIAPI
-ShellSetFilePosition (
- IN SHELL_FILE_HANDLE FileHandle,
- IN UINT64 Position
- )
-{
- return (FileFunctionMap.SetFilePosition (FileHandle, Position));
-}
-
-/**
- Gets a file's current position
-
- This function retrieves the current file position for the file handle. For
- directories, the current file position has no meaning outside of the file
- system driver and as such the operation is not supported. An error is returned
- if FileHandle is a directory.
-
- @param FileHandle The open file handle on which to get the position.
- @param Position Byte position from beginning of file.
-
- @retval EFI_SUCCESS the operation completed successfully.
- @retval INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED the request is not valid on directories.
-**/
-EFI_STATUS
-EFIAPI
-ShellGetFilePosition (
- IN SHELL_FILE_HANDLE FileHandle,
- OUT UINT64 *Position
- )
-{
- return (FileFunctionMap.GetFilePosition (FileHandle, Position));
-}
-
-/**
- Flushes data on a file
-
- This function flushes all modified data associated with a file to a device.
-
- @param FileHandle The file handle on which to flush data
-
- @retval EFI_SUCCESS The data was flushed.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened for read only.
-**/
-EFI_STATUS
-EFIAPI
-ShellFlushFile (
- IN SHELL_FILE_HANDLE FileHandle
- )
-{
- return (FileFunctionMap.FlushFile (FileHandle));
-}
-
-/** Retrieve first entry from a directory.
-
- This function takes an open directory handle and gets information from the
- first entry in the directory. A buffer is allocated to contain
- the information and a pointer to the buffer is returned in *Buffer. The
- caller can use ShellFindNextFile() to get subsequent directory entries.
-
- The buffer will be freed by ShellFindNextFile() when the last directory
- entry is read. Otherwise, the caller must free the buffer, using FreePool,
- when finished with it.
-
- @param[in] DirHandle The file handle of the directory to search.
- @param[out] Buffer The pointer to the buffer for the file's information.
-
- @retval EFI_SUCCESS Found the first file.
- @retval EFI_NOT_FOUND Cannot find the directory.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @return Others status of ShellGetFileInfo, ShellSetFilePosition,
- or ShellReadFile
-**/
-EFI_STATUS
-EFIAPI
-ShellFindFirstFile (
- IN SHELL_FILE_HANDLE DirHandle,
- OUT EFI_FILE_INFO **Buffer
- )
-{
- //
- // pass to file handle lib
- //
- return (FileHandleFindFirstFile (DirHandle, Buffer));
-}
-
-/** Retrieve next entries from a directory.
-
- To use this function, the caller must first call the ShellFindFirstFile()
- function to get the first directory entry. Subsequent directory entries are
- retrieved by using the ShellFindNextFile() function. This function can
- be called several times to get each entry from the directory. If the call of
- ShellFindNextFile() retrieved the last directory entry, the next call of
- this function will set *NoFile to TRUE and free the buffer.
-
- @param[in] DirHandle The file handle of the directory.
- @param[out] Buffer The pointer to buffer for file's information.
- @param[out] NoFile The pointer to boolean when last file is found.
-
- @retval EFI_SUCCESS Found the next file, or reached last file
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
-**/
-EFI_STATUS
-EFIAPI
-ShellFindNextFile (
- IN SHELL_FILE_HANDLE DirHandle,
- OUT EFI_FILE_INFO *Buffer,
- OUT BOOLEAN *NoFile
- )
-{
- //
- // pass to file handle lib
- //
- return (FileHandleFindNextFile (DirHandle, Buffer, NoFile));
-}
-
-/**
- Retrieve the size of a file.
-
- if FileHandle is NULL then ASSERT()
- if Size is NULL then ASSERT()
-
- This function extracts the file size info from the FileHandle's EFI_FILE_INFO
- data.
-
- @param FileHandle file handle from which size is retrieved
- @param Size pointer to size
-
- @retval EFI_SUCCESS operation was completed successfully
- @retval EFI_DEVICE_ERROR cannot access the file
-**/
-EFI_STATUS
-EFIAPI
-ShellGetFileSize (
- IN SHELL_FILE_HANDLE FileHandle,
- OUT UINT64 *Size
- )
-{
- return (FileFunctionMap.GetFileSize (FileHandle, Size));
-}
-
-/**
- Retrieves the status of the break execution flag
-
- this function is useful to check whether the application is being asked to halt by the shell.
-
- @retval TRUE the execution break is enabled
- @retval FALSE the execution break is not enabled
-**/
-BOOLEAN
-EFIAPI
-ShellGetExecutionBreakFlag (
- VOID
- )
-{
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- //
- // We are using UEFI Shell 2.0; see if the event has been triggered
- //
- if (gBS->CheckEvent (gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
- return (FALSE);
- }
-
- return (TRUE);
- }
-
- //
- // using EFI Shell; call the function to check
- //
- if (mEfiShellEnvironment2 != NULL) {
- return (mEfiShellEnvironment2->GetExecutionBreak ());
- }
-
- return (FALSE);
-}
-
-/**
- return the value of an environment variable
-
- this function gets the value of the environment variable set by the
- ShellSetEnvironmentVariable function
-
- @param EnvKey The key name of the environment variable.
-
- @retval NULL the named environment variable does not exist.
- @return != NULL pointer to the value of the environment variable
-**/
-CONST CHAR16 *
-EFIAPI
-ShellGetEnvironmentVariable (
- IN CONST CHAR16 *EnvKey
- )
-{
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- return (gEfiShellProtocol->GetEnv (EnvKey));
- }
-
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- return (mEfiShellEnvironment2->GetEnv ((CHAR16 *)EnvKey));
- }
-
- return NULL;
-}
-
-/**
- set the value of an environment variable
-
-This function changes the current value of the specified environment variable. If the
-environment variable exists and the Value is an empty string, then the environment
-variable is deleted. If the environment variable exists and the Value is not an empty
-string, then the value of the environment variable is changed. If the environment
-variable does not exist and the Value is an empty string, there is no action. If the
-environment variable does not exist and the Value is a non-empty string, then the
-environment variable is created and assigned the specified value.
-
- This is not supported pre-UEFI Shell 2.0.
-
- @param EnvKey The key name of the environment variable.
- @param EnvVal The Value of the environment variable
- @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
-
- @retval EFI_SUCCESS the operation was completed successfully
- @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
-**/
-EFI_STATUS
-EFIAPI
-ShellSetEnvironmentVariable (
- IN CONST CHAR16 *EnvKey,
- IN CONST CHAR16 *EnvVal,
- IN BOOLEAN Volatile
- )
-{
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- return (gEfiShellProtocol->SetEnv (EnvKey, EnvVal, Volatile));
- }
-
- //
- // This feature does not exist under EFI shell
- //
- return (EFI_UNSUPPORTED);
-}
-
-/**
- Cause the shell to parse and execute a command line.
-
- This function creates a nested instance of the shell and executes the specified
- command (CommandLine) with the specified environment (Environment). Upon return,
- the status code returned by the specified command is placed in StatusCode.
- If Environment is NULL, then the current environment is used and all changes made
- by the commands executed will be reflected in the current environment. If the
- Environment is non-NULL, then the changes made will be discarded.
- The CommandLine is executed from the current working directory on the current
- device.
-
- The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
- environment. The values pointed to by the parameters will be unchanged by the
- ShellExecute() function. The Output parameter has no effect in a
- UEFI Shell 2.0 environment.
-
- @param[in] ParentHandle The parent image starting the operation.
- @param[in] CommandLine The pointer to a NULL terminated command line.
- @param[in] Output True to display debug output. False to hide it.
- @param[in] EnvironmentVariables Optional pointer to array of environment variables
- in the form "x=y". If NULL, the current set is used.
- @param[out] Status The status of the run command line.
-
- @retval EFI_SUCCESS The operation completed successfully. Status
- contains the status code returned.
- @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
- @retval EFI_OUT_OF_RESOURCES Out of resources.
- @retval EFI_UNSUPPORTED The operation is not allowed.
-**/
-EFI_STATUS
-EFIAPI
-ShellExecute (
- IN EFI_HANDLE *ParentHandle,
- IN CHAR16 *CommandLine OPTIONAL,
- IN BOOLEAN Output OPTIONAL,
- IN CHAR16 **EnvironmentVariables OPTIONAL,
- OUT EFI_STATUS *Status OPTIONAL
- )
-{
- EFI_STATUS CmdStatus;
-
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- //
- // Call UEFI Shell 2.0 version (not using Output parameter)
- //
- return (gEfiShellProtocol->Execute (
- ParentHandle,
- CommandLine,
- EnvironmentVariables,
- Status
- ));
- }
-
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- //
- // Call EFI Shell version.
- //
- // Due to an unfixable bug in the EdkShell implementation, we must
- // dereference "ParentHandle" here:
- //
- // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol,
- // identified by gEfiShellEnvironment2Guid.
- // 2. The Execute() member function takes "ParentImageHandle" as first
- // parameter, with type (EFI_HANDLE*).
- // 3. In the EdkShell implementation, SEnvExecute() implements the
- // Execute() member function. It passes "ParentImageHandle" correctly to
- // SEnvDoExecute().
- // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly --
- // without de-referencing -- to the HandleProtocol() boot service.
- // 5. But HandleProtocol() takes an EFI_HANDLE.
- //
- // Therefore we must
- // - de-reference "ParentHandle" here, to mask the bug in
- // SEnvDoExecute(), and
- // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*).
- //
- CmdStatus = (mEfiShellEnvironment2->Execute (
- (EFI_HANDLE *)*ParentHandle,
- CommandLine,
- Output
- ));
- //
- // No Status output parameter so just use the returned status
- //
- if (Status != NULL) {
- *Status = CmdStatus;
- }
-
- //
- // If there was an error, we can't tell if it was from the command or from
- // the Execute() function, so we'll just assume the shell ran successfully
- // and the error came from the command.
- //
- return EFI_SUCCESS;
- }
-
- return (EFI_UNSUPPORTED);
-}
-
-/**
- Retreives the current directory path
-
- If the DeviceName is NULL, it returns the current device's current directory
- name. If the DeviceName is not NULL, it returns the current directory name
- on specified drive.
-
- Note that the current directory string should exclude the tailing backslash character.
-
- @param DeviceName the name of the drive to get directory on
-
- @retval NULL the directory does not exist
- @return != NULL the directory
-**/
-CONST CHAR16 *
-EFIAPI
-ShellGetCurrentDir (
- IN CHAR16 *CONST DeviceName OPTIONAL
- )
-{
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- return (gEfiShellProtocol->GetCurDir (DeviceName));
- }
-
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- return (mEfiShellEnvironment2->CurDir (DeviceName));
- }
-
- return (NULL);
-}
-
-/**
- sets (enabled or disabled) the page break mode
-
- when page break mode is enabled the screen will stop scrolling
- and wait for operator input before scrolling a subsequent screen.
-
- @param CurrentState TRUE to enable and FALSE to disable
-**/
-VOID
-EFIAPI
-ShellSetPageBreakMode (
- IN BOOLEAN CurrentState
- )
-{
- //
- // check for enabling
- //
- if (CurrentState != 0x00) {
- //
- // check for UEFI Shell 2.0
- //
- if (gEfiShellProtocol != NULL) {
- //
- // Enable with UEFI 2.0 Shell
- //
- gEfiShellProtocol->EnablePageBreak ();
- return;
- } else {
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- //
- // Enable with EFI Shell
- //
- mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
- return;
- }
- }
- } else {
- //
- // check for UEFI Shell 2.0
- //
- if (gEfiShellProtocol != NULL) {
- //
- // Disable with UEFI 2.0 Shell
- //
- gEfiShellProtocol->DisablePageBreak ();
- return;
- } else {
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- //
- // Disable with EFI Shell
- //
- mEfiShellEnvironment2->DisablePageBreak ();
- return;
- }
- }
- }
-}
-
-///
-/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
-/// This allows for the struct to be populated.
-///
-typedef struct {
- LIST_ENTRY Link;
- EFI_STATUS Status;
- CHAR16 *FullName;
- CHAR16 *FileName;
- SHELL_FILE_HANDLE Handle;
- EFI_FILE_INFO *Info;
-} EFI_SHELL_FILE_INFO_NO_CONST;
-
-/**
- Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
-
- if OldStyleFileList is NULL then ASSERT()
-
- this function will convert a SHELL_FILE_ARG based list into a callee allocated
- EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
- the ShellCloseFileMetaArg function.
-
- @param[in] FileList the EFI shell list type
- @param[in, out] ListHead the list to add to
-
- @retval the resultant head of the double linked new format list;
-**/
-LIST_ENTRY *
-InternalShellConvertFileListType (
- IN LIST_ENTRY *FileList,
- IN OUT LIST_ENTRY *ListHead
- )
-{
- SHELL_FILE_ARG *OldInfo;
- LIST_ENTRY *Link;
- EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;
-
- //
- // ASSERTs
- //
- ASSERT (FileList != NULL);
- ASSERT (ListHead != NULL);
-
- //
- // enumerate through each member of the old list and copy
- //
- for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {
- OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
- ASSERT (OldInfo != NULL);
-
- //
- // Skip ones that failed to open...
- //
- if (OldInfo->Status != EFI_SUCCESS) {
- continue;
- }
-
- //
- // make sure the old list was valid
- //
- ASSERT (OldInfo->Info != NULL);
- ASSERT (OldInfo->FullName != NULL);
- ASSERT (OldInfo->FileName != NULL);
-
- //
- // allocate a new EFI_SHELL_FILE_INFO object
- //
- NewInfo = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
- if (NewInfo == NULL) {
- ShellCloseFileMetaArg ((EFI_SHELL_FILE_INFO **)(&ListHead));
- ListHead = NULL;
- break;
- }
-
- //
- // copy the simple items
- //
- NewInfo->Handle = OldInfo->Handle;
- NewInfo->Status = OldInfo->Status;
-
- // old shell checks for 0 not NULL
- OldInfo->Handle = 0;
-
- //
- // allocate new space to copy strings and structure
- //
- NewInfo->FullName = AllocateCopyPool (StrSize (OldInfo->FullName), OldInfo->FullName);
- NewInfo->FileName = AllocateCopyPool (StrSize (OldInfo->FileName), OldInfo->FileName);
- NewInfo->Info = AllocateCopyPool ((UINTN)OldInfo->Info->Size, OldInfo->Info);
-
- //
- // make sure all the memory allocations were successful
- //
- if ((NULL == NewInfo->FullName) || (NewInfo->FileName == NULL) || (NewInfo->Info == NULL)) {
- //
- // Free the partially allocated new node
- //
- SHELL_FREE_NON_NULL (NewInfo->FullName);
- SHELL_FREE_NON_NULL (NewInfo->FileName);
- SHELL_FREE_NON_NULL (NewInfo->Info);
- SHELL_FREE_NON_NULL (NewInfo);
-
- //
- // Free the previously converted stuff
- //
- ShellCloseFileMetaArg ((EFI_SHELL_FILE_INFO **)(&ListHead));
- ListHead = NULL;
- break;
- }
-
- //
- // add that to the list
- //
- InsertTailList (ListHead, &NewInfo->Link);
- }
-
- return (ListHead);
-}
-
-/**
- Opens a group of files based on a path.
-
- This function uses the Arg to open all the matching files. Each matched
- file has a SHELL_FILE_INFO structure to record the file information. These
- structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
- structures from ListHead to access each file. This function supports wildcards
- and will process '?' and '*' as such. the list must be freed with a call to
- ShellCloseFileMetaArg().
-
- If you are NOT appending to an existing list *ListHead must be NULL. If
- *ListHead is NULL then it must be callee freed.
-
- @param Arg pointer to path string
- @param OpenMode mode to open files with
- @param ListHead head of linked list of results
-
- @retval EFI_SUCCESS the operation was successful and the list head
- contains the list of opened files
- @return != EFI_SUCCESS the operation failed
-
- @sa InternalShellConvertFileListType
-**/
-EFI_STATUS
-EFIAPI
-ShellOpenFileMetaArg (
- IN CHAR16 *Arg,
- IN UINT64 OpenMode,
- IN OUT EFI_SHELL_FILE_INFO **ListHead
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY mOldStyleFileList;
- CHAR16 *CleanFilePathStr;
-
- //
- // ASSERT that Arg and ListHead are not NULL
- //
- ASSERT (Arg != NULL);
- ASSERT (ListHead != NULL);
-
- CleanFilePathStr = NULL;
-
- Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- if (*ListHead == NULL) {
- *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
- if (*ListHead == NULL) {
- FreePool (CleanFilePathStr);
- return (EFI_OUT_OF_RESOURCES);
- }
-
- InitializeListHead (&((*ListHead)->Link));
- }
-
- Status = gEfiShellProtocol->OpenFileList (
- CleanFilePathStr,
- OpenMode,
- ListHead
- );
- if (EFI_ERROR (Status)) {
- gEfiShellProtocol->RemoveDupInFileList (ListHead);
- } else {
- Status = gEfiShellProtocol->RemoveDupInFileList (ListHead);
- }
-
- if ((*ListHead != NULL) && IsListEmpty (&(*ListHead)->Link)) {
- FreePool (*ListHead);
- FreePool (CleanFilePathStr);
- *ListHead = NULL;
- return (EFI_NOT_FOUND);
- }
-
- FreePool (CleanFilePathStr);
- return (Status);
- }
-
- //
- // Check for EFI shell
- //
- if (mEfiShellEnvironment2 != NULL) {
- //
- // make sure the list head is initialized
- //
- InitializeListHead (&mOldStyleFileList);
-
- //
- // Get the EFI Shell list of files
- //
- Status = mEfiShellEnvironment2->FileMetaArg (CleanFilePathStr, &mOldStyleFileList);
- if (EFI_ERROR (Status)) {
- *ListHead = NULL;
- FreePool (CleanFilePathStr);
- return (Status);
- }
-
- if (*ListHead == NULL) {
- *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
- if (*ListHead == NULL) {
- FreePool (CleanFilePathStr);
- return (EFI_OUT_OF_RESOURCES);
- }
-
- InitializeListHead (&((*ListHead)->Link));
- }
-
- //
- // Convert that to equivalent of UEFI Shell 2.0 structure
- //
- InternalShellConvertFileListType (&mOldStyleFileList, &(*ListHead)->Link);
-
- //
- // Free the EFI Shell version that was converted.
- //
- mEfiShellEnvironment2->FreeFileList (&mOldStyleFileList);
-
- if (((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink) && ((*ListHead)->Link.BackLink == &((*ListHead)->Link))) {
- FreePool (*ListHead);
- *ListHead = NULL;
- Status = EFI_NOT_FOUND;
- }
-
- FreePool (CleanFilePathStr);
- return (Status);
- }
-
- FreePool (CleanFilePathStr);
- return (EFI_UNSUPPORTED);
-}
-
-/**
- Free the linked list returned from ShellOpenFileMetaArg.
-
- if ListHead is NULL then ASSERT().
-
- @param ListHead the pointer to free.
-
- @retval EFI_SUCCESS the operation was successful.
-**/
-EFI_STATUS
-EFIAPI
-ShellCloseFileMetaArg (
- IN OUT EFI_SHELL_FILE_INFO **ListHead
- )
-{
- LIST_ENTRY *Node;
-
- //
- // ASSERT that ListHead is not NULL
- //
- ASSERT (ListHead != NULL);
-
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellProtocol != NULL) {
- return (gEfiShellProtocol->FreeFileList (ListHead));
- } else if (mEfiShellEnvironment2 != NULL) {
- //
- // Since this is EFI Shell version we need to free our internally made copy
- // of the list
- //
- for ( Node = GetFirstNode (&(*ListHead)->Link)
- ; *ListHead != NULL && !IsListEmpty (&(*ListHead)->Link)
- ; Node = GetFirstNode (&(*ListHead)->Link))
- {
- RemoveEntryList (Node);
- ((EFI_FILE_PROTOCOL *)((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Handle)->Close (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Handle);
- FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->FullName);
- FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->FileName);
- FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Info);
- FreePool ((EFI_SHELL_FILE_INFO_NO_CONST *)Node);
- }
-
- SHELL_FREE_NON_NULL (*ListHead);
- return EFI_SUCCESS;
- }
-
- return (EFI_UNSUPPORTED);
-}
-
-/**
- Find a file by searching the CWD and then the path.
-
- If FileName is NULL then ASSERT.
-
- If the return value is not NULL then the memory must be caller freed.
-
- @param FileName Filename string.
-
- @retval NULL the file was not found
- @return !NULL the full path to the file.
-**/
-CHAR16 *
-EFIAPI
-ShellFindFilePath (
- IN CONST CHAR16 *FileName
- )
-{
- CONST CHAR16 *Path;
- SHELL_FILE_HANDLE Handle;
- EFI_STATUS Status;
- CHAR16 *RetVal;
- CHAR16 *TestPath;
- CONST CHAR16 *Walker;
- UINTN Size;
- CHAR16 *TempChar;
-
- RetVal = NULL;
-
- //
- // First make sure its not an absolute path.
- //
- Status = ShellOpenFileByName (FileName, &Handle, EFI_FILE_MODE_READ, 0);
- if (!EFI_ERROR (Status)) {
- if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
- ASSERT (RetVal == NULL);
- RetVal = StrnCatGrow (&RetVal, NULL, FileName, 0);
- ShellCloseFile (&Handle);
- return (RetVal);
- } else {
- ShellCloseFile (&Handle);
- }
- }
-
- Path = ShellGetEnvironmentVariable (L"cwd");
- if (Path != NULL) {
- Size = StrSize (Path) + sizeof (CHAR16);
- Size += StrSize (FileName);
- TestPath = AllocateZeroPool (Size);
- if (TestPath == NULL) {
- return (NULL);
- }
-
- StrCpyS (TestPath, Size/sizeof (CHAR16), Path);
- StrCatS (TestPath, Size/sizeof (CHAR16), L"\\");
- StrCatS (TestPath, Size/sizeof (CHAR16), FileName);
- Status = ShellOpenFileByName (TestPath, &Handle, EFI_FILE_MODE_READ, 0);
- if (!EFI_ERROR (Status)) {
- if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
- ASSERT (RetVal == NULL);
- RetVal = StrnCatGrow (&RetVal, NULL, TestPath, 0);
- ShellCloseFile (&Handle);
- FreePool (TestPath);
- return (RetVal);
- } else {
- ShellCloseFile (&Handle);
- }
- }
-
- FreePool (TestPath);
- }
-
- Path = ShellGetEnvironmentVariable (L"path");
- if (Path != NULL) {
- Size = StrSize (Path)+sizeof (CHAR16);
- Size += StrSize (FileName);
- TestPath = AllocateZeroPool (Size);
- if (TestPath == NULL) {
- return (NULL);
- }
-
- Walker = (CHAR16 *)Path;
- do {
- CopyMem (TestPath, Walker, StrSize (Walker));
- if (TestPath != NULL) {
- TempChar = StrStr (TestPath, L";");
- if (TempChar != NULL) {
- *TempChar = CHAR_NULL;
- }
-
- if (TestPath[StrLen (TestPath)-1] != L'\\') {
- StrCatS (TestPath, Size/sizeof (CHAR16), L"\\");
- }
-
- if (FileName[0] == L'\\') {
- FileName++;
- }
-
- StrCatS (TestPath, Size/sizeof (CHAR16), FileName);
- if (StrStr (Walker, L";") != NULL) {
- Walker = StrStr (Walker, L";") + 1;
- } else {
- Walker = NULL;
- }
-
- Status = ShellOpenFileByName (TestPath, &Handle, EFI_FILE_MODE_READ, 0);
- if (!EFI_ERROR (Status)) {
- if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
- ASSERT (RetVal == NULL);
- RetVal = StrnCatGrow (&RetVal, NULL, TestPath, 0);
- ShellCloseFile (&Handle);
- break;
- } else {
- ShellCloseFile (&Handle);
- }
- }
- }
- } while (Walker != NULL && Walker[0] != CHAR_NULL);
-
- FreePool (TestPath);
- }
-
- return (RetVal);
-}
-
-/**
- Find a file by searching the CWD and then the path with a variable set of file
- extensions. If the file is not found it will append each extension in the list
- in the order provided and return the first one that is successful.
-
- If FileName is NULL, then ASSERT.
- If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
-
- If the return value is not NULL then the memory must be caller freed.
-
- @param[in] FileName Filename string.
- @param[in] FileExtension Semi-colon delimeted list of possible extensions.
-
- @retval NULL The file was not found.
- @retval !NULL The path to the file.
-**/
-CHAR16 *
-EFIAPI
-ShellFindFilePathEx (
- IN CONST CHAR16 *FileName,
- IN CONST CHAR16 *FileExtension
- )
-{
- CHAR16 *TestPath;
- CHAR16 *RetVal;
- CONST CHAR16 *ExtensionWalker;
- UINTN Size;
- CHAR16 *TempChar;
- CHAR16 *TempChar2;
-
- ASSERT (FileName != NULL);
- if (FileExtension == NULL) {
- return (ShellFindFilePath (FileName));
- }
-
- RetVal = ShellFindFilePath (FileName);
- if (RetVal != NULL) {
- return (RetVal);
- }
-
- Size = StrSize (FileName);
- Size += StrSize (FileExtension);
- TestPath = AllocateZeroPool (Size);
- if (TestPath == NULL) {
- return (NULL);
- }
-
- for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16 *)FileExtension; TempChar2 != NULL; ExtensionWalker = TempChar2 + 1) {
- StrCpyS (TestPath, Size/sizeof (CHAR16), FileName);
- if (ExtensionWalker != NULL) {
- StrCatS (TestPath, Size/sizeof (CHAR16), ExtensionWalker);
- }
-
- TempChar = StrStr (TestPath, L";");
- if (TempChar != NULL) {
- *TempChar = CHAR_NULL;
- }
-
- RetVal = ShellFindFilePath (TestPath);
- if (RetVal != NULL) {
- break;
- }
-
- ASSERT (ExtensionWalker != NULL);
- TempChar2 = StrStr (ExtensionWalker, L";");
- }
-
- FreePool (TestPath);
- return (RetVal);
-}
-
-typedef struct {
- LIST_ENTRY Link;
- CHAR16 *Name;
- SHELL_PARAM_TYPE Type;
- CHAR16 *Value;
- UINTN OriginalPosition;
-} SHELL_PARAM_PACKAGE;
-
-/**
- Checks the list of valid arguments and returns TRUE if the item was found. If the
- return value is TRUE then the type parameter is set also.
-
- if CheckList is NULL then ASSERT();
- if Name is NULL then ASSERT();
- if Type is NULL then ASSERT();
-
- @param Name pointer to Name of parameter found
- @param CheckList List to check against
- @param Type pointer to type of parameter if it was found
-
- @retval TRUE the Parameter was found. Type is valid.
- @retval FALSE the Parameter was not found. Type is not valid.
-**/
-BOOLEAN
-InternalIsOnCheckList (
- IN CONST CHAR16 *Name,
- IN CONST SHELL_PARAM_ITEM *CheckList,
- OUT SHELL_PARAM_TYPE *Type
- )
-{
- SHELL_PARAM_ITEM *TempListItem;
- CHAR16 *TempString;
-
- //
- // ASSERT that all 3 pointer parameters aren't NULL
- //
- ASSERT (CheckList != NULL);
- ASSERT (Type != NULL);
- ASSERT (Name != NULL);
-
- //
- // question mark and page break mode are always supported
- //
- if ((StrCmp (Name, L"-?") == 0) ||
- (StrCmp (Name, L"-b") == 0)
- )
- {
- *Type = TypeFlag;
- return (TRUE);
- }
-
- //
- // Enumerate through the list
- //
- for (TempListItem = (SHELL_PARAM_ITEM *)CheckList; TempListItem->Name != NULL; TempListItem++) {
- //
- // If the Type is TypeStart only check the first characters of the passed in param
- // If it matches set the type and return TRUE
- //
- if (TempListItem->Type == TypeStart) {
- if (StrnCmp (Name, TempListItem->Name, StrLen (TempListItem->Name)) == 0) {
- *Type = TempListItem->Type;
- return (TRUE);
- }
-
- TempString = NULL;
- TempString = StrnCatGrow (&TempString, NULL, Name, StrLen (TempListItem->Name));
- if (TempString != NULL) {
- if (StringNoCaseCompare (&TempString, &TempListItem->Name) == 0) {
- *Type = TempListItem->Type;
- FreePool (TempString);
- return (TRUE);
- }
-
- FreePool (TempString);
- }
- } else if (StringNoCaseCompare (&Name, &TempListItem->Name) == 0) {
- *Type = TempListItem->Type;
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-/**
- Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
-
- @param[in] Name pointer to Name of parameter found
- @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
- @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
-
- @retval TRUE the Parameter is a flag.
- @retval FALSE the Parameter not a flag.
-**/
-BOOLEAN
-InternalIsFlag (
- IN CONST CHAR16 *Name,
- IN CONST BOOLEAN AlwaysAllowNumbers,
- IN CONST BOOLEAN TimeNumbers
- )
-{
- //
- // ASSERT that Name isn't NULL
- //
- ASSERT (Name != NULL);
-
- //
- // If we accept numbers then dont return TRUE. (they will be values)
- //
- if ((((Name[0] == L'-') || (Name[0] == L'+')) && InternalShellIsHexOrDecimalNumber (Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
- return (FALSE);
- }
-
- //
- // If the Name has a /, +, or - as the first character return TRUE
- //
- if ((Name[0] == L'/') ||
- (Name[0] == L'-') ||
- (Name[0] == L'+')
- )
- {
- return (TRUE);
- }
-
- return (FALSE);
-}
-
-/**
- Checks the command line arguments passed against the list of valid ones.
-
- If no initialization is required, then return RETURN_SUCCESS.
-
- @param[in] CheckList pointer to list of parameters to check
- @param[out] CheckPackage pointer to pointer to list checked values
- @param[out] ProblemParam optional pointer to pointer to unicode string for
- the paramater that caused failure. If used then the
- caller is responsible for freeing the memory.
- @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
- @param[in] Argv pointer to array of parameters
- @param[in] Argc Count of parameters in Argv
- @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_OUT_OF_RESOURCES A memory allocation failed
- @retval EFI_INVALID_PARAMETER A parameter was invalid
- @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
- duplicated. the duplicated command line argument
- was returned in ProblemParam if provided.
- @retval EFI_NOT_FOUND a argument required a value that was missing.
- the invalid command line argument was returned in
- ProblemParam if provided.
-**/
-EFI_STATUS
-InternalCommandLineParse (
- IN CONST SHELL_PARAM_ITEM *CheckList,
- OUT LIST_ENTRY **CheckPackage,
- OUT CHAR16 **ProblemParam OPTIONAL,
- IN BOOLEAN AutoPageBreak,
- IN CONST CHAR16 **Argv,
- IN UINTN Argc,
- IN BOOLEAN AlwaysAllowNumbers
- )
-{
- UINTN LoopCounter;
- SHELL_PARAM_TYPE CurrentItemType;
- SHELL_PARAM_PACKAGE *CurrentItemPackage;
- UINTN GetItemValue;
- UINTN ValueSize;
- UINTN Count;
- CONST CHAR16 *TempPointer;
- UINTN CurrentValueSize;
- CHAR16 *NewValue;
-
- CurrentItemPackage = NULL;
- GetItemValue = 0;
- ValueSize = 0;
- Count = 0;
-
- //
- // If there is only 1 item we dont need to do anything
- //
- if (Argc < 1) {
- *CheckPackage = NULL;
- return (EFI_SUCCESS);
- }
-
- //
- // ASSERTs
- //
- ASSERT (CheckList != NULL);
- ASSERT (Argv != NULL);
-
- //
- // initialize the linked list
- //
- *CheckPackage = (LIST_ENTRY *)AllocateZeroPool (sizeof (LIST_ENTRY));
- if (*CheckPackage == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- InitializeListHead (*CheckPackage);
-
- //
- // loop through each of the arguments
- //
- for (LoopCounter = 0; LoopCounter < Argc; ++LoopCounter) {
- if (Argv[LoopCounter] == NULL) {
- //
- // do nothing for NULL argv
- //
- } else if (InternalIsOnCheckList (Argv[LoopCounter], CheckList, &CurrentItemType)) {
- //
- // We might have leftover if last parameter didnt have optional value
- //
- if (GetItemValue != 0) {
- GetItemValue = 0;
- InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
- }
-
- //
- // this is a flag
- //
- CurrentItemPackage = AllocateZeroPool (sizeof (SHELL_PARAM_PACKAGE));
- if (CurrentItemPackage == NULL) {
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return (EFI_OUT_OF_RESOURCES);
- }
-
- CurrentItemPackage->Name = AllocateCopyPool (StrSize (Argv[LoopCounter]), Argv[LoopCounter]);
- if (CurrentItemPackage->Name == NULL) {
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return (EFI_OUT_OF_RESOURCES);
- }
-
- CurrentItemPackage->Type = CurrentItemType;
- CurrentItemPackage->OriginalPosition = (UINTN)(-1);
- CurrentItemPackage->Value = NULL;
-
- //
- // Does this flag require a value
- //
- switch (CurrentItemPackage->Type) {
- //
- // possibly trigger the next loop(s) to populate the value of this item
- //
- case TypeValue:
- case TypeTimeValue:
- GetItemValue = 1;
- ValueSize = 0;
- break;
- case TypeDoubleValue:
- GetItemValue = 2;
- ValueSize = 0;
- break;
- case TypeMaxValue:
- GetItemValue = (UINTN)(-1);
- ValueSize = 0;
- break;
- default:
- //
- // this item has no value expected; we are done
- //
- InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
- ASSERT (GetItemValue == 0);
- break;
- }
- } else if ((GetItemValue != 0) && (CurrentItemPackage != NULL) && !InternalIsFlag (Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
- //
- // get the item VALUE for a previous flag
- //
- CurrentValueSize = ValueSize + StrSize (Argv[LoopCounter]) + sizeof (CHAR16);
- NewValue = ReallocatePool (ValueSize, CurrentValueSize, CurrentItemPackage->Value);
- if (NewValue == NULL) {
- SHELL_FREE_NON_NULL (CurrentItemPackage->Value);
- SHELL_FREE_NON_NULL (CurrentItemPackage);
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return EFI_OUT_OF_RESOURCES;
- }
-
- CurrentItemPackage->Value = NewValue;
- if (ValueSize == 0) {
- StrCpyS (
- CurrentItemPackage->Value,
- CurrentValueSize/sizeof (CHAR16),
- Argv[LoopCounter]
- );
- } else {
- StrCatS (
- CurrentItemPackage->Value,
- CurrentValueSize/sizeof (CHAR16),
- L" "
- );
- StrCatS (
- CurrentItemPackage->Value,
- CurrentValueSize/sizeof (CHAR16),
- Argv[LoopCounter]
- );
- }
-
- ValueSize += StrSize (Argv[LoopCounter]) + sizeof (CHAR16);
-
- GetItemValue--;
- if (GetItemValue == 0) {
- InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
- }
- } else if (!InternalIsFlag (Argv[LoopCounter], AlwaysAllowNumbers, FALSE)) {
- //
- // add this one as a non-flag
- //
-
- TempPointer = Argv[LoopCounter];
- if ( ((*TempPointer == L'^') && (*(TempPointer+1) == L'-'))
- || ((*TempPointer == L'^') && (*(TempPointer+1) == L'/'))
- || ((*TempPointer == L'^') && (*(TempPointer+1) == L'+'))
- )
- {
- TempPointer++;
- }
-
- CurrentItemPackage = AllocateZeroPool (sizeof (SHELL_PARAM_PACKAGE));
- if (CurrentItemPackage == NULL) {
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return (EFI_OUT_OF_RESOURCES);
- }
-
- CurrentItemPackage->Name = NULL;
- CurrentItemPackage->Type = TypePosition;
- CurrentItemPackage->Value = AllocateCopyPool (StrSize (TempPointer), TempPointer);
- if (CurrentItemPackage->Value == NULL) {
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return (EFI_OUT_OF_RESOURCES);
- }
-
- CurrentItemPackage->OriginalPosition = Count++;
- InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
- } else {
- //
- // this was a non-recognised flag... error!
- //
- if (ProblemParam != NULL) {
- *ProblemParam = AllocateCopyPool (StrSize (Argv[LoopCounter]), Argv[LoopCounter]);
- }
-
- ShellCommandLineFreeVarList (*CheckPackage);
- *CheckPackage = NULL;
- return (EFI_VOLUME_CORRUPTED);
- }
- }
-
- if (GetItemValue != 0) {
- GetItemValue = 0;
- InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
- }
-
- //
- // support for AutoPageBreak
- //
- if (AutoPageBreak && ShellCommandLineGetFlag (*CheckPackage, L"-b")) {
- ShellSetPageBreakMode (TRUE);
- }
-
- return (EFI_SUCCESS);
-}
-
-/**
- Checks the command line arguments passed against the list of valid ones.
- Optionally removes NULL values first.
-
- If no initialization is required, then return RETURN_SUCCESS.
-
- @param[in] CheckList The pointer to list of parameters to check.
- @param[out] CheckPackage The package of checked values.
- @param[out] ProblemParam Optional pointer to pointer to unicode string for
- the paramater that caused failure.
- @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
- @param[in] AlwaysAllowNumbers Will never fail for number based flags.
-
- @retval EFI_SUCCESS The operation completed successfully.
- @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
- @retval EFI_INVALID_PARAMETER A parameter was invalid.
- @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
- @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
- of the command line arguments was returned in
- ProblemParam if provided.
- @retval EFI_NOT_FOUND A argument required a value that was missing.
- The invalid command line argument was returned in
- ProblemParam if provided.
-**/
-EFI_STATUS
-EFIAPI
-ShellCommandLineParseEx (
- IN CONST SHELL_PARAM_ITEM *CheckList,
- OUT LIST_ENTRY **CheckPackage,
- OUT CHAR16 **ProblemParam OPTIONAL,
- IN BOOLEAN AutoPageBreak,
- IN BOOLEAN AlwaysAllowNumbers
- )
-{
- //
- // ASSERT that CheckList and CheckPackage aren't NULL
- //
- ASSERT (CheckList != NULL);
- ASSERT (CheckPackage != NULL);
-
- //
- // Check for UEFI Shell 2.0 protocols
- //
- if (gEfiShellParametersProtocol != NULL) {
- return (InternalCommandLineParse (
- CheckList,
- CheckPackage,
- ProblemParam,
- AutoPageBreak,
- (CONST CHAR16 **)gEfiShellParametersProtocol->Argv,
- gEfiShellParametersProtocol->Argc,
- AlwaysAllowNumbers
- ));
- }
-
- //
- // ASSERT That EFI Shell is not required
- //
- ASSERT (mEfiShellInterface != NULL);
- return (InternalCommandLineParse (
- CheckList,
- CheckPackage,
- ProblemParam,
- AutoPageBreak,
- (CONST CHAR16 **)mEfiShellInterface->Argv,
- mEfiShellInterface->Argc,
- AlwaysAllowNumbers
- ));
-}
-
-/**
- Frees shell variable list that was returned from ShellCommandLineParse.
-
- This function will free all the memory that was used for the CheckPackage
- list of postprocessed shell arguments.
-
- this function has no return value.
-
- if CheckPackage is NULL, then return
-
- @param CheckPackage the list to de-allocate
- **/
-VOID
-EFIAPI
-ShellCommandLineFreeVarList (
- IN LIST_ENTRY *CheckPackage
- )
-{
- LIST_ENTRY *Node;
-
- //
- // check for CheckPackage == NULL
- //
- if (CheckPackage == NULL) {
- return;
- }
-
- //
- // for each node in the list
- //
- for ( Node = GetFirstNode (CheckPackage)
- ; !IsListEmpty (CheckPackage)
- ; Node = GetFirstNode (CheckPackage)
- )
- {
- //
- // Remove it from the list
- //
- RemoveEntryList (Node);
-
- //
- // if it has a name free the name
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
- FreePool (((SHELL_PARAM_PACKAGE *)Node)->Name);
- }
-
- //
- // if it has a value free the value
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Value != NULL) {
- FreePool (((SHELL_PARAM_PACKAGE *)Node)->Value);
- }
-
- //
- // free the node structure
- //
- FreePool ((SHELL_PARAM_PACKAGE *)Node);
- }
-
- //
- // free the list head node
- //
- FreePool (CheckPackage);
-}
-
-/**
- Checks for presence of a flag parameter
-
- flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
-
- if CheckPackage is NULL then return FALSE.
- if KeyString is NULL then ASSERT()
-
- @param CheckPackage The package of parsed command line arguments
- @param KeyString the Key of the command line argument to check for
-
- @retval TRUE the flag is on the command line
- @retval FALSE the flag is not on the command line
- **/
-BOOLEAN
-EFIAPI
-ShellCommandLineGetFlag (
- IN CONST LIST_ENTRY *CONST CheckPackage,
- IN CONST CHAR16 *CONST KeyString
- )
-{
- LIST_ENTRY *Node;
- CHAR16 *TempString;
-
- //
- // return FALSE for no package or KeyString is NULL
- //
- if ((CheckPackage == NULL) || (KeyString == NULL)) {
- return (FALSE);
- }
-
- //
- // enumerate through the list of parametrs
- //
- for ( Node = GetFirstNode (CheckPackage)
- ; !IsNull (CheckPackage, Node)
- ; Node = GetNextNode (CheckPackage, Node)
- )
- {
- //
- // If the Name matches, return TRUE (and there may be NULL name)
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
- //
- // If Type is TypeStart then only compare the begining of the strings
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Type == TypeStart) {
- if (StrnCmp (KeyString, ((SHELL_PARAM_PACKAGE *)Node)->Name, StrLen (KeyString)) == 0) {
- return (TRUE);
- }
-
- TempString = NULL;
- TempString = StrnCatGrow (&TempString, NULL, KeyString, StrLen (((SHELL_PARAM_PACKAGE *)Node)->Name));
- if (TempString != NULL) {
- if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
- FreePool (TempString);
- return (TRUE);
- }
-
- FreePool (TempString);
- }
- } else if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
- return (TRUE);
- }
- }
- }
-
- return (FALSE);
-}
-
-/**
- Returns value from command line argument.
-
- Value parameters are in the form of "-<Key> value" or "/<Key> value".
-
- If CheckPackage is NULL, then return NULL.
-
- @param[in] CheckPackage The package of parsed command line arguments.
- @param[in] KeyString The Key of the command line argument to check for.
-
- @retval NULL The flag is not on the command line.
- @retval !=NULL The pointer to unicode string of the value.
-**/
-CONST CHAR16 *
-EFIAPI
-ShellCommandLineGetValue (
- IN CONST LIST_ENTRY *CheckPackage,
- IN CHAR16 *KeyString
- )
-{
- LIST_ENTRY *Node;
- CHAR16 *TempString;
-
- //
- // return NULL for no package or KeyString is NULL
- //
- if ((CheckPackage == NULL) || (KeyString == NULL)) {
- return (NULL);
- }
-
- //
- // enumerate through the list of parametrs
- //
- for ( Node = GetFirstNode (CheckPackage)
- ; !IsNull (CheckPackage, Node)
- ; Node = GetNextNode (CheckPackage, Node)
- )
- {
- //
- // If the Name matches, return TRUE (and there may be NULL name)
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
- //
- // If Type is TypeStart then only compare the begining of the strings
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->Type == TypeStart) {
- if (StrnCmp (KeyString, ((SHELL_PARAM_PACKAGE *)Node)->Name, StrLen (KeyString)) == 0) {
- return (((SHELL_PARAM_PACKAGE *)Node)->Name + StrLen (KeyString));
- }
-
- TempString = NULL;
- TempString = StrnCatGrow (&TempString, NULL, KeyString, StrLen (((SHELL_PARAM_PACKAGE *)Node)->Name));
- if (TempString != NULL) {
- if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
- FreePool (TempString);
- return (((SHELL_PARAM_PACKAGE *)Node)->Name + StrLen (KeyString));
- }
-
- FreePool (TempString);
- }
- } else if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
- return (((SHELL_PARAM_PACKAGE *)Node)->Value);
- }
- }
- }
-
- return (NULL);
-}
-
-/**
- Returns raw value from command line argument.
-
- Raw value parameters are in the form of "value" in a specific position in the list.
-
- If CheckPackage is NULL, then return NULL.
-
- @param[in] CheckPackage The package of parsed command line arguments.
- @param[in] Position The position of the value.
-
- @retval NULL The flag is not on the command line.
- @retval !=NULL The pointer to unicode string of the value.
- **/
-CONST CHAR16 *
-EFIAPI
-ShellCommandLineGetRawValue (
- IN CONST LIST_ENTRY *CONST CheckPackage,
- IN UINTN Position
- )
-{
- LIST_ENTRY *Node;
-
- //
- // check for CheckPackage == NULL
- //
- if (CheckPackage == NULL) {
- return (NULL);
- }
-
- //
- // enumerate through the list of parametrs
- //
- for ( Node = GetFirstNode (CheckPackage)
- ; !IsNull (CheckPackage, Node)
- ; Node = GetNextNode (CheckPackage, Node)
- )
- {
- //
- // If the position matches, return the value
- //
- if (((SHELL_PARAM_PACKAGE *)Node)->OriginalPosition == Position) {
- return (((SHELL_PARAM_PACKAGE *)Node)->Value);
- }
- }
-
- return (NULL);
-}
-
-/**
- returns the number of command line value parameters that were parsed.
-
- this will not include flags.
-
- @param[in] CheckPackage The package of parsed command line arguments.
-
- @retval (UINTN)-1 No parsing has ocurred
- @return other The number of value parameters found
-**/
-UINTN
-EFIAPI
-ShellCommandLineGetCount (
- IN CONST LIST_ENTRY *CheckPackage
- )
-{
- LIST_ENTRY *Node1;
- UINTN Count;
-
- if (CheckPackage == NULL) {
- return (0);
- }
-
- for ( Node1 = GetFirstNode (CheckPackage), Count = 0
- ; !IsNull (CheckPackage, Node1)
- ; Node1 = GetNextNode (CheckPackage, Node1)
- )
- {
- if (((SHELL_PARAM_PACKAGE *)Node1)->Name == NULL) {
- Count++;
- }
- }
-
- return (Count);
-}
-
-/**
- Determines if a parameter is duplicated.
-
- If Param is not NULL then it will point to a callee allocated string buffer
- with the parameter value if a duplicate is found.
-
- If CheckPackage is NULL, then ASSERT.
-
- @param[in] CheckPackage The package of parsed command line arguments.
- @param[out] Param Upon finding one, a pointer to the duplicated parameter.
-
- @retval EFI_SUCCESS No parameters were duplicated.
- @retval EFI_DEVICE_ERROR A duplicate was found.
- **/
-EFI_STATUS
-EFIAPI
-ShellCommandLineCheckDuplicate (
- IN CONST LIST_ENTRY *CheckPackage,
- OUT CHAR16 **Param
- )
-{
- LIST_ENTRY *Node1;
- LIST_ENTRY *Node2;
-
- ASSERT (CheckPackage != NULL);
-
- for ( Node1 = GetFirstNode (CheckPackage)
- ; !IsNull (CheckPackage, Node1)
- ; Node1 = GetNextNode (CheckPackage, Node1)
- )
- {
- for ( Node2 = GetNextNode (CheckPackage, Node1)
- ; !IsNull (CheckPackage, Node2)
- ; Node2 = GetNextNode (CheckPackage, Node2)
- )
- {
- if ((((SHELL_PARAM_PACKAGE *)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE *)Node2)->Name != NULL) && (StrCmp (((SHELL_PARAM_PACKAGE *)Node1)->Name, ((SHELL_PARAM_PACKAGE *)Node2)->Name) == 0)) {
- if (Param != NULL) {
- *Param = NULL;
- *Param = StrnCatGrow (Param, NULL, ((SHELL_PARAM_PACKAGE *)Node1)->Name, 0);
- }
-
- return (EFI_DEVICE_ERROR);
- }
- }
- }
-
- return (EFI_SUCCESS);
-}
-
-/**
- This is a find and replace function. Upon successful return the NewString is a copy of
- SourceString with each instance of FindTarget replaced with ReplaceWith.
-
- If SourceString and NewString overlap the behavior is undefined.
-
- If the string would grow bigger than NewSize it will halt and return error.
-
- @param[in] SourceString The string with source buffer.
- @param[in, out] NewString The string with resultant buffer.
- @param[in] NewSize The size in bytes of NewString.
- @param[in] FindTarget The string to look for.
- @param[in] ReplaceWith The string to replace FindTarget with.
- @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
- immediately before it.
- @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
-
- @retval EFI_INVALID_PARAMETER SourceString was NULL.
- @retval EFI_INVALID_PARAMETER NewString was NULL.
- @retval EFI_INVALID_PARAMETER FindTarget was NULL.
- @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
- @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
- @retval EFI_INVALID_PARAMETER SourceString had length < 1.
- @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
- the new string (truncation occurred).
- @retval EFI_SUCCESS The string was successfully copied with replacement.
-**/
-EFI_STATUS
-EFIAPI
-ShellCopySearchAndReplace (
- IN CHAR16 CONST *SourceString,
- IN OUT CHAR16 *NewString,
- IN UINTN NewSize,
- IN CONST CHAR16 *FindTarget,
- IN CONST CHAR16 *ReplaceWith,
- IN CONST BOOLEAN SkipPreCarrot,
- IN CONST BOOLEAN ParameterReplacing
- )
-{
- UINTN Size;
- CHAR16 *Replace;
-
- if ( (SourceString == NULL)
- || (NewString == NULL)
- || (FindTarget == NULL)
- || (ReplaceWith == NULL)
- || (StrLen (FindTarget) < 1)
- || (StrLen (SourceString) < 1)
- )
- {
- return (EFI_INVALID_PARAMETER);
- }
-
- Replace = NULL;
- if ((StrStr (ReplaceWith, L" ") == NULL) || !ParameterReplacing) {
- Replace = StrnCatGrow (&Replace, NULL, ReplaceWith, 0);
- } else {
- Replace = AllocateZeroPool (StrSize (ReplaceWith) + 2*sizeof (CHAR16));
- if (Replace != NULL) {
- UnicodeSPrint (Replace, StrSize (ReplaceWith) + 2*sizeof (CHAR16), L"\"%s\"", ReplaceWith);
- }
- }
-
- if (Replace == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- NewString = ZeroMem (NewString, NewSize);
- while (*SourceString != CHAR_NULL) {
- //
- // if we find the FindTarget and either Skip == FALSE or Skip and we
- // dont have a carrot do a replace...
- //
- if ( (StrnCmp (SourceString, FindTarget, StrLen (FindTarget)) == 0)
- && ((SkipPreCarrot && (*(SourceString-1) != L'^')) || !SkipPreCarrot)
- )
- {
- SourceString += StrLen (FindTarget);
- Size = StrSize (NewString);
- if ((Size + (StrLen (Replace)*sizeof (CHAR16))) > NewSize) {
- FreePool (Replace);
- return (EFI_BUFFER_TOO_SMALL);
- }
-
- StrCatS (NewString, NewSize/sizeof (CHAR16), Replace);
- } else {
- Size = StrSize (NewString);
- if (Size + sizeof (CHAR16) > NewSize) {
- FreePool (Replace);
- return (EFI_BUFFER_TOO_SMALL);
- }
-
- StrnCatS (NewString, NewSize/sizeof (CHAR16), SourceString, 1);
- SourceString++;
- }
- }
-
- FreePool (Replace);
- return (EFI_SUCCESS);
-}
-
-/**
- Internal worker function to output a string.
-
- This function will output a string to the correct StdOut.
-
- @param[in] String The string to print out.
-
- @retval EFI_SUCCESS The operation was successful.
- @retval !EFI_SUCCESS The operation failed.
-**/
-EFI_STATUS
-InternalPrintTo (
- IN CONST CHAR16 *String
- )
-{
- UINTN Size;
-
- Size = StrSize (String) - sizeof (CHAR16);
- if (Size == 0) {
- return (EFI_SUCCESS);
- }
-
- if (gEfiShellParametersProtocol != NULL) {
- return (gEfiShellProtocol->WriteFile (gEfiShellParametersProtocol->StdOut, &Size, (VOID *)String));
- }
-
- if (mEfiShellInterface != NULL) {
- if (mEfiShellInterface->RedirArgc == 0) {
- //
- // Divide in half for old shell. Must be string length not size.
- //
- Size /= 2; // Divide in half only when no redirection.
- }
-
- return (mEfiShellInterface->StdOut->Write (mEfiShellInterface->StdOut, &Size, (VOID *)String));
- }
-
- ASSERT (FALSE);
- return (EFI_UNSUPPORTED);
-}
-
-/**
- Print at a specific location on the screen.
-
- This function will move the cursor to a given screen location and print the specified string
-
- If -1 is specified for either the Row or Col the current screen location for BOTH
- will be used.
-
- if either Row or Col is out of range for the current console, then ASSERT
- if Format is NULL, then ASSERT
-
- In addition to the standard %-based flags as supported by UefiLib Print() this supports
- the following additional flags:
- %N - Set output attribute to normal
- %H - Set output attribute to highlight
- %E - Set output attribute to error
- %B - Set output attribute to blue color
- %V - Set output attribute to green color
-
- Note: The background color is controlled by the shell command cls.
-
- @param[in] Col the column to print at
- @param[in] Row the row to print at
- @param[in] Format the format string
- @param[in] Marker the marker for the variable argument list
-
- @return EFI_SUCCESS The operation was successful.
- @return EFI_DEVICE_ERROR The console device reported an error.
-**/
-EFI_STATUS
-InternalShellPrintWorker (
- IN INT32 Col OPTIONAL,
- IN INT32 Row OPTIONAL,
- IN CONST CHAR16 *Format,
- IN VA_LIST Marker
- )
-{
- EFI_STATUS Status;
- CHAR16 *ResumeLocation;
- CHAR16 *FormatWalker;
- UINTN OriginalAttribute;
- CHAR16 *mPostReplaceFormat;
- CHAR16 *mPostReplaceFormat2;
-
- mPostReplaceFormat = AllocateZeroPool (PcdGet32 (PcdShellPrintBufferSize));
- mPostReplaceFormat2 = AllocateZeroPool (PcdGet32 (PcdShellPrintBufferSize));
-
- if ((mPostReplaceFormat == NULL) || (mPostReplaceFormat2 == NULL)) {
- SHELL_FREE_NON_NULL (mPostReplaceFormat);
- SHELL_FREE_NON_NULL (mPostReplaceFormat2);
- return (EFI_OUT_OF_RESOURCES);
- }
-
- Status = EFI_SUCCESS;
- OriginalAttribute = gST->ConOut->Mode->Attribute;
-
- //
- // Back and forth each time fixing up 1 of our flags...
- //
- Status = ShellCopySearchAndReplace (Format, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);
- ASSERT_EFI_ERROR (Status);
- Status = ShellCopySearchAndReplace (mPostReplaceFormat, mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);
- ASSERT_EFI_ERROR (Status);
- Status = ShellCopySearchAndReplace (mPostReplaceFormat2, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);
- ASSERT_EFI_ERROR (Status);
- Status = ShellCopySearchAndReplace (mPostReplaceFormat, mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);
- ASSERT_EFI_ERROR (Status);
- Status = ShellCopySearchAndReplace (mPostReplaceFormat2, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Use the last buffer from replacing to print from...
- //
- UnicodeVSPrint (mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);
-
- if ((Col != -1) && (Row != -1)) {
- Status = gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
- }
-
- FormatWalker = mPostReplaceFormat2;
- while (*FormatWalker != CHAR_NULL) {
- //
- // Find the next attribute change request
- //
- ResumeLocation = StrStr (FormatWalker, L"%");
- if (ResumeLocation != NULL) {
- *ResumeLocation = CHAR_NULL;
- }
-
- //
- // print the current FormatWalker string
- //
- if (StrLen (FormatWalker) > 0) {
- Status = InternalPrintTo (FormatWalker);
- if (EFI_ERROR (Status)) {
- break;
- }
- }
-
- //
- // update the attribute
- //
- if (ResumeLocation != NULL) {
- if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) {
- //
- // Move cursor back 1 position to overwrite the ^
- //
- gST->ConOut->SetCursorPosition (gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
-
- //
- // Print a simple '%' symbol
- //
- Status = InternalPrintTo (L"%");
- ResumeLocation = ResumeLocation - 1;
- } else {
- switch (*(ResumeLocation+1)) {
- case (L'N'):
- gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
- break;
- case (L'E'):
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
- break;
- case (L'H'):
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
- break;
- case (L'B'):
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
- break;
- case (L'V'):
- gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
- break;
- default:
- //
- // Print a simple '%' symbol
- //
- Status = InternalPrintTo (L"%");
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ResumeLocation = ResumeLocation - 1;
- break;
- }
- }
- } else {
- //
- // reset to normal now...
- //
- break;
- }
-
- //
- // update FormatWalker to Resume + 2 (skip the % and the indicator)
- //
- FormatWalker = ResumeLocation + 2;
- }
-
- gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
-
- SHELL_FREE_NON_NULL (mPostReplaceFormat);
- SHELL_FREE_NON_NULL (mPostReplaceFormat2);
- return (Status);
-}
-
-/**
- Print at a specific location on the screen.
-
- This function will move the cursor to a given screen location and print the specified string.
-
- If -1 is specified for either the Row or Col the current screen location for BOTH
- will be used.
-
- If either Row or Col is out of range for the current console, then ASSERT.
- If Format is NULL, then ASSERT.
-
- In addition to the standard %-based flags as supported by UefiLib Print() this supports
- the following additional flags:
- %N - Set output attribute to normal
- %H - Set output attribute to highlight
- %E - Set output attribute to error
- %B - Set output attribute to blue color
- %V - Set output attribute to green color
-
- Note: The background color is controlled by the shell command cls.
-
- @param[in] Col the column to print at
- @param[in] Row the row to print at
- @param[in] Format the format string
- @param[in] ... The variable argument list.
-
- @return EFI_SUCCESS The printing was successful.
- @return EFI_DEVICE_ERROR The console device reported an error.
-**/
-EFI_STATUS
-EFIAPI
-ShellPrintEx (
- IN INT32 Col OPTIONAL,
- IN INT32 Row OPTIONAL,
- IN CONST CHAR16 *Format,
- ...
- )
-{
- VA_LIST Marker;
- EFI_STATUS RetVal;
-
- if (Format == NULL) {
- return (EFI_INVALID_PARAMETER);
- }
-
- VA_START (Marker, Format);
- RetVal = InternalShellPrintWorker (Col, Row, Format, Marker);
- VA_END (Marker);
- return (RetVal);
-}
-
-/**
- Print at a specific location on the screen.
-
- This function will move the cursor to a given screen location and print the specified string.
-
- If -1 is specified for either the Row or Col the current screen location for BOTH
- will be used.
-
- If either Row or Col is out of range for the current console, then ASSERT.
- If Format is NULL, then ASSERT.
-
- In addition to the standard %-based flags as supported by UefiLib Print() this supports
- the following additional flags:
- %N - Set output attribute to normal.
- %H - Set output attribute to highlight.
- %E - Set output attribute to error.
- %B - Set output attribute to blue color.
- %V - Set output attribute to green color.
-
- Note: The background color is controlled by the shell command cls.
-
- @param[in] Col The column to print at.
- @param[in] Row The row to print at.
- @param[in] Language The language of the string to retrieve. If this parameter
- is NULL, then the current platform language is used.
- @param[in] HiiFormatStringId The format string Id for getting from Hii.
- @param[in] HiiFormatHandle The format string Handle for getting from Hii.
- @param[in] ... The variable argument list.
-
- @return EFI_SUCCESS The printing was successful.
- @return EFI_DEVICE_ERROR The console device reported an error.
-**/
-EFI_STATUS
-EFIAPI
-ShellPrintHiiEx (
- IN INT32 Col OPTIONAL,
- IN INT32 Row OPTIONAL,
- IN CONST CHAR8 *Language OPTIONAL,
- IN CONST EFI_STRING_ID HiiFormatStringId,
- IN CONST EFI_HII_HANDLE HiiFormatHandle,
- ...
- )
-{
- VA_LIST Marker;
- CHAR16 *HiiFormatString;
- EFI_STATUS RetVal;
-
- RetVal = EFI_DEVICE_ERROR;
-
- VA_START (Marker, HiiFormatHandle);
- HiiFormatString = HiiGetString (HiiFormatHandle, HiiFormatStringId, Language);
- if (HiiFormatString != NULL) {
- RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker);
- SHELL_FREE_NON_NULL (HiiFormatString);
- }
-
- VA_END (Marker);
-
- return (RetVal);
-}
-
-/**
- Function to determine if a given filename represents a file or a directory.
-
- @param[in] DirName Path to directory to test.
-
- @retval EFI_SUCCESS The Path represents a directory
- @retval EFI_NOT_FOUND The Path does not represent a directory
- @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
- @return The path failed to open
-**/
-EFI_STATUS
-EFIAPI
-ShellIsDirectory (
- IN CONST CHAR16 *DirName
- )
-{
- EFI_STATUS Status;
- SHELL_FILE_HANDLE Handle;
- CHAR16 *TempLocation;
- CHAR16 *TempLocation2;
-
- ASSERT (DirName != NULL);
-
- Handle = NULL;
- TempLocation = NULL;
-
- Status = ShellOpenFileByName (DirName, &Handle, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR (Status)) {
- //
- // try good logic first.
- //
- if (gEfiShellProtocol != NULL) {
- TempLocation = StrnCatGrow (&TempLocation, NULL, DirName, 0);
- if (TempLocation == NULL) {
- ShellCloseFile (&Handle);
- return (EFI_OUT_OF_RESOURCES);
- }
-
- TempLocation2 = StrStr (TempLocation, L":");
- if ((TempLocation2 != NULL) && (StrLen (StrStr (TempLocation, L":")) == 2)) {
- *(TempLocation2+1) = CHAR_NULL;
- }
-
- if (gEfiShellProtocol->GetDevicePathFromMap (TempLocation) != NULL) {
- FreePool (TempLocation);
- return (EFI_SUCCESS);
- }
-
- FreePool (TempLocation);
- } else {
- //
- // probably a map name?!?!!?
- //
- TempLocation = StrStr (DirName, L"\\");
- if ((TempLocation != NULL) && (*(TempLocation+1) == CHAR_NULL)) {
- return (EFI_SUCCESS);
- }
- }
-
- return (Status);
- }
-
- if (FileHandleIsDirectory (Handle) == EFI_SUCCESS) {
- ShellCloseFile (&Handle);
- return (EFI_SUCCESS);
- }
-
- ShellCloseFile (&Handle);
- return (EFI_NOT_FOUND);
-}
-
-/**
- Function to determine if a given filename represents a file.
-
- @param[in] Name Path to file to test.
-
- @retval EFI_SUCCESS The Path represents a file.
- @retval EFI_NOT_FOUND The Path does not represent a file.
- @retval other The path failed to open.
-**/
-EFI_STATUS
-EFIAPI
-ShellIsFile (
- IN CONST CHAR16 *Name
- )
-{
- EFI_STATUS Status;
- SHELL_FILE_HANDLE Handle;
-
- ASSERT (Name != NULL);
-
- Handle = NULL;
-
- Status = ShellOpenFileByName (Name, &Handle, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR (Status)) {
- return (Status);
- }
-
- if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
- ShellCloseFile (&Handle);
- return (EFI_SUCCESS);
- }
-
- ShellCloseFile (&Handle);
- return (EFI_NOT_FOUND);
-}
-
-/**
- Function to determine if a given filename represents a file.
-
- This will search the CWD and then the Path.
-
- If Name is NULL, then ASSERT.
-
- @param[in] Name Path to file to test.
-
- @retval EFI_SUCCESS The Path represents a file.
- @retval EFI_NOT_FOUND The Path does not represent a file.
- @retval other The path failed to open.
-**/
-EFI_STATUS
-EFIAPI
-ShellIsFileInPath (
- IN CONST CHAR16 *Name
- )
-{
- CHAR16 *NewName;
- EFI_STATUS Status;
-
- if (!EFI_ERROR (ShellIsFile (Name))) {
- return (EFI_SUCCESS);
- }
-
- NewName = ShellFindFilePath (Name);
- if (NewName == NULL) {
- return (EFI_NOT_FOUND);
- }
-
- Status = ShellIsFile (NewName);
- FreePool (NewName);
- return (Status);
-}
-
-/**
- Function return the number converted from a hex representation of a number.
-
- Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
- result. Use ShellConvertStringToUint64 instead.
-
- @param[in] String String representation of a number.
-
- @return The unsigned integer result of the conversion.
- @retval (UINTN)(-1) An error occurred.
-**/
-UINTN
-EFIAPI
-ShellHexStrToUintn (
- IN CONST CHAR16 *String
- )
-{
- UINT64 RetVal;
-
- if (!EFI_ERROR (ShellConvertStringToUint64 (String, &RetVal, TRUE, TRUE))) {
- return ((UINTN)RetVal);
- }
-
- return ((UINTN)(-1));
-}
-
-/**
- Function to determine whether a string is decimal or hex representation of a number
- and return the number converted from the string. Spaces are always skipped.
-
- @param[in] String String representation of a number
-
- @return the number
- @retval (UINTN)(-1) An error ocurred.
-**/
-UINTN
-EFIAPI
-ShellStrToUintn (
- IN CONST CHAR16 *String
- )
-{
- UINT64 RetVal;
- BOOLEAN Hex;
-
- Hex = FALSE;
-
- if (!InternalShellIsHexOrDecimalNumber (String, Hex, TRUE, FALSE)) {
- Hex = TRUE;
- }
-
- if (!EFI_ERROR (ShellConvertStringToUint64 (String, &RetVal, Hex, TRUE))) {
- return ((UINTN)RetVal);
- }
-
- return ((UINTN)(-1));
-}
-
-/**
- Safely append with automatic string resizing given length of Destination and
- desired length of copy from Source.
-
- append the first D characters of Source to the end of Destination, where D is
- the lesser of Count and the StrLen() of Source. If appending those D characters
- will fit within Destination (whose Size is given as CurrentSize) and
- still leave room for a NULL terminator, then those characters are appended,
- starting at the original terminating NULL of Destination, and a new terminating
- NULL is appended.
-
- If appending D characters onto Destination will result in a overflow of the size
- given in CurrentSize the string will be grown such that the copy can be performed
- and CurrentSize will be updated to the new size.
-
- If Source is NULL, there is nothing to append, just return the current buffer in
- Destination.
-
- if Destination is NULL, then ASSERT()
- if Destination's current length (including NULL terminator) is already more then
- CurrentSize, then ASSERT()
-
- @param[in, out] Destination The String to append onto
- @param[in, out] CurrentSize on call the number of bytes in Destination. On
- return possibly the new size (still in bytes). if NULL
- then allocate whatever is needed.
- @param[in] Source The String to append from
- @param[in] Count Maximum number of characters to append. if 0 then
- all are appended.
-
- @return Destination return the resultant string.
-**/
-CHAR16 *
-EFIAPI
-StrnCatGrow (
- IN OUT CHAR16 **Destination,
- IN OUT UINTN *CurrentSize,
- IN CONST CHAR16 *Source,
- IN UINTN Count
- )
-{
- UINTN DestinationStartSize;
- UINTN NewSize;
-
- //
- // ASSERTs
- //
- ASSERT (Destination != NULL);
-
- //
- // If there's nothing to do then just return Destination
- //
- if (Source == NULL) {
- return (*Destination);
- }
-
- //
- // allow for un-initialized pointers, based on size being 0
- //
- if ((CurrentSize != NULL) && (*CurrentSize == 0)) {
- *Destination = NULL;
- }
-
- //
- // allow for NULL pointers address as Destination
- //
- if (*Destination != NULL) {
- ASSERT (CurrentSize != 0);
- DestinationStartSize = StrSize (*Destination);
- ASSERT (DestinationStartSize <= *CurrentSize);
- } else {
- DestinationStartSize = 0;
- // ASSERT(*CurrentSize == 0);
- }
-
- //
- // Append all of Source?
- //
- if (Count == 0) {
- Count = StrLen (Source);
- }
-
- //
- // Test and grow if required
- //
- if (CurrentSize != NULL) {
- NewSize = *CurrentSize;
- if (NewSize < DestinationStartSize + (Count * sizeof (CHAR16))) {
- while (NewSize < (DestinationStartSize + (Count*sizeof (CHAR16)))) {
- NewSize += 2 * Count * sizeof (CHAR16);
- }
-
- *Destination = ReallocatePool (*CurrentSize, NewSize, *Destination);
- *CurrentSize = NewSize;
- }
- } else {
- NewSize = (Count+1)*sizeof (CHAR16);
- *Destination = AllocateZeroPool (NewSize);
- }
-
- //
- // Now use standard StrnCat on a big enough buffer
- //
- if (*Destination == NULL) {
- return (NULL);
- }
-
- StrnCatS (*Destination, NewSize/sizeof (CHAR16), Source, Count);
- return *Destination;
-}
-
-/**
- Prompt the user and return the resultant answer to the requestor.
-
- This function will display the requested question on the shell prompt and then
- wait for an appropriate answer to be input from the console.
-
- if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
- or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
-
- if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
- CHAR16*.
-
- In either case *Response must be callee freed if Response was not NULL;
-
- @param Type What type of question is asked. This is used to filter the input
- to prevent invalid answers to question.
- @param Prompt Pointer to string prompt to use to request input.
- @param Response Pointer to Response which will be populated upon return.
-
- @retval EFI_SUCCESS The operation was successful.
- @retval EFI_UNSUPPORTED The operation is not supported as requested.
- @retval EFI_INVALID_PARAMETER A parameter was invalid.
- @return other The operation failed.
-**/
-EFI_STATUS
-EFIAPI
-ShellPromptForResponse (
- IN SHELL_PROMPT_REQUEST_TYPE Type,
- IN CHAR16 *Prompt OPTIONAL,
- IN OUT VOID **Response OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_INPUT_KEY Key;
- UINTN EventIndex;
- SHELL_PROMPT_RESPONSE *Resp;
- UINTN Size;
- CHAR16 *Buffer;
-
- Status = EFI_UNSUPPORTED;
- Resp = NULL;
- Buffer = NULL;
- Size = 0;
- if (Type != ShellPromptResponseTypeFreeform) {
- Resp = (SHELL_PROMPT_RESPONSE *)AllocateZeroPool (sizeof (SHELL_PROMPT_RESPONSE));
- if (Resp == NULL) {
- if (Response != NULL) {
- *Response = NULL;
- }
-
- return (EFI_OUT_OF_RESOURCES);
- }
- }
-
- switch (Type) {
- case ShellPromptResponseTypeQuitContinue:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- //
- // wait for valid response
- //
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- if ((Key.UnicodeChar == L'Q') || (Key.UnicodeChar == L'q')) {
- *Resp = ShellPromptResponseQuit;
- } else {
- *Resp = ShellPromptResponseContinue;
- }
-
- break;
- case ShellPromptResponseTypeYesNoCancel:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- //
- // wait for valid response
- //
- *Resp = ShellPromptResponseMax;
- while (*Resp == ShellPromptResponseMax) {
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
-
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- switch (Key.UnicodeChar) {
- case L'Y':
- case L'y':
- *Resp = ShellPromptResponseYes;
- break;
- case L'N':
- case L'n':
- *Resp = ShellPromptResponseNo;
- break;
- case L'C':
- case L'c':
- *Resp = ShellPromptResponseCancel;
- break;
- }
- }
-
- break;
- case ShellPromptResponseTypeYesNoAllCancel:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- //
- // wait for valid response
- //
- *Resp = ShellPromptResponseMax;
- while (*Resp == ShellPromptResponseMax) {
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
-
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- if ((Key.UnicodeChar <= 127) && (Key.UnicodeChar >= 32)) {
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- }
-
- switch (Key.UnicodeChar) {
- case L'Y':
- case L'y':
- *Resp = ShellPromptResponseYes;
- break;
- case L'N':
- case L'n':
- *Resp = ShellPromptResponseNo;
- break;
- case L'A':
- case L'a':
- *Resp = ShellPromptResponseAll;
- break;
- case L'C':
- case L'c':
- *Resp = ShellPromptResponseCancel;
- break;
- }
- }
-
- break;
- case ShellPromptResponseTypeEnterContinue:
- case ShellPromptResponseTypeAnyKeyContinue:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- //
- // wait for valid response
- //
- *Resp = ShellPromptResponseMax;
- while (*Resp == ShellPromptResponseMax) {
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
-
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- if (Type == ShellPromptResponseTypeEnterContinue) {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
- *Resp = ShellPromptResponseContinue;
- break;
- }
- }
-
- if (Type == ShellPromptResponseTypeAnyKeyContinue) {
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR (Status);
- *Resp = ShellPromptResponseContinue;
- break;
- }
- }
-
- break;
- case ShellPromptResponseTypeYesNo:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- //
- // wait for valid response
- //
- *Resp = ShellPromptResponseMax;
- while (*Resp == ShellPromptResponseMax) {
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
-
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- switch (Key.UnicodeChar) {
- case L'Y':
- case L'y':
- *Resp = ShellPromptResponseYes;
- break;
- case L'N':
- case L'n':
- *Resp = ShellPromptResponseNo;
- break;
- }
- }
-
- break;
- case ShellPromptResponseTypeFreeform:
- if (Prompt != NULL) {
- ShellPrintEx (-1, -1, L"%s", Prompt);
- }
-
- while (1) {
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
-
- gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
- Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- if (EFI_ERROR (Status)) {
- break;
- }
-
- ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
- if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
- break;
- }
-
- ASSERT ((Buffer == NULL && Size == 0) || (Buffer != NULL));
- StrnCatGrow (&Buffer, &Size, &Key.UnicodeChar, 1);
- }
-
- break;
- //
- // This is the location to add new prompt types.
- // If your new type loops remember to add ExecutionBreak support.
- //
- default:
- ASSERT (FALSE);
- }
-
- if (Response != NULL) {
- if (Resp != NULL) {
- *Response = Resp;
- } else if (Buffer != NULL) {
- *Response = Buffer;
- } else {
- *Response = NULL;
- }
- } else {
- if (Resp != NULL) {
- FreePool (Resp);
- }
-
- if (Buffer != NULL) {
- FreePool (Buffer);
- }
- }
-
- ShellPrintEx (-1, -1, L"\r\n");
- return (Status);
-}
-
-/**
- Prompt the user and return the resultant answer to the requestor.
-
- This function is the same as ShellPromptForResponse, except that the prompt is
- automatically pulled from HII.
-
- @param Type What type of question is asked. This is used to filter the input
- to prevent invalid answers to question.
- @param[in] HiiFormatStringId The format string Id for getting from Hii.
- @param[in] HiiFormatHandle The format string Handle for getting from Hii.
- @param Response Pointer to Response which will be populated upon return.
-
- @retval EFI_SUCCESS the operation was successful.
- @return other the operation failed.
-
- @sa ShellPromptForResponse
-**/
-EFI_STATUS
-EFIAPI
-ShellPromptForResponseHii (
- IN SHELL_PROMPT_REQUEST_TYPE Type,
- IN CONST EFI_STRING_ID HiiFormatStringId,
- IN CONST EFI_HII_HANDLE HiiFormatHandle,
- IN OUT VOID **Response
- )
-{
- CHAR16 *Prompt;
- EFI_STATUS Status;
-
- Prompt = HiiGetString (HiiFormatHandle, HiiFormatStringId, NULL);
- Status = ShellPromptForResponse (Type, Prompt, Response);
- FreePool (Prompt);
- return (Status);
-}
-
-/**
- Function to determin if an entire string is a valid number.
-
- If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
-
- @param[in] String The string to evaluate.
- @param[in] ForceHex TRUE - always assume hex.
- @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
- @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
-
- @retval TRUE It is all numeric (dec/hex) characters.
- @retval FALSE There is a non-numeric character.
-**/
-BOOLEAN
-InternalShellIsHexOrDecimalNumber (
- IN CONST CHAR16 *String,
- IN CONST BOOLEAN ForceHex,
- IN CONST BOOLEAN StopAtSpace,
- IN CONST BOOLEAN TimeNumbers
- )
-{
- BOOLEAN Hex;
- BOOLEAN LeadingZero;
-
- if (String == NULL) {
- return FALSE;
- }
-
- //
- // chop off a single negative sign
- //
- if (*String == L'-') {
- String++;
- }
-
- if (*String == CHAR_NULL) {
- return FALSE;
- }
-
- //
- // chop leading zeroes
- //
- LeadingZero = FALSE;
- while (*String == L'0') {
- String++;
- LeadingZero = TRUE;
- }
-
- //
- // allow '0x' or '0X', but not 'x' or 'X'
- //
- if ((*String == L'x') || (*String == L'X')) {
- if (!LeadingZero) {
- //
- // we got an x without a preceeding 0
- //
- return (FALSE);
- }
-
- String++;
- Hex = TRUE;
- } else if (ForceHex) {
- Hex = TRUE;
- } else {
- Hex = FALSE;
- }
-
- //
- // loop through the remaining characters and use the lib function
- //
- for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' '); String++) {
- if (TimeNumbers && (String[0] == L':')) {
- continue;
- }
-
- if (Hex) {
- if (!ShellIsHexaDecimalDigitCharacter (*String)) {
- return (FALSE);
- }
- } else {
- if (!ShellIsDecimalDigitCharacter (*String)) {
- return (FALSE);
- }
- }
- }
-
- return (TRUE);
-}
-
-/**
- Function to determine if a given filename exists.
-
- @param[in] Name Path to test.
-
- @retval EFI_SUCCESS The Path represents a file.
- @retval EFI_NOT_FOUND The Path does not represent a file.
- @retval other The path failed to open.
-**/
-EFI_STATUS
-EFIAPI
-ShellFileExists (
- IN CONST CHAR16 *Name
- )
-{
- EFI_STATUS Status;
- EFI_SHELL_FILE_INFO *List;
-
- ASSERT (Name != NULL);
-
- List = NULL;
- Status = ShellOpenFileMetaArg ((CHAR16 *)Name, EFI_FILE_MODE_READ, &List);
- if (EFI_ERROR (Status)) {
- return (Status);
- }
-
- ShellCloseFileMetaArg (&List);
-
- return (EFI_SUCCESS);
-}
-
-/**
- Convert a Unicode character to numerical value.
-
- This internal function only deal with Unicode character
- which maps to a valid hexadecimal ASII character, i.e.
- L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
- Unicode character, the value returned does not make sense.
-
- @param Char The character to convert.
-
- @return The numerical value converted.
-
-**/
-UINTN
-InternalShellHexCharToUintn (
- IN CHAR16 Char
- )
-{
- if (ShellIsDecimalDigitCharacter (Char)) {
- return Char - L'0';
- }
-
- return (10 + CharToUpper (Char) - L'A');
-}
-
-/**
- Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
-
- This function returns a value of type UINT64 by interpreting the contents
- of the Unicode string specified by String as a hexadecimal number.
- The format of the input Unicode string String is:
-
- [spaces][zeros][x][hexadecimal digits].
-
- The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
- The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
- If "x" appears in the input string, it must be prefixed with at least one 0.
- The function will ignore the pad space, which includes spaces or tab characters,
- before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
- [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
- first valid hexadecimal digit. Then, the function stops at the first character that is
- a not a valid hexadecimal character or NULL, whichever one comes first.
-
- If String has only pad spaces, then zero is returned.
- If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
- then zero is returned.
-
- @param[in] String A pointer to a Null-terminated Unicode string.
- @param[out] Value Upon a successful return the value of the conversion.
- @param[in] StopAtSpace FALSE to skip spaces.
-
- @retval EFI_SUCCESS The conversion was successful.
- @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
- @retval EFI_DEVICE_ERROR An overflow occurred.
-**/
-EFI_STATUS
-InternalShellStrHexToUint64 (
- IN CONST CHAR16 *String,
- OUT UINT64 *Value,
- IN CONST BOOLEAN StopAtSpace
- )
-{
- UINT64 Result;
-
- if ((String == NULL) || (StrSize (String) == 0) || (Value == NULL)) {
- return (EFI_INVALID_PARAMETER);
- }
-
- //
- // Ignore the pad spaces (space or tab)
- //
- while ((*String == L' ') || (*String == L'\t')) {
- String++;
- }
-
- //
- // Ignore leading Zeros after the spaces
- //
- while (*String == L'0') {
- String++;
- }
-
- if (CharToUpper (*String) == L'X') {
- if (*(String - 1) != L'0') {
- return 0;
- }
-
- //
- // Skip the 'X'
- //
- String++;
- }
-
- Result = 0;
-
- //
- // there is a space where there should't be
- //
- if (*String == L' ') {
- return (EFI_INVALID_PARAMETER);
- }
-
- while (ShellIsHexaDecimalDigitCharacter (*String)) {
- //
- // If the Hex Number represented by String overflows according
- // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
- //
- if (!(Result <= (RShiftU64 ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
- // if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
- return (EFI_DEVICE_ERROR);
- }
-
- Result = (LShiftU64 (Result, 4));
- Result += InternalShellHexCharToUintn (*String);
- String++;
-
- //
- // stop at spaces if requested
- //
- if (StopAtSpace && (*String == L' ')) {
- break;
- }
- }
-
- *Value = Result;
- return (EFI_SUCCESS);
-}
-
-/**
- Convert a Null-terminated Unicode decimal string to a value of
- type UINT64.
-
- This function returns a value of type UINT64 by interpreting the contents
- of the Unicode string specified by String as a decimal number. The format
- of the input Unicode string String is:
-
- [spaces] [decimal digits].
-
- The valid decimal digit character is in the range [0-9]. The
- function will ignore the pad space, which includes spaces or
- tab characters, before [decimal digits]. The running zero in the
- beginning of [decimal digits] will be ignored. Then, the function
- stops at the first character that is a not a valid decimal character
- or a Null-terminator, whichever one comes first.
-
- If String has only pad spaces, then 0 is returned.
- If String has no pad spaces or valid decimal digits,
- then 0 is returned.
-
- @param[in] String A pointer to a Null-terminated Unicode string.
- @param[out] Value Upon a successful return the value of the conversion.
- @param[in] StopAtSpace FALSE to skip spaces.
-
- @retval EFI_SUCCESS The conversion was successful.
- @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
- @retval EFI_DEVICE_ERROR An overflow occurred.
-**/
-EFI_STATUS
-InternalShellStrDecimalToUint64 (
- IN CONST CHAR16 *String,
- OUT UINT64 *Value,
- IN CONST BOOLEAN StopAtSpace
- )
-{
- UINT64 Result;
-
- if ((String == NULL) || (StrSize (String) == 0) || (Value == NULL)) {
- return (EFI_INVALID_PARAMETER);
- }
-
- //
- // Ignore the pad spaces (space or tab)
- //
- while ((*String == L' ') || (*String == L'\t')) {
- String++;
- }
-
- //
- // Ignore leading Zeros after the spaces
- //
- while (*String == L'0') {
- String++;
- }
-
- Result = 0;
-
- //
- // Stop upon space if requested
- // (if the whole value was 0)
- //
- if (StopAtSpace && (*String == L' ')) {
- *Value = Result;
- return (EFI_SUCCESS);
- }
-
- while (ShellIsDecimalDigitCharacter (*String)) {
- //
- // If the number represented by String overflows according
- // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
- //
-
- if (!(Result <= (DivU64x32 ((((UINT64) ~0) - (*String - L'0')), 10)))) {
- return (EFI_DEVICE_ERROR);
- }
-
- Result = MultU64x32 (Result, 10) + (*String - L'0');
- String++;
-
- //
- // Stop at spaces if requested
- //
- if (StopAtSpace && (*String == L' ')) {
- break;
- }
- }
-
- *Value = Result;
-
- return (EFI_SUCCESS);
-}
-
-/**
- Function to verify and convert a string to its numerical value.
-
- If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
-
- @param[in] String The string to evaluate.
- @param[out] Value Upon a successful return the value of the conversion.
- @param[in] ForceHex TRUE - always assume hex.
- @param[in] StopAtSpace FALSE to skip spaces.
-
- @retval EFI_SUCCESS The conversion was successful.
- @retval EFI_INVALID_PARAMETER String contained an invalid character.
- @retval EFI_NOT_FOUND String was a number, but Value was NULL.
-**/
-EFI_STATUS
-EFIAPI
-ShellConvertStringToUint64 (
- IN CONST CHAR16 *String,
- OUT UINT64 *Value,
- IN CONST BOOLEAN ForceHex,
- IN CONST BOOLEAN StopAtSpace
- )
-{
- UINT64 RetVal;
- CONST CHAR16 *Walker;
- EFI_STATUS Status;
- BOOLEAN Hex;
-
- Hex = ForceHex;
-
- if (!InternalShellIsHexOrDecimalNumber (String, Hex, StopAtSpace, FALSE)) {
- if (!Hex) {
- Hex = TRUE;
- if (!InternalShellIsHexOrDecimalNumber (String, Hex, StopAtSpace, FALSE)) {
- return (EFI_INVALID_PARAMETER);
- }
- } else {
- return (EFI_INVALID_PARAMETER);
- }
- }
-
- //
- // Chop off leading spaces
- //
- for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++) {
- }
-
- //
- // make sure we have something left that is numeric.
- //
- if ((Walker == NULL) || (*Walker == CHAR_NULL) || !InternalShellIsHexOrDecimalNumber (Walker, Hex, StopAtSpace, FALSE)) {
- return (EFI_INVALID_PARAMETER);
- }
-
- //
- // do the conversion.
- //
- if (Hex || (StrnCmp (Walker, L"0x", 2) == 0) || (StrnCmp (Walker, L"0X", 2) == 0)) {
- Status = InternalShellStrHexToUint64 (Walker, &RetVal, StopAtSpace);
- } else {
- Status = InternalShellStrDecimalToUint64 (Walker, &RetVal, StopAtSpace);
- }
-
- if ((Value == NULL) && !EFI_ERROR (Status)) {
- return (EFI_NOT_FOUND);
- }
-
- if (Value != NULL) {
- *Value = RetVal;
- }
-
- return (Status);
-}
-
-/**
- Function to determin if an entire string is a valid number.
-
- If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
-
- @param[in] String The string to evaluate.
- @param[in] ForceHex TRUE - always assume hex.
- @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
-
- @retval TRUE It is all numeric (dec/hex) characters.
- @retval FALSE There is a non-numeric character.
-**/
-BOOLEAN
-EFIAPI
-ShellIsHexOrDecimalNumber (
- IN CONST CHAR16 *String,
- IN CONST BOOLEAN ForceHex,
- IN CONST BOOLEAN StopAtSpace
- )
-{
- if (ShellConvertStringToUint64 (String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {
- return (TRUE);
- }
-
- return (FALSE);
-}
-
-/**
- Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
- buffer. The returned buffer must be callee freed.
-
- If the position upon start is 0, then the Ascii Boolean will be set. This should be
- maintained and not changed for all operations with the same file.
-
- @param[in] Handle SHELL_FILE_HANDLE to read from.
- @param[in, out] Ascii Boolean value for indicating whether the file is
- Ascii (TRUE) or UCS2 (FALSE).
-
- @return The line of text from the file.
- @retval NULL There was not enough memory available.
-
- @sa ShellFileHandleReadLine
-**/
-CHAR16 *
-EFIAPI
-ShellFileHandleReturnLine (
- IN SHELL_FILE_HANDLE Handle,
- IN OUT BOOLEAN *Ascii
- )
-{
- CHAR16 *RetVal;
- UINTN Size;
- EFI_STATUS Status;
-
- Size = 0;
- RetVal = NULL;
-
- Status = ShellFileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- RetVal = AllocateZeroPool (Size);
- if (RetVal == NULL) {
- return (NULL);
- }
-
- Status = ShellFileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii);
- }
-
- if ((Status == EFI_END_OF_FILE) && (RetVal != NULL) && (*RetVal != CHAR_NULL)) {
- Status = EFI_SUCCESS;
- }
-
- if (EFI_ERROR (Status) && (RetVal != NULL)) {
- FreePool (RetVal);
- RetVal = NULL;
- }
-
- return (RetVal);
-}
-
-/**
- Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
-
- If the position upon start is 0, then the Ascii Boolean will be set. This should be
- maintained and not changed for all operations with the same file.
-
- NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
- IS IN ASCII FORMAT.
-
- @param[in] Handle SHELL_FILE_HANDLE to read from.
- @param[in, out] Buffer The pointer to buffer to read into. If this function
- returns EFI_SUCCESS, then on output Buffer will
- contain a UCS2 string, even if the file being
- read is ASCII.
- @param[in, out] Size On input, pointer to number of bytes in Buffer.
- On output, unchanged unless Buffer is too small
- to contain the next line of the file. In that
- case Size is set to the number of bytes needed
- to hold the next line of the file (as a UCS2
- string, even if it is an ASCII file).
- @param[in] Truncate If the buffer is large enough, this has no effect.
- If the buffer is is too small and Truncate is TRUE,
- the line will be truncated.
- If the buffer is is too small and Truncate is FALSE,
- then no read will occur.
-
- @param[in, out] Ascii Boolean value for indicating whether the file is
- Ascii (TRUE) or UCS2 (FALSE).
-
- @retval EFI_SUCCESS The operation was successful. The line is stored in
- Buffer.
- @retval EFI_END_OF_FILE There are no more lines in the file.
- @retval EFI_INVALID_PARAMETER Handle was NULL.
- @retval EFI_INVALID_PARAMETER Size was NULL.
- @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
- Size was updated to the minimum space required.
-**/
-EFI_STATUS
-EFIAPI
-ShellFileHandleReadLine (
- IN SHELL_FILE_HANDLE Handle,
- IN OUT CHAR16 *Buffer,
- IN OUT UINTN *Size,
- IN BOOLEAN Truncate,
- IN OUT BOOLEAN *Ascii
- )
-{
- EFI_STATUS Status;
- CHAR16 CharBuffer;
- UINTN CharSize;
- UINTN CountSoFar;
- UINT64 OriginalFilePosition;
-
- if ( (Handle == NULL)
- || (Size == NULL)
- )
- {
- return (EFI_INVALID_PARAMETER);
- }
-
- if (Buffer == NULL) {
- ASSERT (*Size == 0);
- } else {
- *Buffer = CHAR_NULL;
- }
-
- gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);
- if (OriginalFilePosition == 0) {
- CharSize = sizeof (CHAR16);
- Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
- ASSERT_EFI_ERROR (Status);
- if (CharBuffer == gUnicodeFileTag) {
- *Ascii = FALSE;
- } else {
- *Ascii = TRUE;
- gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition);
- }
- }
-
- if (*Ascii) {
- CharSize = sizeof (CHAR8);
- } else {
- CharSize = sizeof (CHAR16);
- }
-
- for (CountSoFar = 0; ; CountSoFar++) {
- CharBuffer = 0;
- Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
- if ( EFI_ERROR (Status)
- || (CharSize == 0)
- || ((CharBuffer == L'\n') && !(*Ascii))
- || ((CharBuffer == '\n') && *Ascii)
- )
- {
- if (CharSize == 0) {
- Status = EFI_END_OF_FILE;
- }
-
- break;
- }
-
- //
- // if we have space save it...
- //
- if ((CountSoFar+1)*sizeof (CHAR16) < *Size) {
- ASSERT (Buffer != NULL);
- ((CHAR16 *)Buffer)[CountSoFar] = CharBuffer;
- ((CHAR16 *)Buffer)[CountSoFar+1] = CHAR_NULL;
- }
- }
-
- //
- // if we ran out of space tell when...
- //
- if ((CountSoFar+1)*sizeof (CHAR16) > *Size) {
- *Size = (CountSoFar+1)*sizeof (CHAR16);
- if (!Truncate) {
- gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition);
- } else {
- DEBUG ((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
- }
-
- return (EFI_BUFFER_TOO_SMALL);
- }
-
- while (Buffer[StrLen (Buffer)-1] == L'\r') {
- Buffer[StrLen (Buffer)-1] = CHAR_NULL;
- }
-
- return (Status);
-}
-
-/**
- Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
-
- @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
- @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
- @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
- the help content only.
- @retval EFI_DEVICE_ERROR The help data format was incorrect.
- @retval EFI_NOT_FOUND The help data could not be found.
- @retval EFI_SUCCESS The operation was successful.
-**/
-EFI_STATUS
-EFIAPI
-ShellPrintHelp (
- IN CONST CHAR16 *CommandToGetHelpOn,
- IN CONST CHAR16 *SectionToGetHelpOn,
- IN BOOLEAN PrintCommandText
- )
-{
- EFI_STATUS Status;
- CHAR16 *OutText;
-
- OutText = NULL;
-
- //
- // Get the string to print based
- //
- Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
-
- //
- // make sure we got a valid string
- //
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((OutText == NULL) || (StrLen (OutText) == 0)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Chop off trailing stuff we dont need
- //
- while (OutText[StrLen (OutText)-1] == L'\r' || OutText[StrLen (OutText)-1] == L'\n' || OutText[StrLen (OutText)-1] == L' ') {
- OutText[StrLen (OutText)-1] = CHAR_NULL;
- }
-
- //
- // Print this out to the console
- //
- if (PrintCommandText) {
- ShellPrintEx (-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
- } else {
- ShellPrintEx (-1, -1, L"%N%s\r\n", OutText);
- }
-
- SHELL_FREE_NON_NULL (OutText);
-
- return EFI_SUCCESS;
-}
-
-/**
- Function to delete a file by name
-
- @param[in] FileName Pointer to file name to delete.
-
- @retval EFI_SUCCESS the file was deleted sucessfully
- @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
- deleted
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_NOT_FOUND The specified file could not be found on the
- device or the file system could not be found
- on the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
- medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
- file.
- @retval other The file failed to open
-**/
-EFI_STATUS
-EFIAPI
-ShellDeleteFileByName (
- IN CONST CHAR16 *FileName
- )
-{
- EFI_STATUS Status;
- SHELL_FILE_HANDLE FileHandle;
-
- Status = ShellFileExists (FileName);
-
- if (Status == EFI_SUCCESS) {
- Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
- if (Status == EFI_SUCCESS) {
- Status = ShellDeleteFile (&FileHandle);
- }
- }
-
- return (Status);
-}
-
-/**
- Cleans off all the quotes in the string.
-
- @param[in] OriginalString pointer to the string to be cleaned.
- @param[out] CleanString The new string with all quotes removed.
- Memory allocated in the function and free
- by caller.
-
- @retval EFI_SUCCESS The operation was successful.
-**/
-EFI_STATUS
-InternalShellStripQuotes (
- IN CONST CHAR16 *OriginalString,
- OUT CHAR16 **CleanString
- )
-{
- CHAR16 *Walker;
-
- if ((OriginalString == NULL) || (CleanString == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
- if (*CleanString == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL; Walker++) {
- if (*Walker == L'\"') {
- CopyMem (Walker, Walker+1, StrSize (Walker) - sizeof (Walker[0]));
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ Provides interface to shell functionality for shell commands and applications.
+
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright 2016-2018 Dell Technologies.<BR>
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023, Apple Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UefiShellLib.h"
+#include <Library/SortLib.h>
+#include <Library/BaseLib.h>
+
+//
+// globals...
+//
+SHELL_PARAM_ITEM EmptyParamList[] = {
+ { NULL, TypeMax }
+};
+SHELL_PARAM_ITEM SfoParamList[] = {
+ { L"-sfo", TypeFlag },
+ { NULL, TypeMax }
+};
+EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
+EFI_SHELL_INTERFACE *mEfiShellInterface;
+EFI_SHELL_PROTOCOL *gEfiShellProtocol;
+EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
+EFI_HANDLE mEfiShellEnvironment2Handle;
+FILE_HANDLE_FUNCTION_MAP FileFunctionMap;
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationProtocol;
+
+/**
+ Return a clean, fully-qualified version of an input path. If the return value
+ is non-NULL the caller must free the memory when it is no longer needed.
+
+ If asserts are disabled, and if the input parameter is NULL, NULL is returned.
+
+ If there is not enough memory available to create the fully-qualified path or
+ a copy of the input path, NULL is returned.
+
+ If there is no working directory, a clean copy of Path is returned.
+
+ Otherwise, the current file system or working directory (as appropriate) is
+ prepended to Path and the resulting path is cleaned and returned.
+
+ NOTE: If the input path is an empty string, then the current working directory
+ (if it exists) is returned. In other words, an empty input path is treated
+ exactly the same as ".".
+
+ @param[in] Path A pointer to some file or directory path.
+
+ @retval NULL The input path is NULL or out of memory.
+
+ @retval non-NULL A pointer to a clean, fully-qualified version of Path.
+ If there is no working directory, then a pointer to a
+ clean, but not necessarily fully-qualified version of
+ Path. The caller must free this memory when it is no
+ longer needed.
+**/
+CHAR16 *
+EFIAPI
+FullyQualifyPath (
+ IN CONST CHAR16 *Path
+ )
+{
+ CONST CHAR16 *WorkingPath;
+ CONST CHAR16 *InputPath;
+ CHAR16 *CharPtr;
+ CHAR16 *InputFileSystem;
+ UINTN FileSystemCharCount;
+ CHAR16 *FullyQualifiedPath;
+ UINTN Size;
+
+ FullyQualifiedPath = NULL;
+
+ ASSERT (Path != NULL);
+ //
+ // Handle erroneous input when asserts are disabled.
+ //
+ if (Path == NULL) {
+ return NULL;
+ }
+
+ //
+ // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,
+ // we have to consider the file system part separately from the "path" part.
+ // If there is a file system in the path, we have to get the current working
+ // directory for that file system. Then we need to use the part of the path
+ // following the ":". If a path does not contain ":", we use it as given.
+ //
+ InputPath = StrStr (Path, L":");
+ if (InputPath != NULL) {
+ InputPath++;
+ FileSystemCharCount = ((UINTN)InputPath - (UINTN)Path + sizeof (CHAR16)) / sizeof (CHAR16);
+ InputFileSystem = AllocateCopyPool (FileSystemCharCount * sizeof (CHAR16), Path);
+ if (InputFileSystem != NULL) {
+ InputFileSystem[FileSystemCharCount - 1] = CHAR_NULL;
+ }
+
+ WorkingPath = ShellGetCurrentDir (InputFileSystem);
+ SHELL_FREE_NON_NULL (InputFileSystem);
+ } else {
+ InputPath = Path;
+ WorkingPath = ShellGetEnvironmentVariable (L"cwd");
+ }
+
+ if (WorkingPath == NULL) {
+ //
+ // With no working directory, all we can do is copy and clean the input path.
+ //
+ FullyQualifiedPath = AllocateCopyPool (StrSize (Path), Path);
+ } else {
+ //
+ // Allocate space for both strings plus one more character.
+ //
+ Size = StrSize (WorkingPath) + StrSize (InputPath);
+ FullyQualifiedPath = AllocateZeroPool (Size);
+ if (FullyQualifiedPath == NULL) {
+ //
+ // Try to copy and clean just the input. No harm if not enough memory.
+ //
+ FullyQualifiedPath = AllocateCopyPool (StrSize (Path), Path);
+ } else {
+ if ((*InputPath == L'\\') || (*InputPath == L'/')) {
+ //
+ // Absolute path: start with the current working directory, then
+ // truncate the new path after the file system part.
+ //
+ StrCpyS (FullyQualifiedPath, Size/sizeof (CHAR16), WorkingPath);
+ CharPtr = StrStr (FullyQualifiedPath, L":");
+ if (CharPtr != NULL) {
+ *(CharPtr + 1) = CHAR_NULL;
+ }
+ } else {
+ //
+ // Relative path: start with the working directory and append "\".
+ //
+ StrCpyS (FullyQualifiedPath, Size/sizeof (CHAR16), WorkingPath);
+ StrCatS (FullyQualifiedPath, Size/sizeof (CHAR16), L"\\");
+ }
+
+ //
+ // Now append the absolute or relative path.
+ //
+ StrCatS (FullyQualifiedPath, Size/sizeof (CHAR16), InputPath);
+ }
+ }
+
+ PathCleanUpDirectories (FullyQualifiedPath);
+
+ return FullyQualifiedPath;
+}
+
+/**
+ Check if a Unicode character is a hexadecimal character.
+
+ This internal function checks if a Unicode character is a
+ numeric character. The valid hexadecimal characters are
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+ShellIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN)((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
+}
+
+/**
+ Check if a Unicode character is a decimal character.
+
+ This internal function checks if a Unicode character is a
+ decimal character. The valid characters are
+ L'0' to L'9'.
+
+
+ @param Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+ShellIsDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN)(Char >= L'0' && Char <= L'9');
+}
+
+/**
+ Helper function to find ShellEnvironment2 for constructor.
+
+ @param[in] ImageHandle A copy of the calling image's handle.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+**/
+EFI_STATUS
+ShellFindSE2 (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Buffer;
+ UINTN BufferSize;
+ UINTN HandleIndex;
+
+ BufferSize = 0;
+ Buffer = NULL;
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiShellEnvironment2Guid,
+ (VOID **)&mEfiShellEnvironment2,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // look for the mEfiShellEnvironment2 protocol at a higher level
+ //
+ if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))) {
+ //
+ // figure out how big of a buffer we need.
+ //
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiShellEnvironment2Guid,
+ NULL, // ignored for ByProtocol
+ &BufferSize,
+ Buffer
+ );
+ //
+ // maybe it's not there???
+ //
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Buffer = (EFI_HANDLE *)AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiShellEnvironment2Guid,
+ NULL, // ignored for ByProtocol
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ if (!EFI_ERROR (Status) && (Buffer != NULL)) {
+ //
+ // now parse the list of returned handles
+ //
+ Status = EFI_NOT_FOUND;
+ for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof (Buffer[0])); HandleIndex++) {
+ Status = gBS->OpenProtocol (
+ Buffer[HandleIndex],
+ &gEfiShellEnvironment2Guid,
+ (VOID **)&mEfiShellEnvironment2,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) {
+ mEfiShellEnvironment2Handle = Buffer[HandleIndex];
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ return (Status);
+}
+
+/**
+ Function to do most of the work of the constructor. Allows for calling
+ multiple times without complete re-initialization.
+
+ @param[in] ImageHandle A copy of the ImageHandle.
+ @param[in] SystemTable A pointer to the SystemTable for the application.
+
+ @retval EFI_SUCCESS The operationw as successful.
+**/
+EFI_STATUS
+ShellLibConstructorWorker (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (gEfiShellProtocol == NULL) {
+ //
+ // UEFI 2.0 shell interfaces (used preferentially)
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiShellProtocolGuid,
+ (VOID **)&gEfiShellProtocol,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Search for the shell protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **)&gEfiShellProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ gEfiShellProtocol = NULL;
+ }
+ }
+ }
+
+ if (gEfiShellParametersProtocol == NULL) {
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID **)&gEfiShellParametersProtocol,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ gEfiShellParametersProtocol = NULL;
+ }
+ }
+
+ if (gEfiShellProtocol == NULL) {
+ //
+ // Moved to seperate function due to complexity
+ //
+ Status = ShellFindSE2 (ImageHandle);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
+ mEfiShellEnvironment2 = NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiShellInterfaceGuid,
+ (VOID **)&mEfiShellInterface,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ mEfiShellInterface = NULL;
+ }
+ }
+
+ //
+ // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol
+ // or UEFI Shell's Shell protocol.
+ // When ShellLib is linked to a driver producing DynamicCommand protocol,
+ // ShellParameters protocol is set by DynamicCommand.Handler().
+ //
+ if (((mEfiShellEnvironment2 != NULL) && (mEfiShellInterface != NULL)) ||
+ (gEfiShellProtocol != NULL)
+ )
+ {
+ if (gEfiShellProtocol != NULL) {
+ FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;
+ FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;
+ FileFunctionMap.ReadFile = gEfiShellProtocol->ReadFile;
+ FileFunctionMap.WriteFile = gEfiShellProtocol->WriteFile;
+ FileFunctionMap.CloseFile = gEfiShellProtocol->CloseFile;
+ FileFunctionMap.DeleteFile = gEfiShellProtocol->DeleteFile;
+ FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition;
+ FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition;
+ FileFunctionMap.FlushFile = gEfiShellProtocol->FlushFile;
+ FileFunctionMap.GetFileSize = gEfiShellProtocol->GetFileSize;
+ } else {
+ FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo;
+ FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo;
+ FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead;
+ FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite;
+ FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose;
+ FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete;
+ FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition;
+ FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition;
+ FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush;
+ FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize;
+ }
+
+ return (EFI_SUCCESS);
+ }
+
+ return (EFI_NOT_FOUND);
+}
+
+/**
+ Constructor for the Shell library.
+
+ Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
+
+ @param ImageHandle the image handle of the process
+ @param SystemTable the EFI System Table pointer
+
+ @retval EFI_SUCCESS the initialization was complete successfully
+ @return others an error ocurred during initialization
+**/
+EFI_STATUS
+EFIAPI
+ShellLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mEfiShellEnvironment2 = NULL;
+ gEfiShellProtocol = NULL;
+ gEfiShellParametersProtocol = NULL;
+ mEfiShellInterface = NULL;
+ mEfiShellEnvironment2Handle = NULL;
+ mUnicodeCollationProtocol = NULL;
+
+ //
+ // verify that auto initialize is not set false
+ //
+ if (PcdGetBool (PcdShellLibAutoInitialize) == 0) {
+ return (EFI_SUCCESS);
+ }
+
+ return (ShellLibConstructorWorker (ImageHandle, SystemTable));
+}
+
+/**
+ Destructor for the library. free any resources.
+
+ @param[in] ImageHandle A copy of the ImageHandle.
+ @param[in] SystemTable A pointer to the SystemTable for the application.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @return An error from the CloseProtocol function.
+**/
+EFI_STATUS
+EFIAPI
+ShellLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (mEfiShellEnvironment2 != NULL) {
+ Status = gBS->CloseProtocol (
+ mEfiShellEnvironment2Handle == NULL ? ImageHandle : mEfiShellEnvironment2Handle,
+ &gEfiShellEnvironment2Guid,
+ ImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ mEfiShellEnvironment2 = NULL;
+ mEfiShellEnvironment2Handle = NULL;
+ }
+ }
+
+ if (mEfiShellInterface != NULL) {
+ Status = gBS->CloseProtocol (
+ ImageHandle,
+ &gEfiShellInterfaceGuid,
+ ImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ mEfiShellInterface = NULL;
+ }
+ }
+
+ if (gEfiShellProtocol != NULL) {
+ Status = gBS->CloseProtocol (
+ ImageHandle,
+ &gEfiShellProtocolGuid,
+ ImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ gEfiShellProtocol = NULL;
+ }
+ }
+
+ if (gEfiShellParametersProtocol != NULL) {
+ Status = gBS->CloseProtocol (
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ ImageHandle,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ gEfiShellParametersProtocol = NULL;
+ }
+ }
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ This function causes the shell library to initialize itself. If the shell library
+ is already initialized it will de-initialize all the current protocol pointers and
+ re-populate them again.
+
+ When the library is used with PcdShellLibAutoInitialize set to true this function
+ will return EFI_SUCCESS and perform no actions.
+
+ This function is intended for internal access for shell commands only.
+
+ @retval EFI_SUCCESS the initialization was complete successfully
+
+**/
+EFI_STATUS
+EFIAPI
+ShellInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // if auto initialize is not false then skip
+ //
+ if (PcdGetBool (PcdShellLibAutoInitialize) != 0) {
+ return (EFI_SUCCESS);
+ }
+
+ //
+ // deinit the current stuff
+ //
+ Status = ShellLibDestructor (gImageHandle, gST);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // init the new stuff
+ //
+ return (ShellLibConstructorWorker (gImageHandle, gST));
+}
+
+/**
+ This function will retrieve the information about the file for the handle
+ specified and store it in allocated pool memory.
+
+ This function allocates a buffer to store the file's information. It is the
+ caller's responsibility to free the buffer
+
+ @param FileHandle The file handle of the file for which information is
+ being requested.
+
+ @retval NULL information could not be retrieved.
+
+ @return the information about the file
+**/
+EFI_FILE_INFO *
+EFIAPI
+ShellGetFileInfo (
+ IN SHELL_FILE_HANDLE FileHandle
+ )
+{
+ return (FileFunctionMap.GetFileInfo (FileHandle));
+}
+
+/**
+ This function sets the information about the file for the opened handle
+ specified.
+
+ @param[in] FileHandle The file handle of the file for which information
+ is being set.
+
+ @param[in] FileInfo The information to set.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
+ @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+ShellSetFileInfo (
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN EFI_FILE_INFO *FileInfo
+ )
+{
+ return (FileFunctionMap.SetFileInfo (FileHandle, FileInfo));
+}
+
+/**
+This function will open a file or directory referenced by DevicePath.
+
+This function opens a file with the open mode according to the file path. The
+Attributes is valid only for EFI_FILE_MODE_CREATE.
+
+@param FilePath on input the device path to the file. On output
+ the remaining device path.
+@param FileHandle pointer to the file handle.
+@param OpenMode the mode to open the file with.
+@param Attributes the file's file attributes.
+
+@retval EFI_SUCCESS The information was set.
+@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+@retval EFI_UNSUPPORTED Could not open the file path.
+@retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found on
+ the device.
+@retval EFI_NO_MEDIA The device has no medium.
+@retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+@retval EFI_DEVICE_ERROR The device reported an error.
+@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+@retval EFI_WRITE_PROTECTED The file or medium is write protected.
+@retval EFI_ACCESS_DENIED The file was opened read only.
+@retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+@retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+ShellOpenFileByDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT SHELL_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ CHAR16 *FileName;
+ EFI_STATUS Status;
+ EFI_FILE_PROTOCOL *File;
+
+ if ((FilePath == NULL) || (FileHandle == NULL)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // which shell interface should we use
+ //
+ if (gEfiShellProtocol != NULL) {
+ //
+ // use UEFI Shell 2.0 method.
+ //
+ FileName = gEfiShellProtocol->GetFilePathFromDevicePath (*FilePath);
+ if (FileName == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Status = ShellOpenFileByName (FileName, FileHandle, OpenMode, Attributes);
+ FreePool (FileName);
+ return (Status);
+ }
+
+ //
+ // use old shell method.
+ //
+ Status = EfiOpenFileByDevicePath (FilePath, &File, OpenMode, Attributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
+ //
+ *FileHandle = (VOID *)File;
+ return (EFI_SUCCESS);
+}
+
+/**
+ This function will open a file or directory referenced by filename.
+
+ If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
+ otherwise, the Filehandle is NULL. The Attributes is valid only for
+ EFI_FILE_MODE_CREATE.
+
+ if FileName is NULL then ASSERT()
+
+ @param FileName pointer to file name
+ @param FileHandle pointer to the file handle.
+ @param OpenMode the mode to open the file with.
+ @param Attributes the file's file attributes.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found
+ on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+ShellOpenFileByName (
+ IN CONST CHAR16 *FileName,
+ OUT SHELL_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ CHAR16 *FileNameCopy;
+ EFI_STATUS Status2;
+
+ //
+ // ASSERT if FileName is NULL
+ //
+ ASSERT (FileName != NULL);
+
+ if (FileName == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if (gEfiShellProtocol != NULL) {
+ if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
+ //
+ // Create only a directory
+ //
+ if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
+ return ShellCreateDirectory (FileName, FileHandle);
+ }
+
+ //
+ // Create the directory to create the file in
+ //
+ FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
+ if (FileNameCopy == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ PathCleanUpDirectories (FileNameCopy);
+ if (PathRemoveLastItem (FileNameCopy)) {
+ if (!EFI_ERROR (ShellCreateDirectory (FileNameCopy, FileHandle))) {
+ ShellCloseFile (FileHandle);
+ }
+ }
+
+ SHELL_FREE_NON_NULL (FileNameCopy);
+ }
+
+ //
+ // Use UEFI Shell 2.0 method to create the file
+ //
+ Status = gEfiShellProtocol->OpenFileByName (
+ FileName,
+ FileHandle,
+ OpenMode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mUnicodeCollationProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **)&mUnicodeCollationProtocol);
+ if (EFI_ERROR (Status)) {
+ gEfiShellProtocol->CloseFile (*FileHandle);
+ return Status;
+ }
+ }
+
+ if ((mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16 *)FileName, L"NUL") != 0) &&
+ (mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16 *)FileName, L"NULL") != 0) &&
+ !EFI_ERROR (Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0))
+ {
+ FileInfo = FileFunctionMap.GetFileInfo (*FileHandle);
+ ASSERT (FileInfo != NULL);
+ FileInfo->Attribute = Attributes;
+ Status2 = FileFunctionMap.SetFileInfo (*FileHandle, FileInfo);
+ FreePool (FileInfo);
+ if (EFI_ERROR (Status2)) {
+ gEfiShellProtocol->CloseFile (*FileHandle);
+ }
+
+ Status = Status2;
+ }
+
+ return (Status);
+ }
+
+ //
+ // Using EFI Shell version
+ // this means convert name to path and call that function
+ // since this will use EFI method again that will open it.
+ //
+ ASSERT (mEfiShellEnvironment2 != NULL);
+ FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16 *)FileName);
+ if (FilePath != NULL) {
+ return (ShellOpenFileByDevicePath (
+ &FilePath,
+ FileHandle,
+ OpenMode,
+ Attributes
+ ));
+ }
+
+ return (EFI_DEVICE_ERROR);
+}
+
+/**
+ This function create a directory
+
+ If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
+ otherwise, the Filehandle is NULL. If the directory already existed, this
+ function opens the existing directory.
+
+ @param DirectoryName pointer to directory name
+ @param FileHandle pointer to the file handle.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found
+ on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval EFI_VOLUME_FULL The volume is full.
+ @sa ShellOpenFileByName
+**/
+EFI_STATUS
+EFIAPI
+ShellCreateDirectory (
+ IN CONST CHAR16 *DirectoryName,
+ OUT SHELL_FILE_HANDLE *FileHandle
+ )
+{
+ if (gEfiShellProtocol != NULL) {
+ //
+ // Use UEFI Shell 2.0 method
+ //
+ return (gEfiShellProtocol->CreateFile (
+ DirectoryName,
+ EFI_FILE_DIRECTORY,
+ FileHandle
+ ));
+ } else {
+ return (ShellOpenFileByName (
+ DirectoryName,
+ FileHandle,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
+ EFI_FILE_DIRECTORY
+ ));
+ }
+}
+
+/**
+ This function reads information from an opened file.
+
+ If FileHandle is not a directory, the function reads the requested number of
+ bytes from the file at the file's current position and returns them in Buffer.
+ If the read goes beyond the end of the file, the read length is truncated to the
+ end of the file. The file's current position is increased by the number of bytes
+ returned. If FileHandle is a directory, the function reads the directory entry
+ at the file's current position and returns the entry in Buffer. If the Buffer
+ is not large enough to hold the current directory entry, then
+ EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
+ BufferSize is set to be the size of the buffer needed to read the entry. On
+ success, the current position is updated to the next directory entry. If there
+ are no more directory entries, the read returns a zero-length buffer.
+ EFI_FILE_INFO is the structure returned as the directory entry.
+
+ @param FileHandle the opened file handle
+ @param BufferSize on input the size of buffer in bytes. on return
+ the number of bytes written.
+ @param Buffer the buffer to put read data into.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
+ size.
+
+**/
+EFI_STATUS
+EFIAPI
+ShellReadFile (
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return (FileFunctionMap.ReadFile (FileHandle, BufferSize, Buffer));
+}
+
+/**
+ Write data to a file.
+
+ This function writes the specified number of bytes to the file at the current
+ file position. The current file position is advanced the actual number of bytes
+ written, which is returned in BufferSize. Partial writes only occur when there
+ has been a data error during the write attempt (such as "volume space full").
+ The file is automatically grown to hold the data if required. Direct writes to
+ opened directories are not supported.
+
+ @param FileHandle The opened file for writing
+ @param BufferSize on input the number of bytes in Buffer. On output
+ the number of bytes written.
+ @param Buffer the buffer containing data to write is stored.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write-protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+ShellWriteFile (
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return (FileFunctionMap.WriteFile (FileHandle, BufferSize, Buffer));
+}
+
+/**
+ Close an open file handle.
+
+ This function closes a specified file handle. All "dirty" cached file data is
+ flushed to the device, and the file is closed. In all cases the handle is
+ closed.
+
+@param FileHandle the file handle to close.
+
+@retval EFI_SUCCESS the file handle was closed successfully.
+**/
+EFI_STATUS
+EFIAPI
+ShellCloseFile (
+ IN SHELL_FILE_HANDLE *FileHandle
+ )
+{
+ return (FileFunctionMap.CloseFile (*FileHandle));
+}
+
+/**
+ Delete a file and close the handle
+
+ This function closes and deletes a file. In all cases the file handle is closed.
+ If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
+ returned, but the handle is still closed.
+
+ @param FileHandle the file handle to delete
+
+ @retval EFI_SUCCESS the file was closed successfully
+ @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
+ deleted
+ @retval INVALID_PARAMETER One of the parameters has an invalid value.
+**/
+EFI_STATUS
+EFIAPI
+ShellDeleteFile (
+ IN SHELL_FILE_HANDLE *FileHandle
+ )
+{
+ return (FileFunctionMap.DeleteFile (*FileHandle));
+}
+
+/**
+ Set the current position in a file.
+
+ This function sets the current file position for the handle to the position
+ supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
+ absolute positioning is supported, and seeking past the end of the file is
+ allowed (a subsequent write would grow the file). Seeking to position
+ 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
+ If FileHandle is a directory, the only position that may be set is zero. This
+ has the effect of starting the read process of the directory entries over.
+
+ @param FileHandle The file handle on which the position is being set
+ @param Position Byte position from beginning of file
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
+ directories.
+ @retval INVALID_PARAMETER One of the parameters has an invalid value.
+**/
+EFI_STATUS
+EFIAPI
+ShellSetFilePosition (
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN UINT64 Position
+ )
+{
+ return (FileFunctionMap.SetFilePosition (FileHandle, Position));
+}
+
+/**
+ Gets a file's current position
+
+ This function retrieves the current file position for the file handle. For
+ directories, the current file position has no meaning outside of the file
+ system driver and as such the operation is not supported. An error is returned
+ if FileHandle is a directory.
+
+ @param FileHandle The open file handle on which to get the position.
+ @param Position Byte position from beginning of file.
+
+ @retval EFI_SUCCESS the operation completed successfully.
+ @retval INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED the request is not valid on directories.
+**/
+EFI_STATUS
+EFIAPI
+ShellGetFilePosition (
+ IN SHELL_FILE_HANDLE FileHandle,
+ OUT UINT64 *Position
+ )
+{
+ return (FileFunctionMap.GetFilePosition (FileHandle, Position));
+}
+
+/**
+ Flushes data on a file
+
+ This function flushes all modified data associated with a file to a device.
+
+ @param FileHandle The file handle on which to flush data
+
+ @retval EFI_SUCCESS The data was flushed.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened for read only.
+**/
+EFI_STATUS
+EFIAPI
+ShellFlushFile (
+ IN SHELL_FILE_HANDLE FileHandle
+ )
+{
+ return (FileFunctionMap.FlushFile (FileHandle));
+}
+
+/** Retrieve first entry from a directory.
+
+ This function takes an open directory handle and gets information from the
+ first entry in the directory. A buffer is allocated to contain
+ the information and a pointer to the buffer is returned in *Buffer. The
+ caller can use ShellFindNextFile() to get subsequent directory entries.
+
+ The buffer will be freed by ShellFindNextFile() when the last directory
+ entry is read. Otherwise, the caller must free the buffer, using FreePool,
+ when finished with it.
+
+ @param[in] DirHandle The file handle of the directory to search.
+ @param[out] Buffer The pointer to the buffer for the file's information.
+
+ @retval EFI_SUCCESS Found the first file.
+ @retval EFI_NOT_FOUND Cannot find the directory.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @return Others status of ShellGetFileInfo, ShellSetFilePosition,
+ or ShellReadFile
+**/
+EFI_STATUS
+EFIAPI
+ShellFindFirstFile (
+ IN SHELL_FILE_HANDLE DirHandle,
+ OUT EFI_FILE_INFO **Buffer
+ )
+{
+ //
+ // pass to file handle lib
+ //
+ return (FileHandleFindFirstFile (DirHandle, Buffer));
+}
+
+/** Retrieve next entries from a directory.
+
+ To use this function, the caller must first call the ShellFindFirstFile()
+ function to get the first directory entry. Subsequent directory entries are
+ retrieved by using the ShellFindNextFile() function. This function can
+ be called several times to get each entry from the directory. If the call of
+ ShellFindNextFile() retrieved the last directory entry, the next call of
+ this function will set *NoFile to TRUE and free the buffer.
+
+ @param[in] DirHandle The file handle of the directory.
+ @param[out] Buffer The pointer to buffer for file's information.
+ @param[out] NoFile The pointer to boolean when last file is found.
+
+ @retval EFI_SUCCESS Found the next file, or reached last file
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+**/
+EFI_STATUS
+EFIAPI
+ShellFindNextFile (
+ IN SHELL_FILE_HANDLE DirHandle,
+ OUT EFI_FILE_INFO *Buffer,
+ OUT BOOLEAN *NoFile
+ )
+{
+ //
+ // pass to file handle lib
+ //
+ return (FileHandleFindNextFile (DirHandle, Buffer, NoFile));
+}
+
+/**
+ Retrieve the size of a file.
+
+ if FileHandle is NULL then ASSERT()
+ if Size is NULL then ASSERT()
+
+ This function extracts the file size info from the FileHandle's EFI_FILE_INFO
+ data.
+
+ @param FileHandle file handle from which size is retrieved
+ @param Size pointer to size
+
+ @retval EFI_SUCCESS operation was completed successfully
+ @retval EFI_DEVICE_ERROR cannot access the file
+**/
+EFI_STATUS
+EFIAPI
+ShellGetFileSize (
+ IN SHELL_FILE_HANDLE FileHandle,
+ OUT UINT64 *Size
+ )
+{
+ return (FileFunctionMap.GetFileSize (FileHandle, Size));
+}
+
+/**
+ Retrieves the status of the break execution flag
+
+ this function is useful to check whether the application is being asked to halt by the shell.
+
+ @retval TRUE the execution break is enabled
+ @retval FALSE the execution break is not enabled
+**/
+BOOLEAN
+EFIAPI
+ShellGetExecutionBreakFlag (
+ VOID
+ )
+{
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ //
+ // We are using UEFI Shell 2.0; see if the event has been triggered
+ //
+ if (gBS->CheckEvent (gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+ }
+
+ //
+ // using EFI Shell; call the function to check
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ return (mEfiShellEnvironment2->GetExecutionBreak ());
+ }
+
+ return (FALSE);
+}
+
+/**
+ return the value of an environment variable
+
+ this function gets the value of the environment variable set by the
+ ShellSetEnvironmentVariable function
+
+ @param EnvKey The key name of the environment variable.
+
+ @retval NULL the named environment variable does not exist.
+ @return != NULL pointer to the value of the environment variable
+**/
+CONST CHAR16 *
+EFIAPI
+ShellGetEnvironmentVariable (
+ IN CONST CHAR16 *EnvKey
+ )
+{
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ return (gEfiShellProtocol->GetEnv (EnvKey));
+ }
+
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ return (mEfiShellEnvironment2->GetEnv ((CHAR16 *)EnvKey));
+ }
+
+ return NULL;
+}
+
+/**
+ set the value of an environment variable
+
+This function changes the current value of the specified environment variable. If the
+environment variable exists and the Value is an empty string, then the environment
+variable is deleted. If the environment variable exists and the Value is not an empty
+string, then the value of the environment variable is changed. If the environment
+variable does not exist and the Value is an empty string, there is no action. If the
+environment variable does not exist and the Value is a non-empty string, then the
+environment variable is created and assigned the specified value.
+
+ This is not supported pre-UEFI Shell 2.0.
+
+ @param EnvKey The key name of the environment variable.
+ @param EnvVal The Value of the environment variable
+ @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
+
+ @retval EFI_SUCCESS the operation was completed successfully
+ @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
+**/
+EFI_STATUS
+EFIAPI
+ShellSetEnvironmentVariable (
+ IN CONST CHAR16 *EnvKey,
+ IN CONST CHAR16 *EnvVal,
+ IN BOOLEAN Volatile
+ )
+{
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ return (gEfiShellProtocol->SetEnv (EnvKey, EnvVal, Volatile));
+ }
+
+ //
+ // This feature does not exist under EFI shell
+ //
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ Cause the shell to parse and execute a command line.
+
+ This function creates a nested instance of the shell and executes the specified
+ command (CommandLine) with the specified environment (Environment). Upon return,
+ the status code returned by the specified command is placed in StatusCode.
+ If Environment is NULL, then the current environment is used and all changes made
+ by the commands executed will be reflected in the current environment. If the
+ Environment is non-NULL, then the changes made will be discarded.
+ The CommandLine is executed from the current working directory on the current
+ device.
+
+ The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
+ environment. The values pointed to by the parameters will be unchanged by the
+ ShellExecute() function. The Output parameter has no effect in a
+ UEFI Shell 2.0 environment.
+
+ @param[in] ParentHandle The parent image starting the operation.
+ @param[in] CommandLine The pointer to a NULL terminated command line.
+ @param[in] Output True to display debug output. False to hide it.
+ @param[in] EnvironmentVariables Optional pointer to array of environment variables
+ in the form "x=y". If NULL, the current set is used.
+ @param[out] Status The status of the run command line.
+
+ @retval EFI_SUCCESS The operation completed successfully. Status
+ contains the status code returned.
+ @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+ @retval EFI_UNSUPPORTED The operation is not allowed.
+**/
+EFI_STATUS
+EFIAPI
+ShellExecute (
+ IN EFI_HANDLE *ParentHandle,
+ IN CHAR16 *CommandLine OPTIONAL,
+ IN BOOLEAN Output OPTIONAL,
+ IN CHAR16 **EnvironmentVariables OPTIONAL,
+ OUT EFI_STATUS *Status OPTIONAL
+ )
+{
+ EFI_STATUS CmdStatus;
+
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ //
+ // Call UEFI Shell 2.0 version (not using Output parameter)
+ //
+ return (gEfiShellProtocol->Execute (
+ ParentHandle,
+ CommandLine,
+ EnvironmentVariables,
+ Status
+ ));
+ }
+
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ //
+ // Call EFI Shell version.
+ //
+ // Due to an unfixable bug in the EdkShell implementation, we must
+ // dereference "ParentHandle" here:
+ //
+ // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol,
+ // identified by gEfiShellEnvironment2Guid.
+ // 2. The Execute() member function takes "ParentImageHandle" as first
+ // parameter, with type (EFI_HANDLE*).
+ // 3. In the EdkShell implementation, SEnvExecute() implements the
+ // Execute() member function. It passes "ParentImageHandle" correctly to
+ // SEnvDoExecute().
+ // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly --
+ // without de-referencing -- to the HandleProtocol() boot service.
+ // 5. But HandleProtocol() takes an EFI_HANDLE.
+ //
+ // Therefore we must
+ // - de-reference "ParentHandle" here, to mask the bug in
+ // SEnvDoExecute(), and
+ // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*).
+ //
+ CmdStatus = (mEfiShellEnvironment2->Execute (
+ (EFI_HANDLE *)*ParentHandle,
+ CommandLine,
+ Output
+ ));
+ //
+ // No Status output parameter so just use the returned status
+ //
+ if (Status != NULL) {
+ *Status = CmdStatus;
+ }
+
+ //
+ // If there was an error, we can't tell if it was from the command or from
+ // the Execute() function, so we'll just assume the shell ran successfully
+ // and the error came from the command.
+ //
+ return EFI_SUCCESS;
+ }
+
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ Retreives the current directory path
+
+ If the DeviceName is NULL, it returns the current device's current directory
+ name. If the DeviceName is not NULL, it returns the current directory name
+ on specified drive.
+
+ Note that the current directory string should exclude the tailing backslash character.
+
+ @param DeviceName the name of the drive to get directory on
+
+ @retval NULL the directory does not exist
+ @return != NULL the directory
+**/
+CONST CHAR16 *
+EFIAPI
+ShellGetCurrentDir (
+ IN CHAR16 *CONST DeviceName OPTIONAL
+ )
+{
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ return (gEfiShellProtocol->GetCurDir (DeviceName));
+ }
+
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ return (mEfiShellEnvironment2->CurDir (DeviceName));
+ }
+
+ return (NULL);
+}
+
+/**
+ sets (enabled or disabled) the page break mode
+
+ when page break mode is enabled the screen will stop scrolling
+ and wait for operator input before scrolling a subsequent screen.
+
+ @param CurrentState TRUE to enable and FALSE to disable
+**/
+VOID
+EFIAPI
+ShellSetPageBreakMode (
+ IN BOOLEAN CurrentState
+ )
+{
+ //
+ // check for enabling
+ //
+ if (CurrentState != 0x00) {
+ //
+ // check for UEFI Shell 2.0
+ //
+ if (gEfiShellProtocol != NULL) {
+ //
+ // Enable with UEFI 2.0 Shell
+ //
+ gEfiShellProtocol->EnablePageBreak ();
+ return;
+ } else {
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ //
+ // Enable with EFI Shell
+ //
+ mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
+ return;
+ }
+ }
+ } else {
+ //
+ // check for UEFI Shell 2.0
+ //
+ if (gEfiShellProtocol != NULL) {
+ //
+ // Disable with UEFI 2.0 Shell
+ //
+ gEfiShellProtocol->DisablePageBreak ();
+ return;
+ } else {
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ //
+ // Disable with EFI Shell
+ //
+ mEfiShellEnvironment2->DisablePageBreak ();
+ return;
+ }
+ }
+ }
+}
+
+///
+/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
+/// This allows for the struct to be populated.
+///
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_STATUS Status;
+ CHAR16 *FullName;
+ CHAR16 *FileName;
+ SHELL_FILE_HANDLE Handle;
+ EFI_FILE_INFO *Info;
+} EFI_SHELL_FILE_INFO_NO_CONST;
+
+/**
+ Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
+
+ if OldStyleFileList is NULL then ASSERT()
+
+ this function will convert a SHELL_FILE_ARG based list into a callee allocated
+ EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
+ the ShellCloseFileMetaArg function.
+
+ @param[in] FileList the EFI shell list type
+ @param[in, out] ListHead the list to add to
+
+ @retval the resultant head of the double linked new format list;
+**/
+LIST_ENTRY *
+InternalShellConvertFileListType (
+ IN LIST_ENTRY *FileList,
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ SHELL_FILE_ARG *OldInfo;
+ LIST_ENTRY *Link;
+ EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;
+
+ //
+ // ASSERTs
+ //
+ ASSERT (FileList != NULL);
+ ASSERT (ListHead != NULL);
+
+ //
+ // enumerate through each member of the old list and copy
+ //
+ for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {
+ OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
+ ASSERT (OldInfo != NULL);
+
+ //
+ // Skip ones that failed to open...
+ //
+ if (OldInfo->Status != EFI_SUCCESS) {
+ continue;
+ }
+
+ //
+ // make sure the old list was valid
+ //
+ ASSERT (OldInfo->Info != NULL);
+ ASSERT (OldInfo->FullName != NULL);
+ ASSERT (OldInfo->FileName != NULL);
+
+ //
+ // allocate a new EFI_SHELL_FILE_INFO object
+ //
+ NewInfo = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
+ if (NewInfo == NULL) {
+ ShellCloseFileMetaArg ((EFI_SHELL_FILE_INFO **)(&ListHead));
+ ListHead = NULL;
+ break;
+ }
+
+ //
+ // copy the simple items
+ //
+ NewInfo->Handle = OldInfo->Handle;
+ NewInfo->Status = OldInfo->Status;
+
+ // old shell checks for 0 not NULL
+ OldInfo->Handle = 0;
+
+ //
+ // allocate new space to copy strings and structure
+ //
+ NewInfo->FullName = AllocateCopyPool (StrSize (OldInfo->FullName), OldInfo->FullName);
+ NewInfo->FileName = AllocateCopyPool (StrSize (OldInfo->FileName), OldInfo->FileName);
+ NewInfo->Info = AllocateCopyPool ((UINTN)OldInfo->Info->Size, OldInfo->Info);
+
+ //
+ // make sure all the memory allocations were successful
+ //
+ if ((NULL == NewInfo->FullName) || (NewInfo->FileName == NULL) || (NewInfo->Info == NULL)) {
+ //
+ // Free the partially allocated new node
+ //
+ SHELL_FREE_NON_NULL (NewInfo->FullName);
+ SHELL_FREE_NON_NULL (NewInfo->FileName);
+ SHELL_FREE_NON_NULL (NewInfo->Info);
+ SHELL_FREE_NON_NULL (NewInfo);
+
+ //
+ // Free the previously converted stuff
+ //
+ ShellCloseFileMetaArg ((EFI_SHELL_FILE_INFO **)(&ListHead));
+ ListHead = NULL;
+ break;
+ }
+
+ //
+ // add that to the list
+ //
+ InsertTailList (ListHead, &NewInfo->Link);
+ }
+
+ return (ListHead);
+}
+
+/**
+ Opens a group of files based on a path.
+
+ This function uses the Arg to open all the matching files. Each matched
+ file has a SHELL_FILE_INFO structure to record the file information. These
+ structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
+ structures from ListHead to access each file. This function supports wildcards
+ and will process '?' and '*' as such. the list must be freed with a call to
+ ShellCloseFileMetaArg().
+
+ If you are NOT appending to an existing list *ListHead must be NULL. If
+ *ListHead is NULL then it must be callee freed.
+
+ @param Arg pointer to path string
+ @param OpenMode mode to open files with
+ @param ListHead head of linked list of results
+
+ @retval EFI_SUCCESS the operation was successful and the list head
+ contains the list of opened files
+ @return != EFI_SUCCESS the operation failed
+
+ @sa InternalShellConvertFileListType
+**/
+EFI_STATUS
+EFIAPI
+ShellOpenFileMetaArg (
+ IN CHAR16 *Arg,
+ IN UINT64 OpenMode,
+ IN OUT EFI_SHELL_FILE_INFO **ListHead
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY mOldStyleFileList;
+ CHAR16 *CleanFilePathStr;
+
+ //
+ // ASSERT that Arg and ListHead are not NULL
+ //
+ ASSERT (Arg != NULL);
+ ASSERT (ListHead != NULL);
+
+ CleanFilePathStr = NULL;
+
+ Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ if (*ListHead == NULL) {
+ *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
+ if (*ListHead == NULL) {
+ FreePool (CleanFilePathStr);
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ InitializeListHead (&((*ListHead)->Link));
+ }
+
+ Status = gEfiShellProtocol->OpenFileList (
+ CleanFilePathStr,
+ OpenMode,
+ ListHead
+ );
+ if (EFI_ERROR (Status)) {
+ gEfiShellProtocol->RemoveDupInFileList (ListHead);
+ } else {
+ Status = gEfiShellProtocol->RemoveDupInFileList (ListHead);
+ }
+
+ if ((*ListHead != NULL) && IsListEmpty (&(*ListHead)->Link)) {
+ FreePool (*ListHead);
+ FreePool (CleanFilePathStr);
+ *ListHead = NULL;
+ return (EFI_NOT_FOUND);
+ }
+
+ FreePool (CleanFilePathStr);
+ return (Status);
+ }
+
+ //
+ // Check for EFI shell
+ //
+ if (mEfiShellEnvironment2 != NULL) {
+ //
+ // make sure the list head is initialized
+ //
+ InitializeListHead (&mOldStyleFileList);
+
+ //
+ // Get the EFI Shell list of files
+ //
+ Status = mEfiShellEnvironment2->FileMetaArg (CleanFilePathStr, &mOldStyleFileList);
+ if (EFI_ERROR (Status)) {
+ *ListHead = NULL;
+ FreePool (CleanFilePathStr);
+ return (Status);
+ }
+
+ if (*ListHead == NULL) {
+ *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
+ if (*ListHead == NULL) {
+ FreePool (CleanFilePathStr);
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ InitializeListHead (&((*ListHead)->Link));
+ }
+
+ //
+ // Convert that to equivalent of UEFI Shell 2.0 structure
+ //
+ InternalShellConvertFileListType (&mOldStyleFileList, &(*ListHead)->Link);
+
+ //
+ // Free the EFI Shell version that was converted.
+ //
+ mEfiShellEnvironment2->FreeFileList (&mOldStyleFileList);
+
+ if (((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink) && ((*ListHead)->Link.BackLink == &((*ListHead)->Link))) {
+ FreePool (*ListHead);
+ *ListHead = NULL;
+ Status = EFI_NOT_FOUND;
+ }
+
+ FreePool (CleanFilePathStr);
+ return (Status);
+ }
+
+ FreePool (CleanFilePathStr);
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ Free the linked list returned from ShellOpenFileMetaArg.
+
+ if ListHead is NULL then ASSERT().
+
+ @param ListHead the pointer to free.
+
+ @retval EFI_SUCCESS the operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+ShellCloseFileMetaArg (
+ IN OUT EFI_SHELL_FILE_INFO **ListHead
+ )
+{
+ LIST_ENTRY *Node;
+
+ //
+ // ASSERT that ListHead is not NULL
+ //
+ ASSERT (ListHead != NULL);
+
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellProtocol != NULL) {
+ return (gEfiShellProtocol->FreeFileList (ListHead));
+ } else if (mEfiShellEnvironment2 != NULL) {
+ //
+ // Since this is EFI Shell version we need to free our internally made copy
+ // of the list
+ //
+ for ( Node = GetFirstNode (&(*ListHead)->Link)
+ ; *ListHead != NULL && !IsListEmpty (&(*ListHead)->Link)
+ ; Node = GetFirstNode (&(*ListHead)->Link))
+ {
+ RemoveEntryList (Node);
+ ((EFI_FILE_PROTOCOL *)((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Handle)->Close (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Handle);
+ FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->FullName);
+ FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->FileName);
+ FreePool (((EFI_SHELL_FILE_INFO_NO_CONST *)Node)->Info);
+ FreePool ((EFI_SHELL_FILE_INFO_NO_CONST *)Node);
+ }
+
+ SHELL_FREE_NON_NULL (*ListHead);
+ return EFI_SUCCESS;
+ }
+
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ Find a file by searching the CWD and then the path.
+
+ If FileName is NULL then ASSERT.
+
+ If the return value is not NULL then the memory must be caller freed.
+
+ @param FileName Filename string.
+
+ @retval NULL the file was not found
+ @return !NULL the full path to the file.
+**/
+CHAR16 *
+EFIAPI
+ShellFindFilePath (
+ IN CONST CHAR16 *FileName
+ )
+{
+ CONST CHAR16 *Path;
+ SHELL_FILE_HANDLE Handle;
+ EFI_STATUS Status;
+ CHAR16 *RetVal;
+ CHAR16 *TestPath;
+ CONST CHAR16 *Walker;
+ UINTN Size;
+ CHAR16 *TempChar;
+
+ RetVal = NULL;
+
+ //
+ // First make sure its not an absolute path.
+ //
+ Status = ShellOpenFileByName (FileName, &Handle, EFI_FILE_MODE_READ, 0);
+ if (!EFI_ERROR (Status)) {
+ if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
+ ASSERT (RetVal == NULL);
+ RetVal = StrnCatGrow (&RetVal, NULL, FileName, 0);
+ ShellCloseFile (&Handle);
+ return (RetVal);
+ } else {
+ ShellCloseFile (&Handle);
+ }
+ }
+
+ Path = ShellGetEnvironmentVariable (L"cwd");
+ if (Path != NULL) {
+ Size = StrSize (Path) + sizeof (CHAR16);
+ Size += StrSize (FileName);
+ TestPath = AllocateZeroPool (Size);
+ if (TestPath == NULL) {
+ return (NULL);
+ }
+
+ StrCpyS (TestPath, Size/sizeof (CHAR16), Path);
+ StrCatS (TestPath, Size/sizeof (CHAR16), L"\\");
+ StrCatS (TestPath, Size/sizeof (CHAR16), FileName);
+ Status = ShellOpenFileByName (TestPath, &Handle, EFI_FILE_MODE_READ, 0);
+ if (!EFI_ERROR (Status)) {
+ if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
+ ASSERT (RetVal == NULL);
+ RetVal = StrnCatGrow (&RetVal, NULL, TestPath, 0);
+ ShellCloseFile (&Handle);
+ FreePool (TestPath);
+ return (RetVal);
+ } else {
+ ShellCloseFile (&Handle);
+ }
+ }
+
+ FreePool (TestPath);
+ }
+
+ Path = ShellGetEnvironmentVariable (L"path");
+ if (Path != NULL) {
+ Size = StrSize (Path)+sizeof (CHAR16);
+ Size += StrSize (FileName);
+ TestPath = AllocateZeroPool (Size);
+ if (TestPath == NULL) {
+ return (NULL);
+ }
+
+ Walker = (CHAR16 *)Path;
+ do {
+ CopyMem (TestPath, Walker, StrSize (Walker));
+ if (TestPath != NULL) {
+ TempChar = StrStr (TestPath, L";");
+ if (TempChar != NULL) {
+ *TempChar = CHAR_NULL;
+ }
+
+ if (TestPath[StrLen (TestPath)-1] != L'\\') {
+ StrCatS (TestPath, Size/sizeof (CHAR16), L"\\");
+ }
+
+ if (FileName[0] == L'\\') {
+ FileName++;
+ }
+
+ StrCatS (TestPath, Size/sizeof (CHAR16), FileName);
+ if (StrStr (Walker, L";") != NULL) {
+ Walker = StrStr (Walker, L";") + 1;
+ } else {
+ Walker = NULL;
+ }
+
+ Status = ShellOpenFileByName (TestPath, &Handle, EFI_FILE_MODE_READ, 0);
+ if (!EFI_ERROR (Status)) {
+ if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
+ ASSERT (RetVal == NULL);
+ RetVal = StrnCatGrow (&RetVal, NULL, TestPath, 0);
+ ShellCloseFile (&Handle);
+ break;
+ } else {
+ ShellCloseFile (&Handle);
+ }
+ }
+ }
+ } while (Walker != NULL && Walker[0] != CHAR_NULL);
+
+ FreePool (TestPath);
+ }
+
+ return (RetVal);
+}
+
+/**
+ Find a file by searching the CWD and then the path with a variable set of file
+ extensions. If the file is not found it will append each extension in the list
+ in the order provided and return the first one that is successful.
+
+ If FileName is NULL, then ASSERT.
+ If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
+
+ If the return value is not NULL then the memory must be caller freed.
+
+ @param[in] FileName Filename string.
+ @param[in] FileExtension Semi-colon delimeted list of possible extensions.
+
+ @retval NULL The file was not found.
+ @retval !NULL The path to the file.
+**/
+CHAR16 *
+EFIAPI
+ShellFindFilePathEx (
+ IN CONST CHAR16 *FileName,
+ IN CONST CHAR16 *FileExtension
+ )
+{
+ CHAR16 *TestPath;
+ CHAR16 *RetVal;
+ CONST CHAR16 *ExtensionWalker;
+ UINTN Size;
+ CHAR16 *TempChar;
+ CHAR16 *TempChar2;
+
+ ASSERT (FileName != NULL);
+ if (FileExtension == NULL) {
+ return (ShellFindFilePath (FileName));
+ }
+
+ RetVal = ShellFindFilePath (FileName);
+ if (RetVal != NULL) {
+ return (RetVal);
+ }
+
+ Size = StrSize (FileName);
+ Size += StrSize (FileExtension);
+ TestPath = AllocateZeroPool (Size);
+ if (TestPath == NULL) {
+ return (NULL);
+ }
+
+ for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16 *)FileExtension; TempChar2 != NULL; ExtensionWalker = TempChar2 + 1) {
+ StrCpyS (TestPath, Size/sizeof (CHAR16), FileName);
+ if (ExtensionWalker != NULL) {
+ StrCatS (TestPath, Size/sizeof (CHAR16), ExtensionWalker);
+ }
+
+ TempChar = StrStr (TestPath, L";");
+ if (TempChar != NULL) {
+ *TempChar = CHAR_NULL;
+ }
+
+ RetVal = ShellFindFilePath (TestPath);
+ if (RetVal != NULL) {
+ break;
+ }
+
+ ASSERT (ExtensionWalker != NULL);
+ TempChar2 = StrStr (ExtensionWalker, L";");
+ }
+
+ FreePool (TestPath);
+ return (RetVal);
+}
+
+typedef struct {
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ SHELL_PARAM_TYPE Type;
+ CHAR16 *Value;
+ UINTN OriginalPosition;
+} SHELL_PARAM_PACKAGE;
+
+/**
+ Checks the list of valid arguments and returns TRUE if the item was found. If the
+ return value is TRUE then the type parameter is set also.
+
+ if CheckList is NULL then ASSERT();
+ if Name is NULL then ASSERT();
+ if Type is NULL then ASSERT();
+
+ @param Name pointer to Name of parameter found
+ @param CheckList List to check against
+ @param Type pointer to type of parameter if it was found
+
+ @retval TRUE the Parameter was found. Type is valid.
+ @retval FALSE the Parameter was not found. Type is not valid.
+**/
+BOOLEAN
+InternalIsOnCheckList (
+ IN CONST CHAR16 *Name,
+ IN CONST SHELL_PARAM_ITEM *CheckList,
+ OUT SHELL_PARAM_TYPE *Type
+ )
+{
+ SHELL_PARAM_ITEM *TempListItem;
+ CHAR16 *TempString;
+
+ //
+ // ASSERT that all 3 pointer parameters aren't NULL
+ //
+ ASSERT (CheckList != NULL);
+ ASSERT (Type != NULL);
+ ASSERT (Name != NULL);
+
+ //
+ // question mark and page break mode are always supported
+ //
+ if ((StrCmp (Name, L"-?") == 0) ||
+ (StrCmp (Name, L"-b") == 0)
+ )
+ {
+ *Type = TypeFlag;
+ return (TRUE);
+ }
+
+ //
+ // Enumerate through the list
+ //
+ for (TempListItem = (SHELL_PARAM_ITEM *)CheckList; TempListItem->Name != NULL; TempListItem++) {
+ //
+ // If the Type is TypeStart only check the first characters of the passed in param
+ // If it matches set the type and return TRUE
+ //
+ if (TempListItem->Type == TypeStart) {
+ if (StrnCmp (Name, TempListItem->Name, StrLen (TempListItem->Name)) == 0) {
+ *Type = TempListItem->Type;
+ return (TRUE);
+ }
+
+ TempString = NULL;
+ TempString = StrnCatGrow (&TempString, NULL, Name, StrLen (TempListItem->Name));
+ if (TempString != NULL) {
+ if (StringNoCaseCompare (&TempString, &TempListItem->Name) == 0) {
+ *Type = TempListItem->Type;
+ FreePool (TempString);
+ return (TRUE);
+ }
+
+ FreePool (TempString);
+ }
+ } else if (StringNoCaseCompare (&Name, &TempListItem->Name) == 0) {
+ *Type = TempListItem->Type;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/**
+ Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
+
+ @param[in] Name pointer to Name of parameter found
+ @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
+ @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
+
+ @retval TRUE the Parameter is a flag.
+ @retval FALSE the Parameter not a flag.
+**/
+BOOLEAN
+InternalIsFlag (
+ IN CONST CHAR16 *Name,
+ IN CONST BOOLEAN AlwaysAllowNumbers,
+ IN CONST BOOLEAN TimeNumbers
+ )
+{
+ //
+ // ASSERT that Name isn't NULL
+ //
+ ASSERT (Name != NULL);
+
+ //
+ // If we accept numbers then dont return TRUE. (they will be values)
+ //
+ if ((((Name[0] == L'-') || (Name[0] == L'+')) && InternalShellIsHexOrDecimalNumber (Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
+ return (FALSE);
+ }
+
+ //
+ // If the Name has a /, +, or - as the first character return TRUE
+ //
+ if ((Name[0] == L'/') ||
+ (Name[0] == L'-') ||
+ (Name[0] == L'+')
+ )
+ {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/**
+ Checks the command line arguments passed against the list of valid ones.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+
+ @param[in] CheckList pointer to list of parameters to check
+ @param[out] CheckPackage pointer to pointer to list checked values
+ @param[out] ProblemParam optional pointer to pointer to unicode string for
+ the paramater that caused failure. If used then the
+ caller is responsible for freeing the memory.
+ @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
+ @param[in] Argv pointer to array of parameters
+ @param[in] Argc Count of parameters in Argv
+ @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed
+ @retval EFI_INVALID_PARAMETER A parameter was invalid
+ @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
+ duplicated. the duplicated command line argument
+ was returned in ProblemParam if provided.
+ @retval EFI_NOT_FOUND a argument required a value that was missing.
+ the invalid command line argument was returned in
+ ProblemParam if provided.
+**/
+EFI_STATUS
+InternalCommandLineParse (
+ IN CONST SHELL_PARAM_ITEM *CheckList,
+ OUT LIST_ENTRY **CheckPackage,
+ OUT CHAR16 **ProblemParam OPTIONAL,
+ IN BOOLEAN AutoPageBreak,
+ IN CONST CHAR16 **Argv,
+ IN UINTN Argc,
+ IN BOOLEAN AlwaysAllowNumbers
+ )
+{
+ UINTN LoopCounter;
+ SHELL_PARAM_TYPE CurrentItemType;
+ SHELL_PARAM_PACKAGE *CurrentItemPackage;
+ UINTN GetItemValue;
+ UINTN ValueSize;
+ UINTN Count;
+ CONST CHAR16 *TempPointer;
+ UINTN CurrentValueSize;
+ CHAR16 *NewValue;
+
+ CurrentItemPackage = NULL;
+ GetItemValue = 0;
+ ValueSize = 0;
+ Count = 0;
+
+ //
+ // If there is only 1 item we dont need to do anything
+ //
+ if (Argc < 1) {
+ *CheckPackage = NULL;
+ return (EFI_SUCCESS);
+ }
+
+ //
+ // ASSERTs
+ //
+ ASSERT (CheckList != NULL);
+ ASSERT (Argv != NULL);
+
+ //
+ // initialize the linked list
+ //
+ *CheckPackage = (LIST_ENTRY *)AllocateZeroPool (sizeof (LIST_ENTRY));
+ if (*CheckPackage == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ InitializeListHead (*CheckPackage);
+
+ //
+ // loop through each of the arguments
+ //
+ for (LoopCounter = 0; LoopCounter < Argc; ++LoopCounter) {
+ if (Argv[LoopCounter] == NULL) {
+ //
+ // do nothing for NULL argv
+ //
+ } else if (InternalIsOnCheckList (Argv[LoopCounter], CheckList, &CurrentItemType)) {
+ //
+ // We might have leftover if last parameter didnt have optional value
+ //
+ if (GetItemValue != 0) {
+ GetItemValue = 0;
+ InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
+ }
+
+ //
+ // this is a flag
+ //
+ CurrentItemPackage = AllocateZeroPool (sizeof (SHELL_PARAM_PACKAGE));
+ if (CurrentItemPackage == NULL) {
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ CurrentItemPackage->Name = AllocateCopyPool (StrSize (Argv[LoopCounter]), Argv[LoopCounter]);
+ if (CurrentItemPackage->Name == NULL) {
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ CurrentItemPackage->Type = CurrentItemType;
+ CurrentItemPackage->OriginalPosition = (UINTN)(-1);
+ CurrentItemPackage->Value = NULL;
+
+ //
+ // Does this flag require a value
+ //
+ switch (CurrentItemPackage->Type) {
+ //
+ // possibly trigger the next loop(s) to populate the value of this item
+ //
+ case TypeValue:
+ case TypeTimeValue:
+ GetItemValue = 1;
+ ValueSize = 0;
+ break;
+ case TypeDoubleValue:
+ GetItemValue = 2;
+ ValueSize = 0;
+ break;
+ case TypeMaxValue:
+ GetItemValue = (UINTN)(-1);
+ ValueSize = 0;
+ break;
+ default:
+ //
+ // this item has no value expected; we are done
+ //
+ InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
+ ASSERT (GetItemValue == 0);
+ break;
+ }
+ } else if ((GetItemValue != 0) && (CurrentItemPackage != NULL) && !InternalIsFlag (Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
+ //
+ // get the item VALUE for a previous flag
+ //
+ CurrentValueSize = ValueSize + StrSize (Argv[LoopCounter]) + sizeof (CHAR16);
+ NewValue = ReallocatePool (ValueSize, CurrentValueSize, CurrentItemPackage->Value);
+ if (NewValue == NULL) {
+ SHELL_FREE_NON_NULL (CurrentItemPackage->Value);
+ SHELL_FREE_NON_NULL (CurrentItemPackage);
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentItemPackage->Value = NewValue;
+ if (ValueSize == 0) {
+ StrCpyS (
+ CurrentItemPackage->Value,
+ CurrentValueSize/sizeof (CHAR16),
+ Argv[LoopCounter]
+ );
+ } else {
+ StrCatS (
+ CurrentItemPackage->Value,
+ CurrentValueSize/sizeof (CHAR16),
+ L" "
+ );
+ StrCatS (
+ CurrentItemPackage->Value,
+ CurrentValueSize/sizeof (CHAR16),
+ Argv[LoopCounter]
+ );
+ }
+
+ ValueSize += StrSize (Argv[LoopCounter]) + sizeof (CHAR16);
+
+ GetItemValue--;
+ if (GetItemValue == 0) {
+ InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
+ }
+ } else if (!InternalIsFlag (Argv[LoopCounter], AlwaysAllowNumbers, FALSE)) {
+ //
+ // add this one as a non-flag
+ //
+
+ TempPointer = Argv[LoopCounter];
+ if ( ((*TempPointer == L'^') && (*(TempPointer+1) == L'-'))
+ || ((*TempPointer == L'^') && (*(TempPointer+1) == L'/'))
+ || ((*TempPointer == L'^') && (*(TempPointer+1) == L'+'))
+ )
+ {
+ TempPointer++;
+ }
+
+ CurrentItemPackage = AllocateZeroPool (sizeof (SHELL_PARAM_PACKAGE));
+ if (CurrentItemPackage == NULL) {
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ CurrentItemPackage->Name = NULL;
+ CurrentItemPackage->Type = TypePosition;
+ CurrentItemPackage->Value = AllocateCopyPool (StrSize (TempPointer), TempPointer);
+ if (CurrentItemPackage->Value == NULL) {
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ CurrentItemPackage->OriginalPosition = Count++;
+ InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
+ } else {
+ //
+ // this was a non-recognised flag... error!
+ //
+ if (ProblemParam != NULL) {
+ *ProblemParam = AllocateCopyPool (StrSize (Argv[LoopCounter]), Argv[LoopCounter]);
+ }
+
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_VOLUME_CORRUPTED);
+ }
+ }
+
+ if (GetItemValue != 0) {
+ GetItemValue = 0;
+ InsertHeadList (*CheckPackage, &CurrentItemPackage->Link);
+ }
+
+ //
+ // support for AutoPageBreak
+ //
+ if (AutoPageBreak && ShellCommandLineGetFlag (*CheckPackage, L"-b")) {
+ ShellSetPageBreakMode (TRUE);
+ }
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Checks the command line arguments passed against the list of valid ones.
+ Optionally removes NULL values first.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+
+ @param[in] CheckList The pointer to list of parameters to check.
+ @param[out] CheckPackage The package of checked values.
+ @param[out] ProblemParam Optional pointer to pointer to unicode string for
+ the paramater that caused failure.
+ @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
+ @param[in] AlwaysAllowNumbers Will never fail for number based flags.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
+ @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
+ of the command line arguments was returned in
+ ProblemParam if provided.
+ @retval EFI_NOT_FOUND A argument required a value that was missing.
+ The invalid command line argument was returned in
+ ProblemParam if provided.
+**/
+EFI_STATUS
+EFIAPI
+ShellCommandLineParseEx (
+ IN CONST SHELL_PARAM_ITEM *CheckList,
+ OUT LIST_ENTRY **CheckPackage,
+ OUT CHAR16 **ProblemParam OPTIONAL,
+ IN BOOLEAN AutoPageBreak,
+ IN BOOLEAN AlwaysAllowNumbers
+ )
+{
+ //
+ // ASSERT that CheckList and CheckPackage aren't NULL
+ //
+ ASSERT (CheckList != NULL);
+ ASSERT (CheckPackage != NULL);
+
+ //
+ // Check for UEFI Shell 2.0 protocols
+ //
+ if (gEfiShellParametersProtocol != NULL) {
+ return (InternalCommandLineParse (
+ CheckList,
+ CheckPackage,
+ ProblemParam,
+ AutoPageBreak,
+ (CONST CHAR16 **)gEfiShellParametersProtocol->Argv,
+ gEfiShellParametersProtocol->Argc,
+ AlwaysAllowNumbers
+ ));
+ }
+
+ //
+ // ASSERT That EFI Shell is not required
+ //
+ ASSERT (mEfiShellInterface != NULL);
+ return (InternalCommandLineParse (
+ CheckList,
+ CheckPackage,
+ ProblemParam,
+ AutoPageBreak,
+ (CONST CHAR16 **)mEfiShellInterface->Argv,
+ mEfiShellInterface->Argc,
+ AlwaysAllowNumbers
+ ));
+}
+
+/**
+ Frees shell variable list that was returned from ShellCommandLineParse.
+
+ This function will free all the memory that was used for the CheckPackage
+ list of postprocessed shell arguments.
+
+ this function has no return value.
+
+ if CheckPackage is NULL, then return
+
+ @param CheckPackage the list to de-allocate
+ **/
+VOID
+EFIAPI
+ShellCommandLineFreeVarList (
+ IN LIST_ENTRY *CheckPackage
+ )
+{
+ LIST_ENTRY *Node;
+
+ //
+ // check for CheckPackage == NULL
+ //
+ if (CheckPackage == NULL) {
+ return;
+ }
+
+ //
+ // for each node in the list
+ //
+ for ( Node = GetFirstNode (CheckPackage)
+ ; !IsListEmpty (CheckPackage)
+ ; Node = GetFirstNode (CheckPackage)
+ )
+ {
+ //
+ // Remove it from the list
+ //
+ RemoveEntryList (Node);
+
+ //
+ // if it has a name free the name
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
+ FreePool (((SHELL_PARAM_PACKAGE *)Node)->Name);
+ }
+
+ //
+ // if it has a value free the value
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Value != NULL) {
+ FreePool (((SHELL_PARAM_PACKAGE *)Node)->Value);
+ }
+
+ //
+ // free the node structure
+ //
+ FreePool ((SHELL_PARAM_PACKAGE *)Node);
+ }
+
+ //
+ // free the list head node
+ //
+ FreePool (CheckPackage);
+}
+
+/**
+ Checks for presence of a flag parameter
+
+ flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
+
+ if CheckPackage is NULL then return FALSE.
+ if KeyString is NULL then ASSERT()
+
+ @param CheckPackage The package of parsed command line arguments
+ @param KeyString the Key of the command line argument to check for
+
+ @retval TRUE the flag is on the command line
+ @retval FALSE the flag is not on the command line
+ **/
+BOOLEAN
+EFIAPI
+ShellCommandLineGetFlag (
+ IN CONST LIST_ENTRY *CONST CheckPackage,
+ IN CONST CHAR16 *CONST KeyString
+ )
+{
+ LIST_ENTRY *Node;
+ CHAR16 *TempString;
+
+ //
+ // return FALSE for no package or KeyString is NULL
+ //
+ if ((CheckPackage == NULL) || (KeyString == NULL)) {
+ return (FALSE);
+ }
+
+ //
+ // enumerate through the list of parametrs
+ //
+ for ( Node = GetFirstNode (CheckPackage)
+ ; !IsNull (CheckPackage, Node)
+ ; Node = GetNextNode (CheckPackage, Node)
+ )
+ {
+ //
+ // If the Name matches, return TRUE (and there may be NULL name)
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
+ //
+ // If Type is TypeStart then only compare the begining of the strings
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Type == TypeStart) {
+ if (StrnCmp (KeyString, ((SHELL_PARAM_PACKAGE *)Node)->Name, StrLen (KeyString)) == 0) {
+ return (TRUE);
+ }
+
+ TempString = NULL;
+ TempString = StrnCatGrow (&TempString, NULL, KeyString, StrLen (((SHELL_PARAM_PACKAGE *)Node)->Name));
+ if (TempString != NULL) {
+ if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
+ FreePool (TempString);
+ return (TRUE);
+ }
+
+ FreePool (TempString);
+ }
+ } else if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
+ return (TRUE);
+ }
+ }
+ }
+
+ return (FALSE);
+}
+
+/**
+ Returns value from command line argument.
+
+ Value parameters are in the form of "-<Key> value" or "/<Key> value".
+
+ If CheckPackage is NULL, then return NULL.
+
+ @param[in] CheckPackage The package of parsed command line arguments.
+ @param[in] KeyString The Key of the command line argument to check for.
+
+ @retval NULL The flag is not on the command line.
+ @retval !=NULL The pointer to unicode string of the value.
+**/
+CONST CHAR16 *
+EFIAPI
+ShellCommandLineGetValue (
+ IN CONST LIST_ENTRY *CheckPackage,
+ IN CHAR16 *KeyString
+ )
+{
+ LIST_ENTRY *Node;
+ CHAR16 *TempString;
+
+ //
+ // return NULL for no package or KeyString is NULL
+ //
+ if ((CheckPackage == NULL) || (KeyString == NULL)) {
+ return (NULL);
+ }
+
+ //
+ // enumerate through the list of parametrs
+ //
+ for ( Node = GetFirstNode (CheckPackage)
+ ; !IsNull (CheckPackage, Node)
+ ; Node = GetNextNode (CheckPackage, Node)
+ )
+ {
+ //
+ // If the Name matches, return TRUE (and there may be NULL name)
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Name != NULL) {
+ //
+ // If Type is TypeStart then only compare the begining of the strings
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->Type == TypeStart) {
+ if (StrnCmp (KeyString, ((SHELL_PARAM_PACKAGE *)Node)->Name, StrLen (KeyString)) == 0) {
+ return (((SHELL_PARAM_PACKAGE *)Node)->Name + StrLen (KeyString));
+ }
+
+ TempString = NULL;
+ TempString = StrnCatGrow (&TempString, NULL, KeyString, StrLen (((SHELL_PARAM_PACKAGE *)Node)->Name));
+ if (TempString != NULL) {
+ if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
+ FreePool (TempString);
+ return (((SHELL_PARAM_PACKAGE *)Node)->Name + StrLen (KeyString));
+ }
+
+ FreePool (TempString);
+ }
+ } else if (StringNoCaseCompare (&KeyString, &((SHELL_PARAM_PACKAGE *)Node)->Name) == 0) {
+ return (((SHELL_PARAM_PACKAGE *)Node)->Value);
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/**
+ Returns raw value from command line argument.
+
+ Raw value parameters are in the form of "value" in a specific position in the list.
+
+ If CheckPackage is NULL, then return NULL.
+
+ @param[in] CheckPackage The package of parsed command line arguments.
+ @param[in] Position The position of the value.
+
+ @retval NULL The flag is not on the command line.
+ @retval !=NULL The pointer to unicode string of the value.
+ **/
+CONST CHAR16 *
+EFIAPI
+ShellCommandLineGetRawValue (
+ IN CONST LIST_ENTRY *CONST CheckPackage,
+ IN UINTN Position
+ )
+{
+ LIST_ENTRY *Node;
+
+ //
+ // check for CheckPackage == NULL
+ //
+ if (CheckPackage == NULL) {
+ return (NULL);
+ }
+
+ //
+ // enumerate through the list of parametrs
+ //
+ for ( Node = GetFirstNode (CheckPackage)
+ ; !IsNull (CheckPackage, Node)
+ ; Node = GetNextNode (CheckPackage, Node)
+ )
+ {
+ //
+ // If the position matches, return the value
+ //
+ if (((SHELL_PARAM_PACKAGE *)Node)->OriginalPosition == Position) {
+ return (((SHELL_PARAM_PACKAGE *)Node)->Value);
+ }
+ }
+
+ return (NULL);
+}
+
+/**
+ returns the number of command line value parameters that were parsed.
+
+ this will not include flags.
+
+ @param[in] CheckPackage The package of parsed command line arguments.
+
+ @retval (UINTN)-1 No parsing has ocurred
+ @return other The number of value parameters found
+**/
+UINTN
+EFIAPI
+ShellCommandLineGetCount (
+ IN CONST LIST_ENTRY *CheckPackage
+ )
+{
+ LIST_ENTRY *Node1;
+ UINTN Count;
+
+ if (CheckPackage == NULL) {
+ return (0);
+ }
+
+ for ( Node1 = GetFirstNode (CheckPackage), Count = 0
+ ; !IsNull (CheckPackage, Node1)
+ ; Node1 = GetNextNode (CheckPackage, Node1)
+ )
+ {
+ if (((SHELL_PARAM_PACKAGE *)Node1)->Name == NULL) {
+ Count++;
+ }
+ }
+
+ return (Count);
+}
+
+/**
+ Determines if a parameter is duplicated.
+
+ If Param is not NULL then it will point to a callee allocated string buffer
+ with the parameter value if a duplicate is found.
+
+ If CheckPackage is NULL, then ASSERT.
+
+ @param[in] CheckPackage The package of parsed command line arguments.
+ @param[out] Param Upon finding one, a pointer to the duplicated parameter.
+
+ @retval EFI_SUCCESS No parameters were duplicated.
+ @retval EFI_DEVICE_ERROR A duplicate was found.
+ **/
+EFI_STATUS
+EFIAPI
+ShellCommandLineCheckDuplicate (
+ IN CONST LIST_ENTRY *CheckPackage,
+ OUT CHAR16 **Param
+ )
+{
+ LIST_ENTRY *Node1;
+ LIST_ENTRY *Node2;
+
+ ASSERT (CheckPackage != NULL);
+
+ for ( Node1 = GetFirstNode (CheckPackage)
+ ; !IsNull (CheckPackage, Node1)
+ ; Node1 = GetNextNode (CheckPackage, Node1)
+ )
+ {
+ for ( Node2 = GetNextNode (CheckPackage, Node1)
+ ; !IsNull (CheckPackage, Node2)
+ ; Node2 = GetNextNode (CheckPackage, Node2)
+ )
+ {
+ if ((((SHELL_PARAM_PACKAGE *)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE *)Node2)->Name != NULL) && (StrCmp (((SHELL_PARAM_PACKAGE *)Node1)->Name, ((SHELL_PARAM_PACKAGE *)Node2)->Name) == 0)) {
+ if (Param != NULL) {
+ *Param = NULL;
+ *Param = StrnCatGrow (Param, NULL, ((SHELL_PARAM_PACKAGE *)Node1)->Name, 0);
+ }
+
+ return (EFI_DEVICE_ERROR);
+ }
+ }
+ }
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ This is a find and replace function. Upon successful return the NewString is a copy of
+ SourceString with each instance of FindTarget replaced with ReplaceWith.
+
+ If SourceString and NewString overlap the behavior is undefined.
+
+ If the string would grow bigger than NewSize it will halt and return error.
+
+ @param[in] SourceString The string with source buffer.
+ @param[in, out] NewString The string with resultant buffer.
+ @param[in] NewSize The size in bytes of NewString.
+ @param[in] FindTarget The string to look for.
+ @param[in] ReplaceWith The string to replace FindTarget with.
+ @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
+ immediately before it.
+ @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
+
+ @retval EFI_INVALID_PARAMETER SourceString was NULL.
+ @retval EFI_INVALID_PARAMETER NewString was NULL.
+ @retval EFI_INVALID_PARAMETER FindTarget was NULL.
+ @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
+ @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
+ @retval EFI_INVALID_PARAMETER SourceString had length < 1.
+ @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
+ the new string (truncation occurred).
+ @retval EFI_SUCCESS The string was successfully copied with replacement.
+**/
+EFI_STATUS
+EFIAPI
+ShellCopySearchAndReplace (
+ IN CHAR16 CONST *SourceString,
+ IN OUT CHAR16 *NewString,
+ IN UINTN NewSize,
+ IN CONST CHAR16 *FindTarget,
+ IN CONST CHAR16 *ReplaceWith,
+ IN CONST BOOLEAN SkipPreCarrot,
+ IN CONST BOOLEAN ParameterReplacing
+ )
+{
+ UINTN Size;
+ CHAR16 *Replace;
+
+ if ( (SourceString == NULL)
+ || (NewString == NULL)
+ || (FindTarget == NULL)
+ || (ReplaceWith == NULL)
+ || (StrLen (FindTarget) < 1)
+ || (StrLen (SourceString) < 1)
+ )
+ {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Replace = NULL;
+ if ((StrStr (ReplaceWith, L" ") == NULL) || !ParameterReplacing) {
+ Replace = StrnCatGrow (&Replace, NULL, ReplaceWith, 0);
+ } else {
+ Replace = AllocateZeroPool (StrSize (ReplaceWith) + 2*sizeof (CHAR16));
+ if (Replace != NULL) {
+ UnicodeSPrint (Replace, StrSize (ReplaceWith) + 2*sizeof (CHAR16), L"\"%s\"", ReplaceWith);
+ }
+ }
+
+ if (Replace == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ NewString = ZeroMem (NewString, NewSize);
+ while (*SourceString != CHAR_NULL) {
+ //
+ // if we find the FindTarget and either Skip == FALSE or Skip and we
+ // dont have a carrot do a replace...
+ //
+ if ( (StrnCmp (SourceString, FindTarget, StrLen (FindTarget)) == 0)
+ && ((SkipPreCarrot && (*(SourceString-1) != L'^')) || !SkipPreCarrot)
+ )
+ {
+ SourceString += StrLen (FindTarget);
+ Size = StrSize (NewString);
+ if ((Size + (StrLen (Replace)*sizeof (CHAR16))) > NewSize) {
+ FreePool (Replace);
+ return (EFI_BUFFER_TOO_SMALL);
+ }
+
+ StrCatS (NewString, NewSize/sizeof (CHAR16), Replace);
+ } else {
+ Size = StrSize (NewString);
+ if (Size + sizeof (CHAR16) > NewSize) {
+ FreePool (Replace);
+ return (EFI_BUFFER_TOO_SMALL);
+ }
+
+ StrnCatS (NewString, NewSize/sizeof (CHAR16), SourceString, 1);
+ SourceString++;
+ }
+ }
+
+ FreePool (Replace);
+ return (EFI_SUCCESS);
+}
+
+/**
+ Internal worker function to output a string.
+
+ This function will output a string to the correct StdOut.
+
+ @param[in] String The string to print out.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval !EFI_SUCCESS The operation failed.
+**/
+EFI_STATUS
+InternalPrintTo (
+ IN CONST CHAR16 *String
+ )
+{
+ UINTN Size;
+
+ Size = StrSize (String) - sizeof (CHAR16);
+ if (Size == 0) {
+ return (EFI_SUCCESS);
+ }
+
+ if (gEfiShellParametersProtocol != NULL) {
+ return (gEfiShellProtocol->WriteFile (gEfiShellParametersProtocol->StdOut, &Size, (VOID *)String));
+ }
+
+ if (mEfiShellInterface != NULL) {
+ if (mEfiShellInterface->RedirArgc == 0) {
+ //
+ // Divide in half for old shell. Must be string length not size.
+ //
+ Size /= 2; // Divide in half only when no redirection.
+ }
+
+ return (mEfiShellInterface->StdOut->Write (mEfiShellInterface->StdOut, &Size, (VOID *)String));
+ }
+
+ ASSERT (FALSE);
+ return (EFI_UNSUPPORTED);
+}
+
+/**
+ Print at a specific location on the screen.
+
+ This function will move the cursor to a given screen location and print the specified string
+
+ If -1 is specified for either the Row or Col the current screen location for BOTH
+ will be used.
+
+ if either Row or Col is out of range for the current console, then ASSERT
+ if Format is NULL, then ASSERT
+
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports
+ the following additional flags:
+ %N - Set output attribute to normal
+ %H - Set output attribute to highlight
+ %E - Set output attribute to error
+ %B - Set output attribute to blue color
+ %V - Set output attribute to green color
+
+ Note: The background color is controlled by the shell command cls.
+
+ @param[in] Col the column to print at
+ @param[in] Row the row to print at
+ @param[in] Format the format string
+ @param[in] Marker the marker for the variable argument list
+
+ @return EFI_SUCCESS The operation was successful.
+ @return EFI_DEVICE_ERROR The console device reported an error.
+**/
+EFI_STATUS
+InternalShellPrintWorker (
+ IN INT32 Col OPTIONAL,
+ IN INT32 Row OPTIONAL,
+ IN CONST CHAR16 *Format,
+ IN VA_LIST Marker
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ResumeLocation;
+ CHAR16 *FormatWalker;
+ UINTN OriginalAttribute;
+ CHAR16 *mPostReplaceFormat;
+ CHAR16 *mPostReplaceFormat2;
+
+ mPostReplaceFormat = AllocateZeroPool (PcdGet32 (PcdShellPrintBufferSize));
+ mPostReplaceFormat2 = AllocateZeroPool (PcdGet32 (PcdShellPrintBufferSize));
+
+ if ((mPostReplaceFormat == NULL) || (mPostReplaceFormat2 == NULL)) {
+ SHELL_FREE_NON_NULL (mPostReplaceFormat);
+ SHELL_FREE_NON_NULL (mPostReplaceFormat2);
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ Status = EFI_SUCCESS;
+ OriginalAttribute = gST->ConOut->Mode->Attribute;
+
+ //
+ // Back and forth each time fixing up 1 of our flags...
+ //
+ Status = ShellCopySearchAndReplace (Format, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ Status = ShellCopySearchAndReplace (mPostReplaceFormat, mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ Status = ShellCopySearchAndReplace (mPostReplaceFormat2, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ Status = ShellCopySearchAndReplace (mPostReplaceFormat, mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ Status = ShellCopySearchAndReplace (mPostReplaceFormat2, mPostReplaceFormat, PcdGet32 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Use the last buffer from replacing to print from...
+ //
+ UnicodeVSPrint (mPostReplaceFormat2, PcdGet32 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);
+
+ if ((Col != -1) && (Row != -1)) {
+ Status = gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
+ }
+
+ FormatWalker = mPostReplaceFormat2;
+ while (*FormatWalker != CHAR_NULL) {
+ //
+ // Find the next attribute change request
+ //
+ ResumeLocation = StrStr (FormatWalker, L"%");
+ if (ResumeLocation != NULL) {
+ *ResumeLocation = CHAR_NULL;
+ }
+
+ //
+ // print the current FormatWalker string
+ //
+ if (StrLen (FormatWalker) > 0) {
+ Status = InternalPrintTo (FormatWalker);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // update the attribute
+ //
+ if (ResumeLocation != NULL) {
+ if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) {
+ //
+ // Move cursor back 1 position to overwrite the ^
+ //
+ gST->ConOut->SetCursorPosition (gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
+
+ //
+ // Print a simple '%' symbol
+ //
+ Status = InternalPrintTo (L"%");
+ ResumeLocation = ResumeLocation - 1;
+ } else {
+ switch (*(ResumeLocation+1)) {
+ case (L'N'):
+ gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
+ break;
+ case (L'E'):
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ break;
+ case (L'H'):
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ break;
+ case (L'B'):
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ break;
+ case (L'V'):
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ break;
+ default:
+ //
+ // Print a simple '%' symbol
+ //
+ Status = InternalPrintTo (L"%");
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ResumeLocation = ResumeLocation - 1;
+ break;
+ }
+ }
+ } else {
+ //
+ // reset to normal now...
+ //
+ break;
+ }
+
+ //
+ // update FormatWalker to Resume + 2 (skip the % and the indicator)
+ //
+ FormatWalker = ResumeLocation + 2;
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);
+
+ SHELL_FREE_NON_NULL (mPostReplaceFormat);
+ SHELL_FREE_NON_NULL (mPostReplaceFormat2);
+ return (Status);
+}
+
+/**
+ Print at a specific location on the screen.
+
+ This function will move the cursor to a given screen location and print the specified string.
+
+ If -1 is specified for either the Row or Col the current screen location for BOTH
+ will be used.
+
+ If either Row or Col is out of range for the current console, then ASSERT.
+ If Format is NULL, then ASSERT.
+
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports
+ the following additional flags:
+ %N - Set output attribute to normal
+ %H - Set output attribute to highlight
+ %E - Set output attribute to error
+ %B - Set output attribute to blue color
+ %V - Set output attribute to green color
+
+ Note: The background color is controlled by the shell command cls.
+
+ @param[in] Col the column to print at
+ @param[in] Row the row to print at
+ @param[in] Format the format string
+ @param[in] ... The variable argument list.
+
+ @return EFI_SUCCESS The printing was successful.
+ @return EFI_DEVICE_ERROR The console device reported an error.
+**/
+EFI_STATUS
+EFIAPI
+ShellPrintEx (
+ IN INT32 Col OPTIONAL,
+ IN INT32 Row OPTIONAL,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ VA_LIST Marker;
+ EFI_STATUS RetVal;
+
+ if (Format == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ VA_START (Marker, Format);
+ RetVal = InternalShellPrintWorker (Col, Row, Format, Marker);
+ VA_END (Marker);
+ return (RetVal);
+}
+
+/**
+ Print at a specific location on the screen.
+
+ This function will move the cursor to a given screen location and print the specified string.
+
+ If -1 is specified for either the Row or Col the current screen location for BOTH
+ will be used.
+
+ If either Row or Col is out of range for the current console, then ASSERT.
+ If Format is NULL, then ASSERT.
+
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports
+ the following additional flags:
+ %N - Set output attribute to normal.
+ %H - Set output attribute to highlight.
+ %E - Set output attribute to error.
+ %B - Set output attribute to blue color.
+ %V - Set output attribute to green color.
+
+ Note: The background color is controlled by the shell command cls.
+
+ @param[in] Col The column to print at.
+ @param[in] Row The row to print at.
+ @param[in] Language The language of the string to retrieve. If this parameter
+ is NULL, then the current platform language is used.
+ @param[in] HiiFormatStringId The format string Id for getting from Hii.
+ @param[in] HiiFormatHandle The format string Handle for getting from Hii.
+ @param[in] ... The variable argument list.
+
+ @return EFI_SUCCESS The printing was successful.
+ @return EFI_DEVICE_ERROR The console device reported an error.
+**/
+EFI_STATUS
+EFIAPI
+ShellPrintHiiEx (
+ IN INT32 Col OPTIONAL,
+ IN INT32 Row OPTIONAL,
+ IN CONST CHAR8 *Language OPTIONAL,
+ IN CONST EFI_STRING_ID HiiFormatStringId,
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,
+ ...
+ )
+{
+ VA_LIST Marker;
+ CHAR16 *HiiFormatString;
+ EFI_STATUS RetVal;
+
+ RetVal = EFI_DEVICE_ERROR;
+
+ VA_START (Marker, HiiFormatHandle);
+ HiiFormatString = HiiGetString (HiiFormatHandle, HiiFormatStringId, Language);
+ if (HiiFormatString != NULL) {
+ RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker);
+ SHELL_FREE_NON_NULL (HiiFormatString);
+ }
+
+ VA_END (Marker);
+
+ return (RetVal);
+}
+
+/**
+ Function to determine if a given filename represents a file or a directory.
+
+ @param[in] DirName Path to directory to test.
+
+ @retval EFI_SUCCESS The Path represents a directory
+ @retval EFI_NOT_FOUND The Path does not represent a directory
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @return The path failed to open
+**/
+EFI_STATUS
+EFIAPI
+ShellIsDirectory (
+ IN CONST CHAR16 *DirName
+ )
+{
+ EFI_STATUS Status;
+ SHELL_FILE_HANDLE Handle;
+ CHAR16 *TempLocation;
+ CHAR16 *TempLocation2;
+
+ ASSERT (DirName != NULL);
+
+ Handle = NULL;
+ TempLocation = NULL;
+
+ Status = ShellOpenFileByName (DirName, &Handle, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ //
+ // try good logic first.
+ //
+ if (gEfiShellProtocol != NULL) {
+ TempLocation = StrnCatGrow (&TempLocation, NULL, DirName, 0);
+ if (TempLocation == NULL) {
+ ShellCloseFile (&Handle);
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ TempLocation2 = StrStr (TempLocation, L":");
+ if ((TempLocation2 != NULL) && (StrLen (StrStr (TempLocation, L":")) == 2)) {
+ *(TempLocation2+1) = CHAR_NULL;
+ }
+
+ if (gEfiShellProtocol->GetDevicePathFromMap (TempLocation) != NULL) {
+ FreePool (TempLocation);
+ return (EFI_SUCCESS);
+ }
+
+ FreePool (TempLocation);
+ } else {
+ //
+ // probably a map name?!?!!?
+ //
+ TempLocation = StrStr (DirName, L"\\");
+ if ((TempLocation != NULL) && (*(TempLocation+1) == CHAR_NULL)) {
+ return (EFI_SUCCESS);
+ }
+ }
+
+ return (Status);
+ }
+
+ if (FileHandleIsDirectory (Handle) == EFI_SUCCESS) {
+ ShellCloseFile (&Handle);
+ return (EFI_SUCCESS);
+ }
+
+ ShellCloseFile (&Handle);
+ return (EFI_NOT_FOUND);
+}
+
+/**
+ Function to determine if a given filename represents a file.
+
+ @param[in] Name Path to file to test.
+
+ @retval EFI_SUCCESS The Path represents a file.
+ @retval EFI_NOT_FOUND The Path does not represent a file.
+ @retval other The path failed to open.
+**/
+EFI_STATUS
+EFIAPI
+ShellIsFile (
+ IN CONST CHAR16 *Name
+ )
+{
+ EFI_STATUS Status;
+ SHELL_FILE_HANDLE Handle;
+
+ ASSERT (Name != NULL);
+
+ Handle = NULL;
+
+ Status = ShellOpenFileByName (Name, &Handle, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return (Status);
+ }
+
+ if (FileHandleIsDirectory (Handle) != EFI_SUCCESS) {
+ ShellCloseFile (&Handle);
+ return (EFI_SUCCESS);
+ }
+
+ ShellCloseFile (&Handle);
+ return (EFI_NOT_FOUND);
+}
+
+/**
+ Function to determine if a given filename represents a file.
+
+ This will search the CWD and then the Path.
+
+ If Name is NULL, then ASSERT.
+
+ @param[in] Name Path to file to test.
+
+ @retval EFI_SUCCESS The Path represents a file.
+ @retval EFI_NOT_FOUND The Path does not represent a file.
+ @retval other The path failed to open.
+**/
+EFI_STATUS
+EFIAPI
+ShellIsFileInPath (
+ IN CONST CHAR16 *Name
+ )
+{
+ CHAR16 *NewName;
+ EFI_STATUS Status;
+
+ if (!EFI_ERROR (ShellIsFile (Name))) {
+ return (EFI_SUCCESS);
+ }
+
+ NewName = ShellFindFilePath (Name);
+ if (NewName == NULL) {
+ return (EFI_NOT_FOUND);
+ }
+
+ Status = ShellIsFile (NewName);
+ FreePool (NewName);
+ return (Status);
+}
+
+/**
+ Function return the number converted from a hex representation of a number.
+
+ Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
+ result. Use ShellConvertStringToUint64 instead.
+
+ @param[in] String String representation of a number.
+
+ @return The unsigned integer result of the conversion.
+ @retval (UINTN)(-1) An error occurred.
+**/
+UINTN
+EFIAPI
+ShellHexStrToUintn (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 RetVal;
+
+ if (!EFI_ERROR (ShellConvertStringToUint64 (String, &RetVal, TRUE, TRUE))) {
+ return ((UINTN)RetVal);
+ }
+
+ return ((UINTN)(-1));
+}
+
+/**
+ Function to determine whether a string is decimal or hex representation of a number
+ and return the number converted from the string. Spaces are always skipped.
+
+ @param[in] String String representation of a number
+
+ @return the number
+ @retval (UINTN)(-1) An error ocurred.
+**/
+UINTN
+EFIAPI
+ShellStrToUintn (
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 RetVal;
+ BOOLEAN Hex;
+
+ Hex = FALSE;
+
+ if (!InternalShellIsHexOrDecimalNumber (String, Hex, TRUE, FALSE)) {
+ Hex = TRUE;
+ }
+
+ if (!EFI_ERROR (ShellConvertStringToUint64 (String, &RetVal, Hex, TRUE))) {
+ return ((UINTN)RetVal);
+ }
+
+ return ((UINTN)(-1));
+}
+
+/**
+ Safely append with automatic string resizing given length of Destination and
+ desired length of copy from Source.
+
+ append the first D characters of Source to the end of Destination, where D is
+ the lesser of Count and the StrLen() of Source. If appending those D characters
+ will fit within Destination (whose Size is given as CurrentSize) and
+ still leave room for a NULL terminator, then those characters are appended,
+ starting at the original terminating NULL of Destination, and a new terminating
+ NULL is appended.
+
+ If appending D characters onto Destination will result in a overflow of the size
+ given in CurrentSize the string will be grown such that the copy can be performed
+ and CurrentSize will be updated to the new size.
+
+ If Source is NULL, there is nothing to append, just return the current buffer in
+ Destination.
+
+ if Destination is NULL, then ASSERT()
+ if Destination's current length (including NULL terminator) is already more then
+ CurrentSize, then ASSERT()
+
+ @param[in, out] Destination The String to append onto
+ @param[in, out] CurrentSize on call the number of bytes in Destination. On
+ return possibly the new size (still in bytes). if NULL
+ then allocate whatever is needed.
+ @param[in] Source The String to append from
+ @param[in] Count Maximum number of characters to append. if 0 then
+ all are appended.
+
+ @return Destination return the resultant string.
+**/
+CHAR16 *
+EFIAPI
+StrnCatGrow (
+ IN OUT CHAR16 **Destination,
+ IN OUT UINTN *CurrentSize,
+ IN CONST CHAR16 *Source,
+ IN UINTN Count
+ )
+{
+ UINTN DestinationStartSize;
+ UINTN NewSize;
+
+ //
+ // ASSERTs
+ //
+ ASSERT (Destination != NULL);
+
+ //
+ // If there's nothing to do then just return Destination
+ //
+ if (Source == NULL) {
+ return (*Destination);
+ }
+
+ //
+ // allow for un-initialized pointers, based on size being 0
+ //
+ if ((CurrentSize != NULL) && (*CurrentSize == 0)) {
+ *Destination = NULL;
+ }
+
+ //
+ // allow for NULL pointers address as Destination
+ //
+ if (*Destination != NULL) {
+ ASSERT (CurrentSize != 0);
+ DestinationStartSize = StrSize (*Destination);
+ ASSERT (DestinationStartSize <= *CurrentSize);
+ } else {
+ DestinationStartSize = 0;
+ // ASSERT(*CurrentSize == 0);
+ }
+
+ //
+ // Append all of Source?
+ //
+ if (Count == 0) {
+ Count = StrLen (Source);
+ }
+
+ //
+ // Test and grow if required
+ //
+ if (CurrentSize != NULL) {
+ NewSize = *CurrentSize;
+ if (NewSize < DestinationStartSize + (Count * sizeof (CHAR16))) {
+ while (NewSize < (DestinationStartSize + (Count*sizeof (CHAR16)))) {
+ NewSize += 2 * Count * sizeof (CHAR16);
+ }
+
+ *Destination = ReallocatePool (*CurrentSize, NewSize, *Destination);
+ *CurrentSize = NewSize;
+ }
+ } else {
+ NewSize = (Count+1)*sizeof (CHAR16);
+ *Destination = AllocateZeroPool (NewSize);
+ }
+
+ //
+ // Now use standard StrnCat on a big enough buffer
+ //
+ if (*Destination == NULL) {
+ return (NULL);
+ }
+
+ StrnCatS (*Destination, NewSize/sizeof (CHAR16), Source, Count);
+ return *Destination;
+}
+
+/**
+ Prompt the user and return the resultant answer to the requestor.
+
+ This function will display the requested question on the shell prompt and then
+ wait for an appropriate answer to be input from the console.
+
+ if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
+ or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
+
+ if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
+ CHAR16*.
+
+ In either case *Response must be callee freed if Response was not NULL;
+
+ @param Type What type of question is asked. This is used to filter the input
+ to prevent invalid answers to question.
+ @param Prompt Pointer to string prompt to use to request input.
+ @param Response Pointer to Response which will be populated upon return.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_UNSUPPORTED The operation is not supported as requested.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @return other The operation failed.
+**/
+EFI_STATUS
+EFIAPI
+ShellPromptForResponse (
+ IN SHELL_PROMPT_REQUEST_TYPE Type,
+ IN CHAR16 *Prompt OPTIONAL,
+ IN OUT VOID **Response OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ UINTN EventIndex;
+ SHELL_PROMPT_RESPONSE *Resp;
+ UINTN Size;
+ CHAR16 *Buffer;
+
+ Status = EFI_UNSUPPORTED;
+ Resp = NULL;
+ Buffer = NULL;
+ Size = 0;
+ if (Type != ShellPromptResponseTypeFreeform) {
+ Resp = (SHELL_PROMPT_RESPONSE *)AllocateZeroPool (sizeof (SHELL_PROMPT_RESPONSE));
+ if (Resp == NULL) {
+ if (Response != NULL) {
+ *Response = NULL;
+ }
+
+ return (EFI_OUT_OF_RESOURCES);
+ }
+ }
+
+ switch (Type) {
+ case ShellPromptResponseTypeQuitContinue:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ //
+ // wait for valid response
+ //
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ if ((Key.UnicodeChar == L'Q') || (Key.UnicodeChar == L'q')) {
+ *Resp = ShellPromptResponseQuit;
+ } else {
+ *Resp = ShellPromptResponseContinue;
+ }
+
+ break;
+ case ShellPromptResponseTypeYesNoCancel:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ //
+ // wait for valid response
+ //
+ *Resp = ShellPromptResponseMax;
+ while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ switch (Key.UnicodeChar) {
+ case L'Y':
+ case L'y':
+ *Resp = ShellPromptResponseYes;
+ break;
+ case L'N':
+ case L'n':
+ *Resp = ShellPromptResponseNo;
+ break;
+ case L'C':
+ case L'c':
+ *Resp = ShellPromptResponseCancel;
+ break;
+ }
+ }
+
+ break;
+ case ShellPromptResponseTypeYesNoAllCancel:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ //
+ // wait for valid response
+ //
+ *Resp = ShellPromptResponseMax;
+ while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if ((Key.UnicodeChar <= 127) && (Key.UnicodeChar >= 32)) {
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ }
+
+ switch (Key.UnicodeChar) {
+ case L'Y':
+ case L'y':
+ *Resp = ShellPromptResponseYes;
+ break;
+ case L'N':
+ case L'n':
+ *Resp = ShellPromptResponseNo;
+ break;
+ case L'A':
+ case L'a':
+ *Resp = ShellPromptResponseAll;
+ break;
+ case L'C':
+ case L'c':
+ *Resp = ShellPromptResponseCancel;
+ break;
+ }
+ }
+
+ break;
+ case ShellPromptResponseTypeEnterContinue:
+ case ShellPromptResponseTypeAnyKeyContinue:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ //
+ // wait for valid response
+ //
+ *Resp = ShellPromptResponseMax;
+ while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ if (Type == ShellPromptResponseTypeEnterContinue) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ *Resp = ShellPromptResponseContinue;
+ break;
+ }
+ }
+
+ if (Type == ShellPromptResponseTypeAnyKeyContinue) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ ASSERT_EFI_ERROR (Status);
+ *Resp = ShellPromptResponseContinue;
+ break;
+ }
+ }
+
+ break;
+ case ShellPromptResponseTypeYesNo:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ //
+ // wait for valid response
+ //
+ *Resp = ShellPromptResponseMax;
+ while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ switch (Key.UnicodeChar) {
+ case L'Y':
+ case L'y':
+ *Resp = ShellPromptResponseYes;
+ break;
+ case L'N':
+ case L'n':
+ *Resp = ShellPromptResponseNo;
+ break;
+ }
+ }
+
+ break;
+ case ShellPromptResponseTypeFreeform:
+ if (Prompt != NULL) {
+ ShellPrintEx (-1, -1, L"%s", Prompt);
+ }
+
+ while (1) {
+ if (ShellGetExecutionBreakFlag ()) {
+ Status = EFI_ABORTED;
+ break;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ break;
+ }
+
+ ASSERT ((Buffer == NULL && Size == 0) || (Buffer != NULL));
+ StrnCatGrow (&Buffer, &Size, &Key.UnicodeChar, 1);
+ }
+
+ break;
+ //
+ // This is the location to add new prompt types.
+ // If your new type loops remember to add ExecutionBreak support.
+ //
+ default:
+ ASSERT (FALSE);
+ }
+
+ if (Response != NULL) {
+ if (Resp != NULL) {
+ *Response = Resp;
+ } else if (Buffer != NULL) {
+ *Response = Buffer;
+ } else {
+ *Response = NULL;
+ }
+ } else {
+ if (Resp != NULL) {
+ FreePool (Resp);
+ }
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+ }
+
+ ShellPrintEx (-1, -1, L"\r\n");
+ return (Status);
+}
+
+/**
+ Prompt the user and return the resultant answer to the requestor.
+
+ This function is the same as ShellPromptForResponse, except that the prompt is
+ automatically pulled from HII.
+
+ @param Type What type of question is asked. This is used to filter the input
+ to prevent invalid answers to question.
+ @param[in] HiiFormatStringId The format string Id for getting from Hii.
+ @param[in] HiiFormatHandle The format string Handle for getting from Hii.
+ @param Response Pointer to Response which will be populated upon return.
+
+ @retval EFI_SUCCESS the operation was successful.
+ @return other the operation failed.
+
+ @sa ShellPromptForResponse
+**/
+EFI_STATUS
+EFIAPI
+ShellPromptForResponseHii (
+ IN SHELL_PROMPT_REQUEST_TYPE Type,
+ IN CONST EFI_STRING_ID HiiFormatStringId,
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,
+ IN OUT VOID **Response
+ )
+{
+ CHAR16 *Prompt;
+ EFI_STATUS Status;
+
+ Prompt = HiiGetString (HiiFormatHandle, HiiFormatStringId, NULL);
+ Status = ShellPromptForResponse (Type, Prompt, Response);
+ FreePool (Prompt);
+ return (Status);
+}
+
+/**
+ Function to determin if an entire string is a valid number.
+
+ If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
+
+ @param[in] String The string to evaluate.
+ @param[in] ForceHex TRUE - always assume hex.
+ @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
+ @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
+
+ @retval TRUE It is all numeric (dec/hex) characters.
+ @retval FALSE There is a non-numeric character.
+**/
+BOOLEAN
+InternalShellIsHexOrDecimalNumber (
+ IN CONST CHAR16 *String,
+ IN CONST BOOLEAN ForceHex,
+ IN CONST BOOLEAN StopAtSpace,
+ IN CONST BOOLEAN TimeNumbers
+ )
+{
+ BOOLEAN Hex;
+ BOOLEAN LeadingZero;
+
+ if (String == NULL) {
+ return FALSE;
+ }
+
+ //
+ // chop off a single negative sign
+ //
+ if (*String == L'-') {
+ String++;
+ }
+
+ if (*String == CHAR_NULL) {
+ return FALSE;
+ }
+
+ //
+ // chop leading zeroes
+ //
+ LeadingZero = FALSE;
+ while (*String == L'0') {
+ String++;
+ LeadingZero = TRUE;
+ }
+
+ //
+ // allow '0x' or '0X', but not 'x' or 'X'
+ //
+ if ((*String == L'x') || (*String == L'X')) {
+ if (!LeadingZero) {
+ //
+ // we got an x without a preceeding 0
+ //
+ return (FALSE);
+ }
+
+ String++;
+ Hex = TRUE;
+ } else if (ForceHex) {
+ Hex = TRUE;
+ } else {
+ Hex = FALSE;
+ }
+
+ //
+ // loop through the remaining characters and use the lib function
+ //
+ for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' '); String++) {
+ if (TimeNumbers && (String[0] == L':')) {
+ continue;
+ }
+
+ if (Hex) {
+ if (!ShellIsHexaDecimalDigitCharacter (*String)) {
+ return (FALSE);
+ }
+ } else {
+ if (!ShellIsDecimalDigitCharacter (*String)) {
+ return (FALSE);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+/**
+ Function to determine if a given filename exists.
+
+ @param[in] Name Path to test.
+
+ @retval EFI_SUCCESS The Path represents a file.
+ @retval EFI_NOT_FOUND The Path does not represent a file.
+ @retval other The path failed to open.
+**/
+EFI_STATUS
+EFIAPI
+ShellFileExists (
+ IN CONST CHAR16 *Name
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_FILE_INFO *List;
+
+ ASSERT (Name != NULL);
+
+ List = NULL;
+ Status = ShellOpenFileMetaArg ((CHAR16 *)Name, EFI_FILE_MODE_READ, &List);
+ if (EFI_ERROR (Status)) {
+ return (Status);
+ }
+
+ ShellCloseFileMetaArg (&List);
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Convert a Unicode character to numerical value.
+
+ This internal function only deal with Unicode character
+ which maps to a valid hexadecimal ASII character, i.e.
+ L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
+ Unicode character, the value returned does not make sense.
+
+ @param Char The character to convert.
+
+ @return The numerical value converted.
+
+**/
+UINTN
+InternalShellHexCharToUintn (
+ IN CHAR16 Char
+ )
+{
+ if (ShellIsDecimalDigitCharacter (Char)) {
+ return Char - L'0';
+ }
+
+ return (10 + CharToUpper (Char) - L'A');
+}
+
+/**
+ Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a hexadecimal number.
+ The format of the input Unicode string String is:
+
+ [spaces][zeros][x][hexadecimal digits].
+
+ The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+ The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+ If "x" appears in the input string, it must be prefixed with at least one 0.
+ The function will ignore the pad space, which includes spaces or tab characters,
+ before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+ [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+ first valid hexadecimal digit. Then, the function stops at the first character that is
+ a not a valid hexadecimal character or NULL, whichever one comes first.
+
+ If String has only pad spaces, then zero is returned.
+ If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+ then zero is returned.
+
+ @param[in] String A pointer to a Null-terminated Unicode string.
+ @param[out] Value Upon a successful return the value of the conversion.
+ @param[in] StopAtSpace FALSE to skip spaces.
+
+ @retval EFI_SUCCESS The conversion was successful.
+ @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
+ @retval EFI_DEVICE_ERROR An overflow occurred.
+**/
+EFI_STATUS
+InternalShellStrHexToUint64 (
+ IN CONST CHAR16 *String,
+ OUT UINT64 *Value,
+ IN CONST BOOLEAN StopAtSpace
+ )
+{
+ UINT64 Result;
+
+ if ((String == NULL) || (StrSize (String) == 0) || (Value == NULL)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ if (CharToUpper (*String) == L'X') {
+ if (*(String - 1) != L'0') {
+ return 0;
+ }
+
+ //
+ // Skip the 'X'
+ //
+ String++;
+ }
+
+ Result = 0;
+
+ //
+ // there is a space where there should't be
+ //
+ if (*String == L' ') {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ while (ShellIsHexaDecimalDigitCharacter (*String)) {
+ //
+ // If the Hex Number represented by String overflows according
+ // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
+ //
+ if (!(Result <= (RShiftU64 ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
+ // if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
+ return (EFI_DEVICE_ERROR);
+ }
+
+ Result = (LShiftU64 (Result, 4));
+ Result += InternalShellHexCharToUintn (*String);
+ String++;
+
+ //
+ // stop at spaces if requested
+ //
+ if (StopAtSpace && (*String == L' ')) {
+ break;
+ }
+ }
+
+ *Value = Result;
+ return (EFI_SUCCESS);
+}
+
+/**
+ Convert a Null-terminated Unicode decimal string to a value of
+ type UINT64.
+
+ This function returns a value of type UINT64 by interpreting the contents
+ of the Unicode string specified by String as a decimal number. The format
+ of the input Unicode string String is:
+
+ [spaces] [decimal digits].
+
+ The valid decimal digit character is in the range [0-9]. The
+ function will ignore the pad space, which includes spaces or
+ tab characters, before [decimal digits]. The running zero in the
+ beginning of [decimal digits] will be ignored. Then, the function
+ stops at the first character that is a not a valid decimal character
+ or a Null-terminator, whichever one comes first.
+
+ If String has only pad spaces, then 0 is returned.
+ If String has no pad spaces or valid decimal digits,
+ then 0 is returned.
+
+ @param[in] String A pointer to a Null-terminated Unicode string.
+ @param[out] Value Upon a successful return the value of the conversion.
+ @param[in] StopAtSpace FALSE to skip spaces.
+
+ @retval EFI_SUCCESS The conversion was successful.
+ @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
+ @retval EFI_DEVICE_ERROR An overflow occurred.
+**/
+EFI_STATUS
+InternalShellStrDecimalToUint64 (
+ IN CONST CHAR16 *String,
+ OUT UINT64 *Value,
+ IN CONST BOOLEAN StopAtSpace
+ )
+{
+ UINT64 Result;
+
+ if ((String == NULL) || (StrSize (String) == 0) || (Value == NULL)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Ignore the pad spaces (space or tab)
+ //
+ while ((*String == L' ') || (*String == L'\t')) {
+ String++;
+ }
+
+ //
+ // Ignore leading Zeros after the spaces
+ //
+ while (*String == L'0') {
+ String++;
+ }
+
+ Result = 0;
+
+ //
+ // Stop upon space if requested
+ // (if the whole value was 0)
+ //
+ if (StopAtSpace && (*String == L' ')) {
+ *Value = Result;
+ return (EFI_SUCCESS);
+ }
+
+ while (ShellIsDecimalDigitCharacter (*String)) {
+ //
+ // If the number represented by String overflows according
+ // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
+ //
+
+ if (!(Result <= (DivU64x32 ((((UINT64) ~0) - (*String - L'0')), 10)))) {
+ return (EFI_DEVICE_ERROR);
+ }
+
+ Result = MultU64x32 (Result, 10) + (*String - L'0');
+ String++;
+
+ //
+ // Stop at spaces if requested
+ //
+ if (StopAtSpace && (*String == L' ')) {
+ break;
+ }
+ }
+
+ *Value = Result;
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Function to verify and convert a string to its numerical value.
+
+ If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
+
+ @param[in] String The string to evaluate.
+ @param[out] Value Upon a successful return the value of the conversion.
+ @param[in] ForceHex TRUE - always assume hex.
+ @param[in] StopAtSpace FALSE to skip spaces.
+
+ @retval EFI_SUCCESS The conversion was successful.
+ @retval EFI_INVALID_PARAMETER String contained an invalid character.
+ @retval EFI_NOT_FOUND String was a number, but Value was NULL.
+**/
+EFI_STATUS
+EFIAPI
+ShellConvertStringToUint64 (
+ IN CONST CHAR16 *String,
+ OUT UINT64 *Value,
+ IN CONST BOOLEAN ForceHex,
+ IN CONST BOOLEAN StopAtSpace
+ )
+{
+ UINT64 RetVal;
+ CONST CHAR16 *Walker;
+ EFI_STATUS Status;
+ BOOLEAN Hex;
+
+ Hex = ForceHex;
+
+ if (!InternalShellIsHexOrDecimalNumber (String, Hex, StopAtSpace, FALSE)) {
+ if (!Hex) {
+ Hex = TRUE;
+ if (!InternalShellIsHexOrDecimalNumber (String, Hex, StopAtSpace, FALSE)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+ } else {
+ return (EFI_INVALID_PARAMETER);
+ }
+ }
+
+ //
+ // Chop off leading spaces
+ //
+ for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++) {
+ }
+
+ //
+ // make sure we have something left that is numeric.
+ //
+ if ((Walker == NULL) || (*Walker == CHAR_NULL) || !InternalShellIsHexOrDecimalNumber (Walker, Hex, StopAtSpace, FALSE)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // do the conversion.
+ //
+ if (Hex || (StrnCmp (Walker, L"0x", 2) == 0) || (StrnCmp (Walker, L"0X", 2) == 0)) {
+ Status = InternalShellStrHexToUint64 (Walker, &RetVal, StopAtSpace);
+ } else {
+ Status = InternalShellStrDecimalToUint64 (Walker, &RetVal, StopAtSpace);
+ }
+
+ if ((Value == NULL) && !EFI_ERROR (Status)) {
+ return (EFI_NOT_FOUND);
+ }
+
+ if (Value != NULL) {
+ *Value = RetVal;
+ }
+
+ return (Status);
+}
+
+/**
+ Function to determin if an entire string is a valid number.
+
+ If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
+
+ @param[in] String The string to evaluate.
+ @param[in] ForceHex TRUE - always assume hex.
+ @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
+
+ @retval TRUE It is all numeric (dec/hex) characters.
+ @retval FALSE There is a non-numeric character.
+**/
+BOOLEAN
+EFIAPI
+ShellIsHexOrDecimalNumber (
+ IN CONST CHAR16 *String,
+ IN CONST BOOLEAN ForceHex,
+ IN CONST BOOLEAN StopAtSpace
+ )
+{
+ if (ShellConvertStringToUint64 (String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/**
+ Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
+ buffer. The returned buffer must be callee freed.
+
+ If the position upon start is 0, then the Ascii Boolean will be set. This should be
+ maintained and not changed for all operations with the same file.
+
+ @param[in] Handle SHELL_FILE_HANDLE to read from.
+ @param[in, out] Ascii Boolean value for indicating whether the file is
+ Ascii (TRUE) or UCS2 (FALSE).
+
+ @return The line of text from the file.
+ @retval NULL There was not enough memory available.
+
+ @sa ShellFileHandleReadLine
+**/
+CHAR16 *
+EFIAPI
+ShellFileHandleReturnLine (
+ IN SHELL_FILE_HANDLE Handle,
+ IN OUT BOOLEAN *Ascii
+ )
+{
+ CHAR16 *RetVal;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ Size = 0;
+ RetVal = NULL;
+
+ Status = ShellFileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ RetVal = AllocateZeroPool (Size);
+ if (RetVal == NULL) {
+ return (NULL);
+ }
+
+ Status = ShellFileHandleReadLine (Handle, RetVal, &Size, FALSE, Ascii);
+ }
+
+ if ((Status == EFI_END_OF_FILE) && (RetVal != NULL) && (*RetVal != CHAR_NULL)) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status) && (RetVal != NULL)) {
+ FreePool (RetVal);
+ RetVal = NULL;
+ }
+
+ return (RetVal);
+}
+
+/**
+ Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
+
+ If the position upon start is 0, then the Ascii Boolean will be set. This should be
+ maintained and not changed for all operations with the same file.
+
+ NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
+ IS IN ASCII FORMAT.
+
+ @param[in] Handle SHELL_FILE_HANDLE to read from.
+ @param[in, out] Buffer The pointer to buffer to read into. If this function
+ returns EFI_SUCCESS, then on output Buffer will
+ contain a UCS2 string, even if the file being
+ read is ASCII.
+ @param[in, out] Size On input, pointer to number of bytes in Buffer.
+ On output, unchanged unless Buffer is too small
+ to contain the next line of the file. In that
+ case Size is set to the number of bytes needed
+ to hold the next line of the file (as a UCS2
+ string, even if it is an ASCII file).
+ @param[in] Truncate If the buffer is large enough, this has no effect.
+ If the buffer is is too small and Truncate is TRUE,
+ the line will be truncated.
+ If the buffer is is too small and Truncate is FALSE,
+ then no read will occur.
+
+ @param[in, out] Ascii Boolean value for indicating whether the file is
+ Ascii (TRUE) or UCS2 (FALSE).
+
+ @retval EFI_SUCCESS The operation was successful. The line is stored in
+ Buffer.
+ @retval EFI_END_OF_FILE There are no more lines in the file.
+ @retval EFI_INVALID_PARAMETER Handle was NULL.
+ @retval EFI_INVALID_PARAMETER Size was NULL.
+ @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
+ Size was updated to the minimum space required.
+**/
+EFI_STATUS
+EFIAPI
+ShellFileHandleReadLine (
+ IN SHELL_FILE_HANDLE Handle,
+ IN OUT CHAR16 *Buffer,
+ IN OUT UINTN *Size,
+ IN BOOLEAN Truncate,
+ IN OUT BOOLEAN *Ascii
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 CharBuffer;
+ UINTN CharSize;
+ UINTN CountSoFar;
+ UINT64 OriginalFilePosition;
+
+ if ( (Handle == NULL)
+ || (Size == NULL)
+ )
+ {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if (Buffer == NULL) {
+ ASSERT (*Size == 0);
+ } else {
+ *Buffer = CHAR_NULL;
+ }
+
+ gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);
+ if (OriginalFilePosition == 0) {
+ CharSize = sizeof (CHAR16);
+ Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
+ ASSERT_EFI_ERROR (Status);
+ if (CharBuffer == gUnicodeFileTag) {
+ *Ascii = FALSE;
+ } else {
+ *Ascii = TRUE;
+ gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition);
+ }
+ }
+
+ if (*Ascii) {
+ CharSize = sizeof (CHAR8);
+ } else {
+ CharSize = sizeof (CHAR16);
+ }
+
+ for (CountSoFar = 0; ; CountSoFar++) {
+ CharBuffer = 0;
+ Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
+ if ( EFI_ERROR (Status)
+ || (CharSize == 0)
+ || ((CharBuffer == L'\n') && !(*Ascii))
+ || ((CharBuffer == '\n') && *Ascii)
+ )
+ {
+ if (CharSize == 0) {
+ Status = EFI_END_OF_FILE;
+ }
+
+ break;
+ }
+
+ //
+ // if we have space save it...
+ //
+ if ((CountSoFar+1)*sizeof (CHAR16) < *Size) {
+ ASSERT (Buffer != NULL);
+ ((CHAR16 *)Buffer)[CountSoFar] = CharBuffer;
+ ((CHAR16 *)Buffer)[CountSoFar+1] = CHAR_NULL;
+ }
+ }
+
+ //
+ // if we ran out of space tell when...
+ //
+ if ((CountSoFar+1)*sizeof (CHAR16) > *Size) {
+ *Size = (CountSoFar+1)*sizeof (CHAR16);
+ if (!Truncate) {
+ gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition);
+ } else {
+ DEBUG ((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
+ }
+
+ return (EFI_BUFFER_TOO_SMALL);
+ }
+
+ while (Buffer[StrLen (Buffer)-1] == L'\r') {
+ Buffer[StrLen (Buffer)-1] = CHAR_NULL;
+ }
+
+ return (Status);
+}
+
+/**
+ Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
+
+ @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
+ @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
+ @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
+ the help content only.
+ @retval EFI_DEVICE_ERROR The help data format was incorrect.
+ @retval EFI_NOT_FOUND The help data could not be found.
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+ShellPrintHelp (
+ IN CONST CHAR16 *CommandToGetHelpOn,
+ IN CONST CHAR16 *SectionToGetHelpOn,
+ IN BOOLEAN PrintCommandText
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *OutText;
+
+ OutText = NULL;
+
+ //
+ // Get the string to print based
+ //
+ Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
+
+ //
+ // make sure we got a valid string
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((OutText == NULL) || (StrLen (OutText) == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Chop off trailing stuff we dont need
+ //
+ while (OutText[StrLen (OutText)-1] == L'\r' || OutText[StrLen (OutText)-1] == L'\n' || OutText[StrLen (OutText)-1] == L' ') {
+ OutText[StrLen (OutText)-1] = CHAR_NULL;
+ }
+
+ //
+ // Print this out to the console
+ //
+ if (PrintCommandText) {
+ ShellPrintEx (-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
+ } else {
+ ShellPrintEx (-1, -1, L"%N%s\r\n", OutText);
+ }
+
+ SHELL_FREE_NON_NULL (OutText);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to delete a file by name
+
+ @param[in] FileName Pointer to file name to delete.
+
+ @retval EFI_SUCCESS the file was deleted sucessfully
+ @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
+ deleted
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found
+ on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval other The file failed to open
+**/
+EFI_STATUS
+EFIAPI
+ShellDeleteFileByName (
+ IN CONST CHAR16 *FileName
+ )
+{
+ EFI_STATUS Status;
+ SHELL_FILE_HANDLE FileHandle;
+
+ Status = ShellFileExists (FileName);
+
+ if (Status == EFI_SUCCESS) {
+ Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
+ if (Status == EFI_SUCCESS) {
+ Status = ShellDeleteFile (&FileHandle);
+ }
+ }
+
+ return (Status);
+}
+
+/**
+ Cleans off all the quotes in the string.
+
+ @param[in] OriginalString pointer to the string to be cleaned.
+ @param[out] CleanString The new string with all quotes removed.
+ Memory allocated in the function and free
+ by caller.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+InternalShellStripQuotes (
+ IN CONST CHAR16 *OriginalString,
+ OUT CHAR16 **CleanString
+ )
+{
+ CHAR16 *Walker;
+
+ if ((OriginalString == NULL) || (CleanString == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
+ if (*CleanString == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL; Walker++) {
+ if (*Walker == L'\"') {
+ CopyMem (Walker, Walker+1, StrSize (Walker) - sizeof (Walker[0]));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.h b/ShellPkg/Library/UefiShellLib/UefiShellLib.h
index 3015188a01..e88b4461c6 100644
--- a/ShellPkg/Library/UefiShellLib/UefiShellLib.h
+++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.h
@@ -1,88 +1,88 @@
-/** @file
- Provides interface to shell functionality for shell commands and applications.
-
- (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _UEFI_SHELL_LIB_INTERNAL_H_
-#define _UEFI_SHELL_LIB_INTERNAL_H_
-
-#include <Uefi.h>
-
-#include <Guid/FileInfo.h>
-
-#include <Protocol/SimpleFileSystem.h>
-#include <Protocol/LoadedImage.h>
-#include <Protocol/EfiShellInterface.h>
-#include <Protocol/EfiShellEnvironment2.h>
-#include <Protocol/Shell.h>
-#include <Protocol/ShellParameters.h>
-#include <Protocol/UnicodeCollation.h>
-
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/PcdLib.h>
-#include <Library/FileHandleLib.h>
-#include <Library/PrintLib.h>
-#include <Library/UefiLib.h>
-#include <Library/HiiLib.h>
-#include <Library/ShellLib.h>
-
-typedef struct {
- EFI_SHELL_GET_FILE_INFO GetFileInfo;
- EFI_SHELL_SET_FILE_INFO SetFileInfo;
- EFI_SHELL_READ_FILE ReadFile;
- EFI_SHELL_WRITE_FILE WriteFile;
- EFI_SHELL_CLOSE_FILE CloseFile;
- EFI_SHELL_DELETE_FILE DeleteFile;
- EFI_SHELL_GET_FILE_POSITION GetFilePosition;
- EFI_SHELL_SET_FILE_POSITION SetFilePosition;
- EFI_SHELL_FLUSH_FILE FlushFile;
- EFI_SHELL_GET_FILE_SIZE GetFileSize;
-} FILE_HANDLE_FUNCTION_MAP;
-
-/**
- Function to determin if an entire string is a valid number.
-
- If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
-
- @param[in] String The string to evaluate.
- @param[in] ForceHex TRUE - always assume hex.
- @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
- @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
-
- @retval TRUE It is all numeric (dec/hex) characters.
- @retval FALSE There is a non-numeric character.
-**/
-BOOLEAN
-InternalShellIsHexOrDecimalNumber (
- IN CONST CHAR16 *String,
- IN CONST BOOLEAN ForceHex,
- IN CONST BOOLEAN StopAtSpace,
- IN CONST BOOLEAN TimeNumbers
- );
-
-/**
- Cleans off all the quotes in the string.
-
- @param[in] OriginalString pointer to the string to be cleaned.
- @param[out] CleanString The new string with all quotes removed.
- Memory allocated in the function and free
- by caller.
-
- @retval EFI_SUCCESS The operation was successful.
-**/
-EFI_STATUS
-InternalShellStripQuotes (
- IN CONST CHAR16 *OriginalString,
- OUT CHAR16 **CleanString
- );
-
-#endif
+/** @file
+ Provides interface to shell functionality for shell commands and applications.
+
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UEFI_SHELL_LIB_INTERNAL_H_
+#define _UEFI_SHELL_LIB_INTERNAL_H_
+
+#include <Uefi.h>
+
+#include <Guid/FileInfo.h>
+
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/EfiShellInterface.h>
+#include <Protocol/EfiShellEnvironment2.h>
+#include <Protocol/Shell.h>
+#include <Protocol/ShellParameters.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/ShellLib.h>
+
+typedef struct {
+ EFI_SHELL_GET_FILE_INFO GetFileInfo;
+ EFI_SHELL_SET_FILE_INFO SetFileInfo;
+ EFI_SHELL_READ_FILE ReadFile;
+ EFI_SHELL_WRITE_FILE WriteFile;
+ EFI_SHELL_CLOSE_FILE CloseFile;
+ EFI_SHELL_DELETE_FILE DeleteFile;
+ EFI_SHELL_GET_FILE_POSITION GetFilePosition;
+ EFI_SHELL_SET_FILE_POSITION SetFilePosition;
+ EFI_SHELL_FLUSH_FILE FlushFile;
+ EFI_SHELL_GET_FILE_SIZE GetFileSize;
+} FILE_HANDLE_FUNCTION_MAP;
+
+/**
+ Function to determin if an entire string is a valid number.
+
+ If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
+
+ @param[in] String The string to evaluate.
+ @param[in] ForceHex TRUE - always assume hex.
+ @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
+ @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
+
+ @retval TRUE It is all numeric (dec/hex) characters.
+ @retval FALSE There is a non-numeric character.
+**/
+BOOLEAN
+InternalShellIsHexOrDecimalNumber (
+ IN CONST CHAR16 *String,
+ IN CONST BOOLEAN ForceHex,
+ IN CONST BOOLEAN StopAtSpace,
+ IN CONST BOOLEAN TimeNumbers
+ );
+
+/**
+ Cleans off all the quotes in the string.
+
+ @param[in] OriginalString pointer to the string to be cleaned.
+ @param[out] CleanString The new string with all quotes removed.
+ Memory allocated in the function and free
+ by caller.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+InternalShellStripQuotes (
+ IN CONST CHAR16 *OriginalString,
+ OUT CHAR16 **CleanString
+ );
+
+#endif
diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.inf b/ShellPkg/Library/UefiShellLib/UefiShellLib.inf
index 1eeee70a3a..aff2d36d44 100644
--- a/ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.inf
@@ -1,65 +1,65 @@
-## @file
-# Provides interface to shell functionality for shell commands and applications.
-#
-# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
-# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010006
- BASE_NAME = UefiShellLib
- FILE_GUID = 449D0F00-2148-4a43-9836-F10B3980ECF5
- MODULE_TYPE = UEFI_DRIVER
- VERSION_STRING = 1.2
- LIBRARY_CLASS = ShellLib|UEFI_APPLICATION UEFI_DRIVER DXE_RUNTIME_DRIVER DXE_DRIVER
- CONSTRUCTOR = ShellLibConstructor
- DESTRUCTOR = ShellLibDestructor
-
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources.common]
- UefiShellLib.c
- UefiShellLib.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
- ShellPkg/ShellPkg.dec
-
-[LibraryClasses]
- UefiBootServicesTableLib
- MemoryAllocationLib
- DevicePathLib
- BaseLib
- BaseMemoryLib
- DebugLib
- FileHandleLib
- PrintLib
- UefiLib
- HiiLib
- SortLib
-
-[Protocols]
- gEfiUnicodeCollation2ProtocolGuid ## CONSUMES
-
- # shell 2.0
- gEfiShellProtocolGuid ## SOMETIMES_CONSUMES
- gEfiShellParametersProtocolGuid ## SOMETIMES_CONSUMES
-
- # 'old' shell
- gEfiShellEnvironment2Guid ## SOMETIMES_CONSUMES
- gEfiShellInterfaceGuid ## SOMETIMES_CONSUMES
-
-[Guids]
- gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
- gEfiShellEnvironment2ExtGuid ## SOMETIMES_CONSUMES ## GUID
-
-[Pcd.common]
- gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize ## CONSUMES
- gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize ## CONSUMES
+## @file
+# Provides interface to shell functionality for shell commands and applications.
+#
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiShellLib
+ FILE_GUID = 449D0F00-2148-4a43-9836-F10B3980ECF5
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.2
+ LIBRARY_CLASS = ShellLib|UEFI_APPLICATION UEFI_DRIVER DXE_RUNTIME_DRIVER DXE_DRIVER
+ CONSTRUCTOR = ShellLibConstructor
+ DESTRUCTOR = ShellLibDestructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ UefiShellLib.c
+ UefiShellLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ DevicePathLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ FileHandleLib
+ PrintLib
+ UefiLib
+ HiiLib
+ SortLib
+
+[Protocols]
+ gEfiUnicodeCollation2ProtocolGuid ## CONSUMES
+
+ # shell 2.0
+ gEfiShellProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiShellParametersProtocolGuid ## SOMETIMES_CONSUMES
+
+ # 'old' shell
+ gEfiShellEnvironment2Guid ## SOMETIMES_CONSUMES
+ gEfiShellInterfaceGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiShellEnvironment2ExtGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Pcd.common]
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize ## CONSUMES
+ gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize ## CONSUMES