| /** @file | |
| Provides interface to shell functionality for shell commands and applications. | |
| Copyright (c) 2006 - 2009, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <Uefi.h> | |
| #include <Library/ShellLib.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 <Protocol/EfiShellEnvironment2.h> | |
| #include <Protocol/EfiShellInterface.h> | |
| #include <Protocol/EfiShell.h> | |
| #include <Protocol/EfiShellParameters.h> | |
| #include <Protocol/SimpleFileSystem.h> | |
| #include "UefiShellLib.h" | |
| #define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) | |
| #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN) | |
| // | |
| // This is not static since it's extern in the .h file | |
| // | |
| SHELL_PARAM_ITEM EmptyParamList[] = { | |
| {NULL, TypeMax} | |
| }; | |
| // | |
| // Static file globals for the shell library | |
| // | |
| STATIC EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; | |
| STATIC EFI_SHELL_INTERFACE *mEfiShellInterface; | |
| STATIC EFI_SHELL_PROTOCOL *mEfiShellProtocol; | |
| STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol; | |
| STATIC EFI_HANDLE mEfiShellEnvironment2Handle; | |
| STATIC FILE_HANDLE_FUNCTION_MAP FileFunctionMap; | |
| /** | |
| helper function to find ShellEnvironment2 for constructor | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| 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) != FALSE)){ | |
| // | |
| // figure out how big of a buffer we need. | |
| // | |
| Status = gBS->LocateHandle (ByProtocol, | |
| &gEfiShellEnvironment2Guid, | |
| NULL, // ignored for ByProtocol | |
| &BufferSize, | |
| Buffer | |
| ); | |
| ASSERT(Status == EFI_BUFFER_TOO_SMALL); | |
| Buffer = (EFI_HANDLE*)AllocatePool(BufferSize); | |
| ASSERT(Buffer != NULL); | |
| Status = gBS->LocateHandle (ByProtocol, | |
| &gEfiShellEnvironment2Guid, | |
| NULL, // ignored for ByProtocol | |
| &BufferSize, | |
| Buffer | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // 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) != FALSE) { | |
| mEfiShellEnvironment2Handle = Buffer[HandleIndex]; | |
| Status = EFI_SUCCESS; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (Buffer != NULL) { | |
| FreePool (Buffer); | |
| } | |
| return (Status); | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| ShellLibConstructorWorker ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ){ | |
| EFI_STATUS Status; | |
| // | |
| // UEFI 2.0 shell interfaces (used preferentially) | |
| // | |
| Status = gBS->OpenProtocol(ImageHandle, | |
| &gEfiShellProtocolGuid, | |
| (VOID **)&mEfiShellProtocol, | |
| ImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| mEfiShellProtocol = NULL; | |
| } | |
| Status = gBS->OpenProtocol(ImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| (VOID **)&mEfiShellParametersProtocol, | |
| ImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| mEfiShellParametersProtocol = NULL; | |
| } | |
| if (mEfiShellParametersProtocol == NULL || mEfiShellProtocol == 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; | |
| } | |
| } | |
| // | |
| // only success getting 2 of either the old or new, but no 1/2 and 1/2 | |
| // | |
| if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) || | |
| (mEfiShellProtocol != NULL && mEfiShellParametersProtocol != NULL) ) { | |
| if (mEfiShellProtocol != NULL) { | |
| FileFunctionMap.GetFileInfo = mEfiShellProtocol->GetFileInfo; | |
| FileFunctionMap.SetFileInfo = mEfiShellProtocol->SetFileInfo; | |
| FileFunctionMap.ReadFile = mEfiShellProtocol->ReadFile; | |
| FileFunctionMap.WriteFile = mEfiShellProtocol->WriteFile; | |
| FileFunctionMap.CloseFile = mEfiShellProtocol->CloseFile; | |
| FileFunctionMap.DeleteFile = mEfiShellProtocol->DeleteFile; | |
| FileFunctionMap.GetFilePosition = mEfiShellProtocol->GetFilePosition; | |
| FileFunctionMap.SetFilePosition = mEfiShellProtocol->SetFilePosition; | |
| FileFunctionMap.FlushFile = mEfiShellProtocol->FlushFile; | |
| FileFunctionMap.GetFileSize = mEfiShellProtocol->GetFileSize; | |
| } else { | |
| FileFunctionMap.GetFileInfo = FileHandleGetInfo; | |
| FileFunctionMap.SetFileInfo = FileHandleSetInfo; | |
| FileFunctionMap.ReadFile = FileHandleRead; | |
| FileFunctionMap.WriteFile = FileHandleWrite; | |
| FileFunctionMap.CloseFile = FileHandleClose; | |
| FileFunctionMap.DeleteFile = FileHandleDelete; | |
| FileFunctionMap.GetFilePosition = FileHandleGetPosition; | |
| FileFunctionMap.SetFilePosition = FileHandleSetPosition; | |
| FileFunctionMap.FlushFile = FileHandleFlush; | |
| FileFunctionMap.GetFileSize = 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 sucessfully | |
| @return others an error ocurred during initialization | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ShellLibConstructor ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| mEfiShellEnvironment2 = NULL; | |
| mEfiShellProtocol = NULL; | |
| mEfiShellParametersProtocol = NULL; | |
| mEfiShellInterface = NULL; | |
| mEfiShellEnvironment2Handle = NULL; | |
| // | |
| // verify that auto initialize is not set false | |
| // | |
| if (PcdGetBool(PcdShellLibAutoInitialize) == 0) { | |
| return (EFI_SUCCESS); | |
| } | |
| return (ShellLibConstructorWorker(ImageHandle, SystemTable)); | |
| } | |
| /** | |
| Destructory for the library. free any resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ShellLibDestructor ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ){ | |
| if (mEfiShellEnvironment2 != NULL) { | |
| gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle, | |
| &gEfiShellEnvironment2Guid, | |
| ImageHandle, | |
| NULL); | |
| mEfiShellEnvironment2 = NULL; | |
| } | |
| if (mEfiShellInterface != NULL) { | |
| gBS->CloseProtocol(ImageHandle, | |
| &gEfiShellInterfaceGuid, | |
| ImageHandle, | |
| NULL); | |
| mEfiShellInterface = NULL; | |
| } | |
| if (mEfiShellProtocol != NULL) { | |
| gBS->CloseProtocol(ImageHandle, | |
| &gEfiShellProtocolGuid, | |
| ImageHandle, | |
| NULL); | |
| mEfiShellProtocol = NULL; | |
| } | |
| if (mEfiShellParametersProtocol != NULL) { | |
| gBS->CloseProtocol(ImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| ImageHandle, | |
| NULL); | |
| mEfiShellParametersProtocol = NULL; | |
| } | |
| mEfiShellEnvironment2Handle = 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 poitners 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 sucessfully | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ShellInitialize ( | |
| ) { | |
| // | |
| // if auto initialize is not false then skip | |
| // | |
| if (PcdGetBool(PcdShellLibAutoInitialize) != 0) { | |
| return (EFI_SUCCESS); | |
| } | |
| // | |
| // deinit the current stuff | |
| // | |
| ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST)); | |
| // | |
| // 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 EFI_FILE_HANDLE FileHandle | |
| ) | |
| { | |
| return (FileFunctionMap.GetFileInfo(FileHandle)); | |
| } | |
| /** | |
| This function will set the information about the file for the opened handle | |
| specified. | |
| @param FileHandle The file handle of the file for which information | |
| is being set | |
| @param FileInfo The infotmation to set. | |
| @retval EFI_SUCCESS The information was set. | |
| @retval EFI_UNSUPPORTED The InformationType is not known. | |
| @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 EFI_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 DeviceHandle pointer to the system device handle. | |
| @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 EFI_HANDLE *DeviceHandle, | |
| OUT EFI_FILE_HANDLE *FileHandle, | |
| IN UINT64 OpenMode, | |
| IN UINT64 Attributes | |
| ) | |
| { | |
| CHAR16 *FileName; | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; | |
| EFI_FILE_HANDLE LastHandle; | |
| // | |
| // ASERT for FileHandle, FilePath, and DeviceHandle being NULL | |
| // | |
| ASSERT(FilePath != NULL); | |
| ASSERT(FileHandle != NULL); | |
| ASSERT(DeviceHandle != NULL); | |
| // | |
| // which shell interface should we use | |
| // | |
| if (mEfiShellProtocol != NULL) { | |
| // | |
| // use UEFI Shell 2.0 method. | |
| // | |
| FileName = mEfiShellProtocol->GetFilePathFromDevicePath(*FilePath); | |
| if (FileName == NULL) { | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes); | |
| FreePool(FileName); | |
| return (Status); | |
| } | |
| // | |
| // use old shell method. | |
| // | |
| Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, | |
| FilePath, | |
| DeviceHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->OpenProtocol(*DeviceHandle, | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| (VOID**)&EfiSimpleFileSystemProtocol, | |
| gImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle); | |
| if (EFI_ERROR (Status)) { | |
| FileHandle = NULL; | |
| return Status; | |
| } | |
| // | |
| // go down directories one node at a time. | |
| // | |
| while (!IsDevicePathEnd (*FilePath)) { | |
| // | |
| // For file system access each node should be a file path component | |
| // | |
| if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || | |
| DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP | |
| ) { | |
| FileHandle = NULL; | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| // | |
| // Open this file path node | |
| // | |
| LastHandle = *FileHandle; | |
| *FileHandle = NULL; | |
| // | |
| // Try to test opening an existing file | |
| // | |
| Status = LastHandle->Open ( | |
| LastHandle, | |
| FileHandle, | |
| ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
| OpenMode &~EFI_FILE_MODE_CREATE, | |
| 0 | |
| ); | |
| // | |
| // see if the error was that it needs to be created | |
| // | |
| if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { | |
| Status = LastHandle->Open ( | |
| LastHandle, | |
| FileHandle, | |
| ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
| OpenMode, | |
| Attributes | |
| ); | |
| } | |
| // | |
| // Close the last node | |
| // | |
| LastHandle->Close (LastHandle); | |
| if (EFI_ERROR(Status)) { | |
| return (Status); | |
| } | |
| // | |
| // Get the next node | |
| // | |
| *FilePath = NextDevicePathNode (*FilePath); | |
| } | |
| 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 EFI_FILE_HANDLE *FileHandle, | |
| IN UINT64 OpenMode, | |
| IN UINT64 Attributes | |
| ) | |
| { | |
| EFI_HANDLE DeviceHandle; | |
| EFI_DEVICE_PATH_PROTOCOL *FilePath; | |
| EFI_STATUS Status; | |
| EFI_FILE_INFO *FileInfo; | |
| // | |
| // ASSERT if FileName is NULL | |
| // | |
| ASSERT(FileName != NULL); | |
| if (mEfiShellProtocol != NULL) { | |
| // | |
| // Use UEFI Shell 2.0 method | |
| // | |
| Status = mEfiShellProtocol->OpenFileByName(FileName, | |
| FileHandle, | |
| OpenMode); | |
| if (!EFI_ERROR(Status)){ | |
| FileInfo = FileHandleGetInfo(*FileHandle); | |
| ASSERT(FileInfo != NULL); | |
| FileInfo->Attribute = Attributes; | |
| Status = FileHandleSetInfo(*FileHandle, FileInfo); | |
| } | |
| 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 (FileDevicePath != NULL) { | |
| return (ShellOpenFileByDevicePath(&FilePath, | |
| &DeviceHandle, | |
| 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 EFI_FILE_HANDLE *FileHandle | |
| ) | |
| { | |
| // | |
| // this is a pass thru to the open file function with sepcific open mode and attributes | |
| // | |
| 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 EFI_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 EFI_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 sucessfully. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ShellCloseFile ( | |
| IN EFI_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 sucessfully | |
| @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 EFI_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 begining of file | |
| @retval EFI_SUCCESS Operation completed sucessfully. | |
| @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 EFI_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 begining of file. | |
| @retval EFI_SUCCESS the operation completed sucessfully. | |
| @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 EFI_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 EFI_FILE_HANDLE FileHandle | |
| ) | |
| { | |
| return (FileFunctionMap.FlushFile(FileHandle)); | |
| } | |
| /** | |
| Retrieves the first file from a directory | |
| This function opens a directory and gets the first file's info in the | |
| directory. Caller can use ShellFindNextFile() to get other files. When | |
| complete the caller is responsible for calling FreePool() on Buffer. | |
| @param DirHandle The file handle of the directory to search | |
| @param Buffer Pointer to buffer for 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 EFI_FILE_HANDLE DirHandle, | |
| OUT EFI_FILE_INFO **Buffer | |
| ) | |
| { | |
| // | |
| // pass to file handle lib | |
| // | |
| return (FileHandleFindFirstFile(DirHandle, Buffer)); | |
| } | |
| /** | |
| Retrieves the next file in a directory. | |
| To use this function, caller must call the LibFindFirstFile() to get the | |
| first file, and then use this function get other files. This function can be | |
| called for several times to get each file's information in the directory. If | |
| the call of ShellFindNextFile() got the last file in the directory, the next | |
| call of this function has no file to get. *NoFile will be set to TRUE and the | |
| Buffer memory will be automatically freed. | |
| @param DirHandle the file handle of the directory | |
| @param Buffer pointer to buffer for file's information | |
| @param NoFile 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 EFI_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 sucessfully | |
| @retval EFI_DEVICE_ERROR cannot access the file | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ShellGetFileSize ( | |
| IN EFI_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 (mEfiShellProtocol != NULL) { | |
| // | |
| // We are using UEFI Shell 2.0; see if the event has been triggered | |
| // | |
| if (gBS->CheckEvent(mEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) { | |
| return (FALSE); | |
| } | |
| return (TRUE); | |
| } | |
| // | |
| // using EFI Shell; call the function to check | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| return (mEfiShellEnvironment2->GetExecutionBreak()); | |
| } | |
| /** | |
| 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 (mEfiShellProtocol != NULL) { | |
| return (mEfiShellProtocol->GetEnv(EnvKey)); | |
| } | |
| // | |
| // ASSERT that we must have EFI shell | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| // | |
| // using EFI Shell | |
| // | |
| return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey)); | |
| } | |
| /** | |
| 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 sucessfully | |
| @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 (mEfiShellProtocol != NULL) { | |
| return (mEfiShellProtocol->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. | |
| EnvironmentVariables and Status are only supported for UEFI Shell 2.0. | |
| Output is only supported for pre-UEFI Shell 2.0 | |
| @param ImageHandle Parent image that is starting the operation | |
| @param CommandLine pointer to null terminated command line. | |
| @param Output true to display debug output. false to hide it. | |
| @param EnvironmentVariables optional pointer to array of environment variables | |
| in the form "x=y". if NULL current set is used. | |
| @param Status the status of the run command line. | |
| @retval EFI_SUCCESS the operation completed sucessfully. 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 | |
| ) | |
| { | |
| // | |
| // Check for UEFI Shell 2.0 protocols | |
| // | |
| if (mEfiShellProtocol != NULL) { | |
| // | |
| // Call UEFI Shell 2.0 version (not using Output parameter) | |
| // | |
| return (mEfiShellProtocol->Execute(ParentHandle, | |
| CommandLine, | |
| EnvironmentVariables, | |
| Status)); | |
| } | |
| // | |
| // ASSERT that we must have EFI shell | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| // | |
| // Call EFI Shell version (not using EnvironmentVariables or Status parameters) | |
| // Due to oddity in the EFI shell we want to dereference the ParentHandle here | |
| // | |
| return (mEfiShellEnvironment2->Execute(*ParentHandle, | |
| CommandLine, | |
| Output)); | |
| } | |
| /** | |
| 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. | |
| @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 *DeviceName OPTIONAL | |
| ) | |
| { | |
| // | |
| // Check for UEFI Shell 2.0 protocols | |
| // | |
| if (mEfiShellProtocol != NULL) { | |
| return (mEfiShellProtocol->GetCurDir(DeviceName)); | |
| } | |
| // | |
| // ASSERT that we must have EFI shell | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| return (mEfiShellEnvironment2->CurDir(DeviceName)); | |
| } | |
| /** | |
| 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 (mEfiShellProtocol != NULL) { | |
| // | |
| // Enable with UEFI 2.0 Shell | |
| // | |
| mEfiShellProtocol->EnablePageBreak(); | |
| return; | |
| } else { | |
| // | |
| // ASSERT that must have EFI Shell | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| // | |
| // Enable with EFI Shell | |
| // | |
| mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF); | |
| return; | |
| } | |
| } else { | |
| // | |
| // check for UEFI Shell 2.0 | |
| // | |
| if (mEfiShellProtocol != NULL) { | |
| // | |
| // Disable with UEFI 2.0 Shell | |
| // | |
| mEfiShellProtocol->DisablePageBreak(); | |
| return; | |
| } else { | |
| // | |
| // ASSERT that must have EFI Shell | |
| // | |
| ASSERT(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; | |
| EFI_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* | |
| EFIAPI | |
| 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); | |
| // | |
| // make sure the old list was valid | |
| // | |
| ASSERT(OldInfo != NULL); | |
| 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)); | |
| // | |
| // 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 = AllocateZeroPool(StrSize(OldInfo->FullName)); | |
| NewInfo->FileName = AllocateZeroPool(StrSize(OldInfo->FileName)); | |
| NewInfo->Info = AllocateZeroPool((UINTN)OldInfo->Info->Size); | |
| // | |
| // make sure all the memory allocations were sucessful | |
| // | |
| ASSERT(NewInfo->FullName != NULL); | |
| ASSERT(NewInfo->FileName != NULL); | |
| ASSERT(NewInfo->Info != NULL); | |
| // | |
| // Copt the strings and structure | |
| // | |
| StrCpy(NewInfo->FullName, OldInfo->FullName); | |
| StrCpy(NewInfo->FileName, OldInfo->FileName); | |
| gBS->CopyMem (NewInfo->Info, OldInfo->Info, (UINTN)OldInfo->Info->Size); | |
| // | |
| // 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_ARG structure to record the file information. These | |
| structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG | |
| 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 sucessful and the list head | |
| contains the list of opened files | |
| #retval EFI_UNSUPPORTED a previous ShellOpenFileMetaArg must be closed first. | |
| *ListHead is set to NULL. | |
| @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; | |
| // | |
| // ASSERT that Arg and ListHead are not NULL | |
| // | |
| ASSERT(Arg != NULL); | |
| ASSERT(ListHead != NULL); | |
| // | |
| // Check for UEFI Shell 2.0 protocols | |
| // | |
| if (mEfiShellProtocol != NULL) { | |
| if (*ListHead == NULL) { | |
| *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); | |
| if (*ListHead == NULL) { | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| InitializeListHead(&((*ListHead)->Link)); | |
| } | |
| return (mEfiShellProtocol->OpenFileList(Arg, | |
| OpenMode, | |
| ListHead)); | |
| } | |
| // | |
| // ASSERT that we must have EFI shell | |
| // | |
| ASSERT(mEfiShellEnvironment2 != NULL); | |
| // | |
| // make sure the list head is initialized | |
| // | |
| InitializeListHead(&mOldStyleFileList); | |
| // | |
| // Get the EFI Shell list of files | |
| // | |
| Status = mEfiShellEnvironment2->FileMetaArg(Arg, &mOldStyleFileList); | |
| if (EFI_ERROR(Status)) { | |
| *ListHead = NULL; | |
| return (Status); | |
| } | |
| if (*ListHead == NULL) { | |
| *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); | |
| if (*ListHead == NULL) { | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| } | |
| // | |
| // 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); | |
| return (Status); | |
| } | |
| /** | |
| 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 sucessful | |
| **/ | |
| 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 (mEfiShellProtocol != NULL) { | |
| return (mEfiShellProtocol->FreeFileList(ListHead)); | |
| } else { | |
| // | |
| // Since this is EFI Shell version we need to free our internally made copy | |
| // of the list | |
| // | |
| for ( Node = GetFirstNode(&(*ListHead)->Link) | |
| ; IsListEmpty(&(*ListHead)->Link) == FALSE | |
| ; Node = GetFirstNode(&(*ListHead)->Link)) { | |
| RemoveEntryList(Node); | |
| ((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); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| typedef struct { | |
| LIST_ENTRY Link; | |
| CHAR16 *Name; | |
| ParamType 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 Type pointer to type of parameter if it was found | |
| @param Name pointer to Name of parameter found | |
| @param CheckList List to check against | |
| @retval TRUE the Parameter was found. Type is valid. | |
| @retval FALSE the Parameter was not found. Type is not valid. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| InternalIsOnCheckList ( | |
| IN CONST CHAR16 *Name, | |
| IN CONST SHELL_PARAM_ITEM *CheckList, | |
| OUT ParamType *Type | |
| ) | |
| { | |
| SHELL_PARAM_ITEM *TempListItem; | |
| // | |
| // 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) | |
| ) { | |
| 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 && StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) { | |
| *Type = TempListItem->Type; | |
| return (TRUE); | |
| } else if (StrCmp(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 Name pointer to Name of parameter found | |
| @retval TRUE the Parameter is a flag. | |
| @retval FALSE the Parameter not a flag | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| InternalIsFlag ( | |
| IN CONST CHAR16 *Name | |
| ) | |
| { | |
| // | |
| // ASSERT that Name isn't NULL | |
| // | |
| ASSERT(Name != NULL); | |
| // | |
| // 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 CheckList pointer to list of parameters to check | |
| @param CheckPackage pointer to pointer to list checked values | |
| @param 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 AutoPageBreak will automatically set PageBreakEnabled for "b" parameter | |
| @param Argc Count of parameters in Argv | |
| @param Argv pointer to array of parameters | |
| @retval EFI_SUCCESS The operation completed sucessfully. | |
| @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 | |
| EFIAPI | |
| 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 | |
| ) | |
| { | |
| UINTN LoopCounter; | |
| UINTN Count; | |
| ParamType CurrentItemType; | |
| SHELL_PARAM_PACKAGE *CurrentItemPackage; | |
| BOOLEAN GetItemValue; | |
| CurrentItemPackage = NULL; | |
| // | |
| // ASSERTs | |
| // | |
| ASSERT(CheckList != NULL); | |
| ASSERT(Argv != NULL); | |
| Count = 0; | |
| GetItemValue = FALSE; | |
| // | |
| // If there is only 1 item we dont need to do anything | |
| // | |
| if (Argc <= 1) { | |
| *CheckPackage = NULL; | |
| return (EFI_SUCCESS); | |
| } | |
| // | |
| // initialize the linked list | |
| // | |
| *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY)); | |
| 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) == TRUE) { | |
| // | |
| // this is a flag | |
| // | |
| CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE)); | |
| ASSERT(CurrentItemPackage != NULL); | |
| CurrentItemPackage->Name = AllocatePool(StrSize(Argv[LoopCounter])); | |
| ASSERT(CurrentItemPackage->Name != NULL); | |
| StrCpy(CurrentItemPackage->Name, Argv[LoopCounter]); | |
| CurrentItemPackage->Type = CurrentItemType; | |
| CurrentItemPackage->OriginalPosition = (UINTN)(-1); | |
| CurrentItemPackage->Value = NULL; | |
| // | |
| // Does this flag require a value | |
| // | |
| if (CurrentItemPackage->Type == TypeValue) { | |
| // | |
| // trigger the next loop to populate the value of this item | |
| // | |
| GetItemValue = TRUE; | |
| } else { | |
| // | |
| // this item has no value expected; we are done | |
| // | |
| InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); | |
| } | |
| } else if (GetItemValue == TRUE && InternalIsFlag(Argv[LoopCounter]) == FALSE) { | |
| ASSERT(CurrentItemPackage != NULL); | |
| // | |
| // get the item VALUE for the previous flag | |
| // | |
| GetItemValue = FALSE; | |
| CurrentItemPackage->Value = AllocateZeroPool(StrSize(Argv[LoopCounter])); | |
| ASSERT(CurrentItemPackage->Value != NULL); | |
| StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]); | |
| InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); | |
| } else if (InternalIsFlag(Argv[LoopCounter]) == FALSE) { | |
| // | |
| // add this one as a non-flag | |
| // | |
| CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE)); | |
| ASSERT(CurrentItemPackage != NULL); | |
| CurrentItemPackage->Name = NULL; | |
| CurrentItemPackage->Type = TypePosition; | |
| CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter])); | |
| ASSERT(CurrentItemPackage->Value != NULL); | |
| StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]); | |
| CurrentItemPackage->OriginalPosition = Count++; | |
| InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); | |
| } else if (ProblemParam) { | |
| // | |
| // this was a non-recognised flag... error! | |
| // | |
| *ProblemParam = AllocatePool(StrSize(Argv[LoopCounter])); | |
| ASSERT(*ProblemParam != NULL); | |
| StrCpy(*ProblemParam, Argv[LoopCounter]); | |
| ShellCommandLineFreeVarList(*CheckPackage); | |
| *CheckPackage = NULL; | |
| return (EFI_VOLUME_CORRUPTED); | |
| } else { | |
| ShellCommandLineFreeVarList(*CheckPackage); | |
| *CheckPackage = NULL; | |
| return (EFI_VOLUME_CORRUPTED); | |
| } | |
| } | |
| // | |
| // 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 CheckList pointer to list of parameters to check | |
| @param CheckPackage pointer to pointer to list checked values | |
| @param ProblemParam optional pointer to pointer to unicode string for | |
| the paramater that caused failure. | |
| @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter | |
| @retval EFI_SUCCESS The operation completed sucessfully. | |
| @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_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 | |
| ShellCommandLineParse ( | |
| IN CONST SHELL_PARAM_ITEM *CheckList, | |
| OUT LIST_ENTRY **CheckPackage, | |
| OUT CHAR16 **ProblemParam OPTIONAL, | |
| IN BOOLEAN AutoPageBreak | |
| ) | |
| { | |
| // | |
| // ASSERT that CheckList and CheckPackage aren't NULL | |
| // | |
| ASSERT(CheckList != NULL); | |
| ASSERT(CheckPackage != NULL); | |
| // | |
| // Check for UEFI Shell 2.0 protocols | |
| // | |
| if (mEfiShellParametersProtocol != NULL) { | |
| return (InternalCommandLineParse(CheckList, | |
| CheckPackage, | |
| ProblemParam, | |
| AutoPageBreak, | |
| (CONST CHAR16**) mEfiShellParametersProtocol->Argv, | |
| mEfiShellParametersProtocol->Argc )); | |
| } | |
| // | |
| // ASSERT That EFI Shell is not required | |
| // | |
| ASSERT (mEfiShellInterface != NULL); | |
| return (InternalCommandLineParse(CheckList, | |
| CheckPackage, | |
| ProblemParam, | |
| AutoPageBreak, | |
| (CONST CHAR16**) mEfiShellInterface->Argv, | |
| mEfiShellInterface->Argc )); | |
| } | |
| /** | |
| 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) | |
| ; Node != 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 *CheckPackage, | |
| IN CHAR16 *KeyString | |
| ) | |
| { | |
| LIST_ENTRY *Node; | |
| // | |
| // ASSERT that both CheckPackage and KeyString aren't NULL | |
| // | |
| ASSERT(KeyString != NULL); | |
| // | |
| // return FALSE for no package | |
| // | |
| if (CheckPackage == 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 | |
| && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0 | |
| ){ | |
| return (TRUE); | |
| } else if (StrCmp(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 CheckPackage The package of parsed command line arguments | |
| @param KeyString the Key of the command line argument to check for | |
| @retval NULL the flag is not on the command line | |
| @return !=NULL pointer to unicode string of the value | |
| **/ | |
| CONST CHAR16* | |
| EFIAPI | |
| ShellCommandLineGetValue ( | |
| IN CONST LIST_ENTRY *CheckPackage, | |
| IN CHAR16 *KeyString | |
| ) | |
| { | |
| 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 Name matches, return the value (name can be NULL) | |
| // | |
| 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 | |
| && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0 | |
| ){ | |
| // | |
| // return the string part after the flag | |
| // | |
| return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString)); | |
| } else if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { | |
| // | |
| // return the value | |
| // | |
| 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 CheckPackage The package of parsed command line arguments | |
| @param Position the position of the value | |
| @retval NULL the flag is not on the command line | |
| @return !=NULL pointer to unicode string of the value | |
| **/ | |
| CONST CHAR16* | |
| EFIAPI | |
| ShellCommandLineGetRawValue ( | |
| IN CONST LIST_ENTRY *CheckPackage, | |
| IN UINT32 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); | |
| } | |
| /** | |
| This is a find and replace function. it will return the NewString as a copy of | |
| SourceString with each instance of FindTarget replaced with ReplaceWith. | |
| If the string would grow bigger than NewSize it will halt and return error. | |
| @param[in] SourceString String with source buffer | |
| @param[in,out] NewString String with resultant buffer | |
| @param[in] NewSize Size in bytes of NewString | |
| @param[in] FindTarget String to look for | |
| @param[in[ ReplaceWith String to replace FindTarget with | |
| @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 sucessfully copied with replacement | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CopyReplace( | |
| IN CHAR16 CONST *SourceString, | |
| IN CHAR16 *NewString, | |
| IN UINTN NewSize, | |
| IN CONST CHAR16 *FindTarget, | |
| IN CONST CHAR16 *ReplaceWith | |
| ){ | |
| UINTN Size; | |
| if ( (SourceString == NULL) | |
| || (NewString == NULL) | |
| || (FindTarget == NULL) | |
| || (ReplaceWith == NULL) | |
| || (StrLen(FindTarget) < 1) | |
| || (StrLen(SourceString) < 1) | |
| ){ | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| NewString = SetMem16(NewString, NewSize, L'\0'); | |
| while (*SourceString != L'\0') { | |
| if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0) { | |
| SourceString += StrLen(FindTarget); | |
| Size = StrSize(NewString); | |
| if ((Size + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) { | |
| return (EFI_BUFFER_TOO_SMALL); | |
| } | |
| StrCat(NewString, ReplaceWith); | |
| } else { | |
| Size = StrSize(NewString); | |
| if (Size + sizeof(CHAR16) > NewSize) { | |
| return (EFI_BUFFER_TOO_SMALL); | |
| } | |
| StrnCat(NewString, SourceString, 1); | |
| SourceString++; | |
| } | |
| } | |
| return (EFI_SUCCESS); | |
| } | |
| /** | |
| 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] Row the row to print at | |
| @param[in] Col the column to print at | |
| @param[in] Format the format string | |
| @return the number of characters printed to the screen | |
| **/ | |
| UINTN | |
| EFIAPI | |
| ShellPrintEx( | |
| IN INT32 Col OPTIONAL, | |
| IN INT32 Row OPTIONAL, | |
| IN CONST CHAR16 *Format, | |
| ... | |
| ){ | |
| VA_LIST Marker; | |
| UINTN BufferSize; | |
| CHAR16 *PostReplaceFormat; | |
| CHAR16 *PostReplaceFormat2; | |
| UINTN Return; | |
| EFI_STATUS Status; | |
| UINTN NormalAttribute; | |
| CHAR16 *ResumeLocation; | |
| CHAR16 *FormatWalker; | |
| VA_START (Marker, Format); | |
| BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16); | |
| PostReplaceFormat = AllocateZeroPool (BufferSize); | |
| ASSERT (PostReplaceFormat != NULL); | |
| PostReplaceFormat2 = AllocateZeroPool (BufferSize); | |
| ASSERT (PostReplaceFormat2 != NULL); | |
| // | |
| // Back and forth each time fixing up 1 of our flags... | |
| // | |
| Status = CopyReplace(Format, PostReplaceFormat, BufferSize, L"%N", L"%%N"); | |
| ASSERT_EFI_ERROR(Status); | |
| Status = CopyReplace(PostReplaceFormat, PostReplaceFormat2, BufferSize, L"%E", L"%%E"); | |
| ASSERT_EFI_ERROR(Status); | |
| Status = CopyReplace(PostReplaceFormat2, PostReplaceFormat, BufferSize, L"%H", L"%%H"); | |
| ASSERT_EFI_ERROR(Status); | |
| Status = CopyReplace(PostReplaceFormat, PostReplaceFormat2, BufferSize, L"%B", L"%%B"); | |
| ASSERT_EFI_ERROR(Status); | |
| Status = CopyReplace(PostReplaceFormat2, PostReplaceFormat, BufferSize, L"%V", L"%%V"); | |
| ASSERT_EFI_ERROR(Status); | |
| // | |
| // Use the last buffer from replacing to print from... | |
| // | |
| Return = UnicodeVSPrint (PostReplaceFormat2, BufferSize, PostReplaceFormat, Marker); | |
| FreePool(PostReplaceFormat); | |
| if (Col != -1 && Row != -1) { | |
| Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row); | |
| ASSERT_EFI_ERROR(Status); | |
| } | |
| NormalAttribute = gST->ConOut->Mode->Attribute; | |
| FormatWalker = PostReplaceFormat2; | |
| while (*FormatWalker != L'\0') { | |
| // | |
| // Find the next attribute change request | |
| // | |
| ResumeLocation = StrStr(FormatWalker, L"%"); | |
| if (ResumeLocation != NULL) { | |
| *ResumeLocation = L'\0'; | |
| } | |
| // | |
| // print the current FormatWalker string | |
| // | |
| Status = gST->ConOut->OutputString(gST->ConOut, FormatWalker); | |
| ASSERT_EFI_ERROR(Status); | |
| // | |
| // update the attribute | |
| // | |
| if (ResumeLocation != NULL) { | |
| switch (*(ResumeLocation+1)) { | |
| case (L'N'): | |
| gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute); | |
| break; | |
| case (L'E'): | |
| gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); | |
| break; | |
| case (L'H'): | |
| gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); | |
| break; | |
| case (L'B'): | |
| gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); | |
| break; | |
| case (L'V'): | |
| gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); | |
| break; | |
| default: | |
| ASSERT(FALSE); | |
| break; | |
| } | |
| } else { | |
| // | |
| // reset to normal now... | |
| // | |
| gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute); | |
| break; | |
| } | |
| // | |
| // update FormatWalker to Resume + 2 (skip the % and the indicator) | |
| // | |
| FormatWalker = ResumeLocation + 2; | |
| } | |
| FreePool(PostReplaceFormat2); | |
| return (Return); | |
| } |