/** @file\r
Provides interface to shell functionality for shell commands and applications.\r
\r
-Copyright (c) 2006 - 2009, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
+ Copyright (c) 2006 - 2010, Intel Corporation<BR>\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
-#include <Uefi.h>\r
-#include <Library/ShellLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/FileHandleLib.h>\r
-#include <Protocol/EfiShellEnvironment2.h>\r
-#include <Protocol/EfiShellInterface.h>\r
-#include <Protocol/EfiShell.h>\r
-#include <Protocol/EfiShellParameters.h>\r
-#include <Protocol/SimpleFileSystem.h>\r
-\r
-#include "BaseShellLib.h"\r
+#include "UefiShellLib.h"\r
\r
#define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)\r
#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)\r
STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;\r
STATIC EFI_HANDLE mEfiShellEnvironment2Handle;\r
STATIC FILE_HANDLE_FUNCTION_MAP FileFunctionMap;\r
+STATIC UINTN mTotalParameterCount;\r
+STATIC CHAR16 *mPostReplaceFormat;\r
+STATIC CHAR16 *mPostReplaceFormat2;\r
+\r
+/**\r
+ Check if a Unicode character is a hexadecimal character.\r
+\r
+ This internal function checks if a Unicode character is a \r
+ decimal character. The valid hexadecimal character is \r
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+ @param Char The character to check against.\r
+\r
+ @retval TRUE If the Char is a hexadecmial character.\r
+ @retval FALSE If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ShellLibIsHexaDecimalDigitCharacter (\r
+ IN CHAR16 Char\r
+ ) {\r
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
\r
/**\r
helper function to find ShellEnvironment2 for constructor\r
EFIAPI\r
ShellFindSE2 (\r
IN EFI_HANDLE ImageHandle\r
- )\r
-{\r
+ ) {\r
EFI_STATUS Status;\r
EFI_HANDLE *Buffer;\r
UINTN BufferSize;\r
//\r
// look for the mEfiShellEnvironment2 protocol at a higher level\r
//\r
- if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE &&\r
- (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER ||\r
- (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER)))) {\r
+ if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE)){\r
//\r
// figure out how big of a buffer we need.\r
//\r
&BufferSize,\r
Buffer\r
);\r
- ASSERT(Status == EFI_BUFFER_TOO_SMALL);\r
- Buffer = (EFI_HANDLE*)AllocatePool(BufferSize);\r
- ASSERT(Buffer != NULL);\r
- Status = gBS->LocateHandle (ByProtocol,\r
- &gEfiShellEnvironment2Guid,\r
- NULL, // ignored for ByProtocol\r
- &BufferSize,\r
- Buffer\r
- );\r
+ //\r
+ // maybe it's not there???\r
+ //\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ Buffer = (EFI_HANDLE*)AllocatePool(BufferSize);\r
+ ASSERT(Buffer != NULL);\r
+ Status = gBS->LocateHandle (ByProtocol,\r
+ &gEfiShellEnvironment2Guid,\r
+ NULL, // ignored for ByProtocol\r
+ &BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
if (!EFI_ERROR (Status)) {\r
//\r
// now parse the list of returned handles\r
NULL,\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
);\r
- if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE &&\r
- (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER ||\r
- (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER))) {\r
+ if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE) {\r
mEfiShellEnvironment2Handle = Buffer[HandleIndex];\r
Status = EFI_SUCCESS;\r
break;\r
ShellLibConstructorWorker (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
-){\r
+ ) {\r
EFI_STATUS Status;\r
\r
+ ASSERT(PcdGet16 (PcdShellPrintBufferSize) < PcdGet32 (PcdMaximumUnicodeStringLength));\r
+ mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));\r
+ ASSERT (mPostReplaceFormat != NULL);\r
+ mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));\r
+ ASSERT (mPostReplaceFormat2 != NULL);\r
+\r
+ //\r
+ // Set the parameter count to an invalid number\r
+ //\r
+ mTotalParameterCount = (UINTN)(-1);\r
+\r
//\r
// UEFI 2.0 shell interfaces (used preferentially)\r
//\r
ShellLibConstructor (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
+ ) {\r
\r
\r
mEfiShellEnvironment2 = NULL;\r
mEfiShellParametersProtocol = NULL;\r
mEfiShellInterface = NULL;\r
mEfiShellEnvironment2Handle = NULL;\r
+ mPostReplaceFormat = NULL;\r
+ mPostReplaceFormat2 = NULL;\r
\r
- ///@todo make a worker constructor so initialize function works\r
//\r
// verify that auto initialize is not set false\r
// \r
ShellLibDestructor (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
+ ) {\r
if (mEfiShellEnvironment2 != NULL) {\r
gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,\r
&gEfiShellEnvironment2Guid,\r
mEfiShellParametersProtocol = NULL;\r
}\r
mEfiShellEnvironment2Handle = NULL;\r
+\r
+ if (mPostReplaceFormat != NULL) {\r
+ FreePool(mPostReplaceFormat);\r
+ }\r
+ if (mPostReplaceFormat2 != NULL) {\r
+ FreePool(mPostReplaceFormat2);\r
+ }\r
+ mPostReplaceFormat = NULL;\r
+ mPostReplaceFormat2 = NULL;\r
+\r
return (EFI_SUCCESS);\r
}\r
\r
EFIAPI\r
ShellGetFileInfo (\r
IN EFI_FILE_HANDLE FileHandle\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.GetFileInfo(FileHandle));\r
}\r
\r
ShellSetFileInfo (\r
IN EFI_FILE_HANDLE FileHandle,\r
IN EFI_FILE_INFO *FileInfo\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));\r
} \r
\r
OUT EFI_FILE_HANDLE *FileHandle,\r
IN UINT64 OpenMode,\r
IN UINT64 Attributes\r
- )\r
-{\r
+ ) {\r
CHAR16 *FileName;\r
EFI_STATUS Status;\r
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;\r
}\r
Status = gBS->OpenProtocol(*DeviceHandle,\r
&gEfiSimpleFileSystemProtocolGuid,\r
- (VOID**) &EfiSimpleFileSystemProtocol,\r
+ (VOID**)&EfiSimpleFileSystemProtocol,\r
gImageHandle,\r
NULL,\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
EFI_STATUS\r
EFIAPI\r
ShellOpenFileByName(\r
- IN CHAR16 *FileName,\r
+ IN CONST CHAR16 *FileName,\r
OUT EFI_FILE_HANDLE *FileHandle,\r
IN UINT64 OpenMode,\r
IN UINT64 Attributes\r
- )\r
-{\r
+ ) {\r
EFI_HANDLE DeviceHandle;\r
EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *FileInfo;\r
\r
//\r
// ASSERT if FileName is NULL\r
//\r
// Use UEFI Shell 2.0 method\r
//\r
- return (mEfiShellProtocol->OpenFileByName(FileName,\r
- FileHandle,\r
- OpenMode));\r
-\r
- ///@todo add the attributes\r
+ Status = mEfiShellProtocol->OpenFileByName(FileName,\r
+ FileHandle,\r
+ OpenMode);\r
+ if (!EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){\r
+ FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);\r
+ ASSERT(FileInfo != NULL);\r
+ FileInfo->Attribute = Attributes;\r
+ Status = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);\r
+ FreePool(FileInfo);\r
+ }\r
+ return (Status);\r
} \r
//\r
// Using EFI Shell version\r
// since this will use EFI method again that will open it.\r
//\r
ASSERT(mEfiShellEnvironment2 != NULL);\r
- FilePath = mEfiShellEnvironment2->NameToPath (FileName);\r
+ FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);\r
if (FileDevicePath != NULL) {\r
return (ShellOpenFileByDevicePath(&FilePath,\r
&DeviceHandle,\r
EFI_STATUS\r
EFIAPI\r
ShellCreateDirectory(\r
- IN CHAR16 *DirectoryName,\r
+ IN CONST CHAR16 *DirectoryName,\r
OUT EFI_FILE_HANDLE *FileHandle\r
- )\r
-{\r
- //\r
- // this is a pass thru to the open file function with sepcific open mode and attributes\r
- //\r
- return (ShellOpenFileByName(DirectoryName,\r
- FileHandle,\r
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
- EFI_FILE_DIRECTORY\r
- ));\r
+ ) {\r
+ if (mEfiShellProtocol != NULL) {\r
+ //\r
+ // Use UEFI Shell 2.0 method\r
+ //\r
+ return (mEfiShellProtocol->CreateFile(DirectoryName,\r
+ EFI_FILE_DIRECTORY,\r
+ FileHandle\r
+ ));\r
+ } else {\r
+ return (ShellOpenFileByName(DirectoryName,\r
+ FileHandle,\r
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
+ EFI_FILE_DIRECTORY\r
+ ));\r
+ }\r
}\r
\r
/**\r
IN EFI_FILE_HANDLE FileHandle,\r
IN OUT UINTN *BufferSize,\r
OUT VOID *Buffer\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));\r
}\r
\r
IN EFI_FILE_HANDLE FileHandle,\r
IN OUT UINTN *BufferSize,\r
IN VOID *Buffer\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));\r
}\r
\r
EFIAPI\r
ShellCloseFile (\r
IN EFI_FILE_HANDLE *FileHandle\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.CloseFile(*FileHandle));\r
}\r
\r
EFIAPI\r
ShellDeleteFile (\r
IN EFI_FILE_HANDLE *FileHandle\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.DeleteFile(*FileHandle));\r
}\r
\r
ShellSetFilePosition (\r
IN EFI_FILE_HANDLE FileHandle,\r
IN UINT64 Position\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.SetFilePosition(FileHandle, Position));\r
}\r
\r
ShellGetFilePosition (\r
IN EFI_FILE_HANDLE FileHandle,\r
OUT UINT64 *Position\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.GetFilePosition(FileHandle, Position));\r
}\r
/**\r
EFIAPI\r
ShellFlushFile (\r
IN EFI_FILE_HANDLE FileHandle\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.FlushFile(FileHandle));\r
}\r
\r
ShellFindFirstFile (\r
IN EFI_FILE_HANDLE DirHandle,\r
OUT EFI_FILE_INFO **Buffer\r
- )\r
-{\r
+ ) {\r
//\r
// pass to file handle lib\r
//\r
IN EFI_FILE_HANDLE DirHandle,\r
OUT EFI_FILE_INFO *Buffer,\r
OUT BOOLEAN *NoFile\r
- )\r
-{\r
+ ) {\r
//\r
// pass to file handle lib\r
//\r
ShellGetFileSize (\r
IN EFI_FILE_HANDLE FileHandle,\r
OUT UINT64 *Size\r
- )\r
-{\r
+ ) {\r
return (FileFunctionMap.GetFileSize(FileHandle, Size));\r
}\r
/**\r
CONST CHAR16*\r
EFIAPI\r
ShellGetEnvironmentVariable (\r
- IN CHAR16 *EnvKey\r
+ IN CONST CHAR16 *EnvKey\r
)\r
{\r
// \r
//\r
// using EFI Shell\r
//\r
- return (mEfiShellEnvironment2->GetEnv(EnvKey));\r
+ return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey));\r
}\r
/**\r
set the value of an environment variable\r
EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via\r
the ShellCloseFileMetaArg function.\r
\r
- @param FileList the EFI shell list type\r
+ @param[in] FileList the EFI shell list type\r
+ @param[in,out] ListHead the list to add to\r
\r
@retval the resultant head of the double linked new format list;\r
**/\r
LIST_ENTRY*\r
EFIAPI\r
InternalShellConvertFileListType (\r
- LIST_ENTRY *FileList\r
+ IN LIST_ENTRY *FileList,\r
+ IN OUT LIST_ENTRY *ListHead\r
)\r
{\r
- LIST_ENTRY *ListHead;\r
SHELL_FILE_ARG *OldInfo;\r
- LIST_ENTRY *Link;\r
+ LIST_ENTRY *Link;\r
EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;\r
\r
//\r
- // ASSERT that FileList is not NULL\r
- //\r
- ASSERT(FileList != NULL);\r
-\r
- //\r
- // Allocate our list head and initialize the list\r
+ // ASSERTs\r
//\r
- ListHead = AllocateZeroPool(sizeof(LIST_ENTRY));\r
- ASSERT (ListHead != NULL);\r
- ListHead = InitializeListHead (ListHead);\r
+ ASSERT(FileList != NULL);\r
+ ASSERT(ListHead != NULL);\r
\r
//\r
// enumerate through each member of the old list and copy\r
//\r
// add that to the list\r
//\r
- InsertTailList(ListHead, (LIST_ENTRY*)NewInfo);\r
+ InsertTailList(ListHead, &NewInfo->Link);\r
}\r
return (ListHead);\r
}\r
and will process '?' and '*' as such. the list must be freed with a call to \r
ShellCloseFileMetaArg().\r
\r
- This function will fail if called sequentially without freeing the list in the middle.\r
+ If you are NOT appending to an existing list *ListHead must be NULL. If \r
+ *ListHead is NULL then it must be callee freed.\r
\r
@param Arg pointer to path string\r
@param OpenMode mode to open files with\r
)\r
{\r
EFI_STATUS Status;\r
- LIST_ENTRY *EmptyNode;\r
- LIST_ENTRY *mOldStyleFileList;\r
+ LIST_ENTRY mOldStyleFileList;\r
\r
//\r
// ASSERT that Arg and ListHead are not NULL\r
// Check for UEFI Shell 2.0 protocols\r
//\r
if (mEfiShellProtocol != NULL) {\r
- return (mEfiShellProtocol->OpenFileList(Arg, \r
+ if (*ListHead == NULL) {\r
+ *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+ if (*ListHead == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ InitializeListHead(&((*ListHead)->Link));\r
+ } \r
+ Status = mEfiShellProtocol->OpenFileList(Arg, \r
OpenMode, \r
- ListHead));\r
+ ListHead);\r
+ if (EFI_ERROR(Status)) {\r
+ mEfiShellProtocol->RemoveDupInFileList(ListHead);\r
+ } else {\r
+ Status = mEfiShellProtocol->RemoveDupInFileList(ListHead);\r
+ }\r
+ return (Status);\r
} \r
\r
//\r
//\r
ASSERT(mEfiShellEnvironment2 != NULL);\r
\r
- //\r
- // allocate memory for old list head\r
- //\r
- mOldStyleFileList = (LIST_ENTRY*)AllocatePool(sizeof(LIST_ENTRY));\r
- ASSERT(mOldStyleFileList != NULL);\r
-\r
//\r
// make sure the list head is initialized\r
//\r
- InitializeListHead((LIST_ENTRY*)mOldStyleFileList);\r
+ InitializeListHead(&mOldStyleFileList);\r
\r
//\r
// Get the EFI Shell list of files\r
//\r
- Status = mEfiShellEnvironment2->FileMetaArg(Arg, mOldStyleFileList);\r
+ Status = mEfiShellEnvironment2->FileMetaArg(Arg, &mOldStyleFileList);\r
if (EFI_ERROR(Status)) {\r
*ListHead = NULL;\r
return (Status);\r
}\r
\r
+ if (*ListHead == NULL) {\r
+ *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+ if (*ListHead == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ }\r
+\r
//\r
// Convert that to equivalent of UEFI Shell 2.0 structure\r
//\r
- EmptyNode = InternalShellConvertFileListType(mOldStyleFileList);\r
+ InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link);\r
\r
//\r
// Free the EFI Shell version that was converted.\r
//\r
- ASSERT_EFI_ERROR(mEfiShellEnvironment2->FreeFileList(mOldStyleFileList));\r
- FreePool(mOldStyleFileList);\r
- mOldStyleFileList = NULL;\r
-\r
- //\r
- // remove the empty head of the list\r
- //\r
- *ListHead = (EFI_SHELL_FILE_INFO*)RemoveEntryList(EmptyNode);\r
- FreePool(EmptyNode); \r
+ mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList);\r
\r
return (Status);\r
}\r
// Since this is EFI Shell version we need to free our internally made copy \r
// of the list\r
//\r
- for (Node = GetFirstNode((LIST_ENTRY*)*ListHead) ; IsListEmpty((LIST_ENTRY*)*ListHead) == FALSE ; Node = GetFirstNode((LIST_ENTRY*)*ListHead)) {\r
+ for ( Node = GetFirstNode(&(*ListHead)->Link) \r
+ ; IsListEmpty(&(*ListHead)->Link) == FALSE \r
+ ; Node = GetFirstNode(&(*ListHead)->Link)) {\r
RemoveEntryList(Node);\r
((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);\r
FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);\r
}\r
}\r
\r
+/**\r
+ Find a file by searching the CWD and then the path.\r
+\r
+ If FileName is NULL then ASSERT.\r
+\r
+ If the return value is not NULL then the memory must be caller freed.\r
+\r
+ @param FileName Filename string.\r
+\r
+ @retval NULL the file was not found\r
+ @return !NULL the full path to the file.\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+ShellFindFilePath (\r
+ IN CONST CHAR16 *FileName\r
+ )\r
+{\r
+ CONST CHAR16 *Path;\r
+ EFI_FILE_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ CHAR16 *RetVal;\r
+ CHAR16 *TestPath;\r
+ CONST CHAR16 *Walker;\r
+ UINTN Size;\r
+\r
+ RetVal = NULL;\r
+\r
+ Path = ShellGetEnvironmentVariable(L"cwd");\r
+ if (Path != NULL) {\r
+ Size = StrSize(Path);\r
+ Size += StrSize(FileName);\r
+ TestPath = AllocateZeroPool(Size);\r
+ StrCpy(TestPath, Path);\r
+ StrCat(TestPath, FileName);\r
+ Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (!EFI_ERROR(Status)){\r
+ RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
+ ShellCloseFile(&Handle);\r
+ FreePool(TestPath);\r
+ return (RetVal);\r
+ }\r
+ FreePool(TestPath);\r
+ }\r
+ Path = ShellGetEnvironmentVariable(L"path");\r
+ if (Path != NULL) {\r
+ Size = StrSize(Path);\r
+ Size += StrSize(FileName);\r
+ TestPath = AllocateZeroPool(Size);\r
+ Walker = (CHAR16*)Path; \r
+ do {\r
+ CopyMem(TestPath, Walker, StrSize(Walker));\r
+ if (StrStr(TestPath, L";") != NULL) {\r
+ *(StrStr(TestPath, L";")) = CHAR_NULL;\r
+ }\r
+ StrCat(TestPath, FileName);\r
+ if (StrStr(Walker, L";") != NULL) {\r
+ Walker = StrStr(Walker, L";") + 1;\r
+ } else {\r
+ Walker = NULL;\r
+ }\r
+ Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (!EFI_ERROR(Status)){\r
+ RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
+ ShellCloseFile(&Handle);\r
+ break;\r
+ }\r
+ } while (Walker != NULL && Walker[0] != CHAR_NULL);\r
+ FreePool(TestPath);\r
+ }\r
+ return (RetVal);\r
+}\r
+\r
+/**\r
+ Find a file by searching the CWD and then the path with a variable set of file \r
+ extensions. If the file is not found it will append each extension in the list \r
+ in the order provided and return the first one that is successful.\r
+\r
+ If FileName is NULL, then ASSERT.\r
+ If FileExtension is NULL, then behavior is identical to ShellFindFilePath.\r
+\r
+ If the return value is not NULL then the memory must be caller freed.\r
+\r
+ @param[in] FileName Filename string.\r
+ @param[in] FileExtension Semi-colon delimeted list of possible extensions.\r
+\r
+ @retval NULL The file was not found.\r
+ @retval !NULL The path to the file.\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+ShellFindFilePathEx (\r
+ IN CONST CHAR16 *FileName,\r
+ IN CONST CHAR16 *FileExtension\r
+ )\r
+{\r
+ CHAR16 *TestPath;\r
+ CHAR16 *RetVal;\r
+ CONST CHAR16 *ExtensionWalker;\r
+ ASSERT(FileName != NULL);\r
+ if (FileExtension == NULL) {\r
+ return (ShellFindFilePath(FileName));\r
+ }\r
+ RetVal = ShellFindFilePath(FileName);\r
+ if (RetVal != NULL) {\r
+ return (RetVal);\r
+ }\r
+ TestPath = AllocateZeroPool(StrSize(FileName) + StrSize(FileExtension));\r
+ for (ExtensionWalker = FileExtension ; ; ExtensionWalker = StrStr(ExtensionWalker, L";") + 1 ){\r
+ StrCpy(TestPath, FileName);\r
+ StrCat(TestPath, ExtensionWalker);\r
+ if (StrStr(TestPath, L";") != NULL) {\r
+ *(StrStr(TestPath, L";")) = CHAR_NULL;\r
+ }\r
+ RetVal = ShellFindFilePath(TestPath);\r
+ if (RetVal != NULL) {\r
+ break;\r
+ }\r
+ //\r
+ // Must be after first loop...\r
+ //\r
+ if (StrStr(ExtensionWalker, L";") == NULL) {\r
+ break;\r
+ }\r
+ }\r
+ FreePool(TestPath);\r
+ return (RetVal);\r
+}\r
+\r
typedef struct {\r
- LIST_ENTRY List;\r
+ LIST_ENTRY Link;\r
CHAR16 *Name;\r
ParamType Type;\r
CHAR16 *Value;\r
IN CONST CHAR16 *Name,\r
IN CONST SHELL_PARAM_ITEM *CheckList,\r
OUT ParamType *Type\r
- )\r
-{\r
+ ) {\r
SHELL_PARAM_ITEM *TempListItem;\r
\r
//\r
//\r
for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {\r
//\r
- // If the Name matches set the type and return TRUE\r
+ // If the Type is TypeStart only check the first characters of the passed in param\r
+ // If it matches set the type and return TRUE\r
//\r
- if (StrCmp(Name, TempListItem->Name) == 0) {\r
+ if (TempListItem->Type == TypeStart && StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {\r
+ *Type = TempListItem->Type;\r
+ return (TRUE);\r
+ } else if (StrCmp(Name, TempListItem->Name) == 0) {\r
*Type = TempListItem->Type;\r
return (TRUE);\r
}\r
}\r
+\r
return (FALSE);\r
}\r
/**\r
BOOLEAN\r
EFIAPI\r
InternalIsFlag (\r
- IN CONST CHAR16 *Name\r
+ IN CONST CHAR16 *Name,\r
+ IN BOOLEAN AlwaysAllowNumbers\r
)\r
{\r
//\r
//\r
ASSERT(Name != NULL);\r
\r
+ //\r
+ // If we accept numbers then dont return TRUE. (they will be values)\r
+ //\r
+ if (((Name[0] == L'-' || Name[0] == L'+') && ShellLibIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers != FALSE) {\r
+ return (FALSE);\r
+ }\r
+\r
//\r
// If the Name has a / or - as the first character return TRUE\r
//\r
the invalid command line argument was returned in\r
ProblemParam if provided.\r
**/\r
+STATIC\r
EFI_STATUS\r
EFIAPI\r
InternalCommandLineParse (\r
OUT CHAR16 **ProblemParam OPTIONAL,\r
IN BOOLEAN AutoPageBreak,\r
IN CONST CHAR16 **Argv,\r
- IN UINTN Argc\r
- )\r
-{\r
+ IN UINTN Argc,\r
+ IN BOOLEAN AlwaysAllowNumbers\r
+ ) {\r
UINTN LoopCounter;\r
- UINTN Count;\r
ParamType CurrentItemType;\r
SHELL_PARAM_PACKAGE *CurrentItemPackage;\r
- BOOLEAN GetItemValue;\r
+ UINTN GetItemValue;\r
+ UINTN ValueSize;\r
\r
CurrentItemPackage = NULL;\r
-\r
- //\r
- // ASSERTs\r
- //\r
- ASSERT(CheckList != NULL);\r
- ASSERT(Argv != NULL);\r
-\r
- Count = 0;\r
- GetItemValue = FALSE;\r
+ mTotalParameterCount = 0;\r
+ GetItemValue = 0;\r
+ ValueSize = 0;\r
\r
//\r
// If there is only 1 item we dont need to do anything\r
return (EFI_SUCCESS);\r
}\r
\r
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT(CheckList != NULL);\r
+ ASSERT(Argv != NULL);\r
+\r
//\r
// initialize the linked list\r
//\r
//\r
// do nothing for NULL argv\r
//\r
- } else if (GetItemValue == TRUE) {\r
- ASSERT(CurrentItemPackage != NULL);\r
- //\r
- // get the item VALUE for the previous flag\r
- //\r
- GetItemValue = FALSE;\r
- CurrentItemPackage->Value = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
- ASSERT(CurrentItemPackage->Value != NULL);\r
- StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
- InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);\r
- } else if (InternalIsFlag(Argv[LoopCounter]) == FALSE) {\r
+ } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) != FALSE) {\r
//\r
- // add this one as a non-flag\r
+ // We might have leftover if last parameter didnt have optional value\r
//\r
- CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE));\r
- ASSERT(CurrentItemPackage != NULL);\r
- CurrentItemPackage->Name = NULL;\r
- CurrentItemPackage->Type = TypePosition;\r
- CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter]));\r
- ASSERT(CurrentItemPackage->Value != NULL);\r
- StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
- CurrentItemPackage->OriginalPosition = Count++;\r
- InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);\r
- } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {\r
+ if (GetItemValue != 0) {\r
+ GetItemValue = 0;\r
+ InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+ }\r
//\r
// this is a flag\r
//\r
StrCpy(CurrentItemPackage->Name, Argv[LoopCounter]);\r
CurrentItemPackage->Type = CurrentItemType;\r
CurrentItemPackage->OriginalPosition = (UINTN)(-1);\r
+ CurrentItemPackage->Value = NULL;\r
\r
//\r
// Does this flag require a value\r
//\r
- if (CurrentItemPackage->Type == TypeValue) {\r
+ switch (CurrentItemPackage->Type) {\r
//\r
- // trigger the next loop to populate the value of this item\r
- //\r
- GetItemValue = TRUE; \r
+ // possibly trigger the next loop(s) to populate the value of this item\r
+ // \r
+ case TypeValue:\r
+ GetItemValue = 1; \r
+ ValueSize = 0;\r
+ break;\r
+ case TypeDoubleValue:\r
+ GetItemValue = 2;\r
+ ValueSize = 0;\r
+ break;\r
+ case TypeMaxValue:\r
+ GetItemValue = (UINTN)(-1);\r
+ ValueSize = 0;\r
+ break;\r
+ default:\r
+ //\r
+ // this item has no value expected; we are done\r
+ //\r
+ InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+ ASSERT(GetItemValue == 0);\r
+ break;\r
+ }\r
+ } else if (GetItemValue != 0 && InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) {\r
+ ASSERT(CurrentItemPackage != NULL);\r
+ //\r
+ // get the item VALUE for a previous flag\r
+ //\r
+ CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16), CurrentItemPackage->Value);\r
+ ASSERT(CurrentItemPackage->Value != NULL);\r
+ if (ValueSize == 0) {\r
+ StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
} else {\r
- //\r
- // this item has no value expected; we are done\r
- //\r
- CurrentItemPackage->Value = NULL;\r
- InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);\r
+ StrCat(CurrentItemPackage->Value, L" ");\r
+ StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
}\r
+ ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+ GetItemValue--;\r
+ if (GetItemValue == 0) {\r
+ InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+ }\r
+ } else if (InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) {\r
+ //\r
+ // add this one as a non-flag\r
+ //\r
+ CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE));\r
+ ASSERT(CurrentItemPackage != NULL);\r
+ CurrentItemPackage->Name = NULL;\r
+ CurrentItemPackage->Type = TypePosition;\r
+ CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter]));\r
+ ASSERT(CurrentItemPackage->Value != NULL);\r
+ StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
+ CurrentItemPackage->OriginalPosition = mTotalParameterCount++;\r
+ InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
} else if (ProblemParam) {\r
//\r
// this was a non-recognised flag... error!\r
return (EFI_VOLUME_CORRUPTED);\r
}\r
}\r
+ if (GetItemValue != 0) {\r
+ GetItemValue = 0;\r
+ InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+ }\r
//\r
// support for AutoPageBreak\r
//\r
**/\r
EFI_STATUS\r
EFIAPI\r
-ShellCommandLineParse (\r
+ShellCommandLineParseEx (\r
IN CONST SHELL_PARAM_ITEM *CheckList,\r
OUT LIST_ENTRY **CheckPackage,\r
OUT CHAR16 **ProblemParam OPTIONAL,\r
- IN BOOLEAN AutoPageBreak\r
- )\r
-{\r
+ IN BOOLEAN AutoPageBreak,\r
+ IN BOOLEAN AlwaysAllowNumbers\r
+ ) {\r
// \r
// ASSERT that CheckList and CheckPackage aren't NULL\r
//\r
ProblemParam, \r
AutoPageBreak, \r
(CONST CHAR16**) mEfiShellParametersProtocol->Argv,\r
- mEfiShellParametersProtocol->Argc ));\r
+ mEfiShellParametersProtocol->Argc,\r
+ AlwaysAllowNumbers));\r
}\r
\r
// \r
ProblemParam, \r
AutoPageBreak, \r
(CONST CHAR16**) mEfiShellInterface->Argv,\r
- mEfiShellInterface->Argc ));\r
+ mEfiShellInterface->Argc,\r
+ AlwaysAllowNumbers));\r
}\r
\r
/**\r
EFIAPI\r
ShellCommandLineFreeVarList (\r
IN LIST_ENTRY *CheckPackage\r
- )\r
-{\r
+ ) {\r
LIST_ENTRY *Node;\r
\r
//\r
//\r
// for each node in the list\r
//\r
- for (Node = GetFirstNode(CheckPackage); Node != CheckPackage ; Node = GetFirstNode(CheckPackage)) {\r
+ for ( Node = GetFirstNode(CheckPackage)\r
+ ; IsListEmpty(CheckPackage) == FALSE\r
+ ; Node = GetFirstNode(CheckPackage)\r
+ ){\r
//\r
// Remove it from the list\r
//\r
ShellCommandLineGetFlag (\r
IN CONST LIST_ENTRY *CheckPackage,\r
IN CHAR16 *KeyString\r
- )\r
-{\r
+ ) {\r
LIST_ENTRY *Node;\r
\r
//\r
//\r
// enumerate through the list of parametrs\r
//\r
- for (Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) ) {\r
+ for ( Node = GetFirstNode(CheckPackage) \r
+ ; !IsNull (CheckPackage, Node) \r
+ ; Node = GetNextNode(CheckPackage, Node) \r
+ ){\r
//\r
// If the Name matches, return TRUE (and there may be NULL name)\r
//\r
if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {\r
- if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
+ //\r
+ // If Type is TypeStart then only compare the begining of the strings\r
+ //\r
+ if ( ((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart \r
+ && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0\r
+ ){\r
+ return (TRUE);\r
+ } else if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
return (TRUE);\r
}\r
}\r
ShellCommandLineGetValue (\r
IN CONST LIST_ENTRY *CheckPackage,\r
IN CHAR16 *KeyString\r
- )\r
-{\r
+ ) {\r
LIST_ENTRY *Node;\r
\r
//\r
//\r
// enumerate through the list of parametrs\r
//\r
- for (Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) ) {\r
+ for ( Node = GetFirstNode(CheckPackage) \r
+ ; !IsNull (CheckPackage, Node) \r
+ ; Node = GetNextNode(CheckPackage, Node) \r
+ ){\r
//\r
// If the Name matches, return the value (name can be NULL)\r
//\r
if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {\r
- if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
+ //\r
+ // If Type is TypeStart then only compare the begining of the strings\r
+ //\r
+ if ( ((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart \r
+ && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0\r
+ ){\r
+ //\r
+ // return the string part after the flag\r
+ //\r
+ return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));\r
+ } else if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
+ //\r
+ // return the value\r
+ //\r
return (((SHELL_PARAM_PACKAGE*)Node)->Value);\r
}\r
}\r
ShellCommandLineGetRawValue (\r
IN CONST LIST_ENTRY *CheckPackage,\r
IN UINT32 Position\r
- )\r
-{\r
+ ) {\r
LIST_ENTRY *Node;\r
\r
//\r
//\r
// enumerate through the list of parametrs\r
//\r
- for (Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) ) {\r
+ for ( Node = GetFirstNode(CheckPackage) \r
+ ; !IsNull (CheckPackage, Node) \r
+ ; Node = GetNextNode(CheckPackage, Node) \r
+ ){\r
//\r
// If the position matches, return the value\r
//\r
}\r
}\r
return (NULL);\r
-}
\ No newline at end of file
+}\r
+\r
+/**\r
+ returns the number of command line value parameters that were parsed. \r
+ \r
+ this will not include flags.\r
+\r
+ @retval (UINTN)-1 No parsing has ocurred\r
+ @return other The number of value parameters found\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellCommandLineGetCount(\r
+ VOID\r
+ )\r
+{\r
+ return (mTotalParameterCount);\r
+}\r
+\r
+/**\r
+ Determins if a parameter is duplicated.\r
+\r
+ If Param is not NULL then it will point to a callee allocated string buffer \r
+ with the parameter value if a duplicate is found.\r
+\r
+ If CheckPackage is NULL, then ASSERT.\r
+\r
+ @param[in] CheckPackage The package of parsed command line arguments.\r
+ @param[out] Param Upon finding one, a pointer to the duplicated parameter.\r
+\r
+ @retval EFI_SUCCESS No parameters were duplicated.\r
+ @retval EFI_DEVICE_ERROR A duplicate was found.\r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellCommandLineCheckDuplicate (\r
+ IN CONST LIST_ENTRY *CheckPackage,\r
+ OUT CHAR16 **Param\r
+ )\r
+{\r
+ LIST_ENTRY *Node1;\r
+ LIST_ENTRY *Node2;\r
+ \r
+ ASSERT(CheckPackage != NULL);\r
+\r
+ for ( Node1 = GetFirstNode(CheckPackage) \r
+ ; !IsNull (CheckPackage, Node1) \r
+ ; Node1 = GetNextNode(CheckPackage, Node1) \r
+ ){\r
+ for ( Node2 = GetNextNode(CheckPackage, Node1) \r
+ ; !IsNull (CheckPackage, Node2) \r
+ ; Node2 = GetNextNode(CheckPackage, Node2) \r
+ ){\r
+ if (StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) {\r
+ if (Param != NULL) {\r
+ *Param = NULL;\r
+ *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0);\r
+ }\r
+ return (EFI_DEVICE_ERROR);\r
+ }\r
+ }\r
+ }\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ This is a find and replace function. Upon successful return the NewString is a copy of \r
+ SourceString with each instance of FindTarget replaced with ReplaceWith.\r
+\r
+ If SourceString and NewString overlap the behavior is undefined.\r
+\r
+ If the string would grow bigger than NewSize it will halt and return error.\r
+\r
+ @param[in] SourceString String with source buffer\r
+ @param[in,out] NewString String with resultant buffer\r
+ @param[in] NewSize Size in bytes of NewString\r
+ @param[in] FindTarget String to look for\r
+ @param[in[ ReplaceWith String to replace FindTarget with\r
+\r
+ @retval EFI_INVALID_PARAMETER SourceString was NULL\r
+ @retval EFI_INVALID_PARAMETER NewString was NULL\r
+ @retval EFI_INVALID_PARAMETER FindTarget was NULL\r
+ @retval EFI_INVALID_PARAMETER ReplaceWith was NULL\r
+ @retval EFI_INVALID_PARAMETER FindTarget had length < 1\r
+ @retval EFI_INVALID_PARAMETER SourceString had length < 1\r
+ @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold \r
+ the new string (truncation occurred)\r
+ @retval EFI_SUCCESS the string was sucessfully copied with replacement\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ShellLibCopySearchAndReplace(\r
+ IN CHAR16 CONST *SourceString,\r
+ IN CHAR16 *NewString,\r
+ IN UINTN NewSize,\r
+ IN CONST CHAR16 *FindTarget,\r
+ IN CONST CHAR16 *ReplaceWith\r
+ ) \r
+{\r
+ UINTN Size;\r
+ if ( (SourceString == NULL)\r
+ || (NewString == NULL)\r
+ || (FindTarget == NULL)\r
+ || (ReplaceWith == NULL)\r
+ || (StrLen(FindTarget) < 1)\r
+ || (StrLen(SourceString) < 1)\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ NewString = SetMem16(NewString, NewSize, CHAR_NULL);\r
+ while (*SourceString != CHAR_NULL) {\r
+ if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0) {\r
+ SourceString += StrLen(FindTarget);\r
+ Size = StrSize(NewString);\r
+ if ((Size + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) {\r
+ return (EFI_BUFFER_TOO_SMALL);\r
+ }\r
+ StrCat(NewString, ReplaceWith);\r
+ } else {\r
+ Size = StrSize(NewString);\r
+ if (Size + sizeof(CHAR16) > NewSize) {\r
+ return (EFI_BUFFER_TOO_SMALL);\r
+ }\r
+ StrnCat(NewString, SourceString, 1);\r
+ SourceString++;\r
+ }\r
+ }\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Internal worker function to output a string.\r
+\r
+ This function will output a string to the correct StdOut.\r
+\r
+ @param[in] String The string to print out.\r
+\r
+ @retval EFI_SUCCESS The operation was sucessful.\r
+ @retval !EFI_SUCCESS The operation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalPrintTo (\r
+ IN CONST CHAR16 *String\r
+ )\r
+{\r
+ UINTN Size;\r
+ Size = StrSize(String) - sizeof(CHAR16);\r
+ if (mEfiShellParametersProtocol != NULL) {\r
+ return (mEfiShellParametersProtocol->StdOut->Write(mEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));\r
+ }\r
+ if (mEfiShellInterface != NULL) {\r
+ //\r
+ // Divide in half for old shell. Must be string length not size.\r
+ //\r
+ Size /= 2;\r
+ return ( mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));\r
+ }\r
+ ASSERT(FALSE);\r
+ return (EFI_UNSUPPORTED);\r
+}\r
+\r
+/**\r
+ Print at a specific location on the screen.\r
+\r
+ This function will move the cursor to a given screen location and print the specified string\r
+ \r
+ If -1 is specified for either the Row or Col the current screen location for BOTH \r
+ will be used.\r
+\r
+ if either Row or Col is out of range for the current console, then ASSERT\r
+ if Format is NULL, then ASSERT\r
+\r
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports \r
+ the following additional flags:\r
+ %N - Set output attribute to normal\r
+ %H - Set output attribute to highlight\r
+ %E - Set output attribute to error\r
+ %B - Set output attribute to blue color\r
+ %V - Set output attribute to green color\r
+\r
+ Note: The background color is controlled by the shell command cls.\r
+\r
+ @param[in] Row the row to print at\r
+ @param[in] Col the column to print at\r
+ @param[in] Format the format string\r
+ @param[in] Marker the marker for the variable argument list\r
+\r
+ @return the number of characters printed to the screen\r
+**/\r
+\r
+UINTN\r
+EFIAPI\r
+InternalShellPrintWorker(\r
+ IN INT32 Col OPTIONAL,\r
+ IN INT32 Row OPTIONAL,\r
+ IN CONST CHAR16 *Format,\r
+ VA_LIST Marker\r
+ ) \r
+{\r
+ UINTN Return;\r
+ EFI_STATUS Status;\r
+ UINTN NormalAttribute;\r
+ CHAR16 *ResumeLocation;\r
+ CHAR16 *FormatWalker;\r
+ \r
+ //\r
+ // Back and forth each time fixing up 1 of our flags...\r
+ //\r
+ Status = ShellLibCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N");\r
+ ASSERT_EFI_ERROR(Status);\r
+ Status = ShellLibCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E");\r
+ ASSERT_EFI_ERROR(Status);\r
+ Status = ShellLibCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H");\r
+ ASSERT_EFI_ERROR(Status);\r
+ Status = ShellLibCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B");\r
+ ASSERT_EFI_ERROR(Status);\r
+ Status = ShellLibCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V");\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //\r
+ // Use the last buffer from replacing to print from...\r
+ //\r
+ Return = UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);\r
+\r
+ if (Col != -1 && Row != -1) {\r
+ Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+\r
+ NormalAttribute = gST->ConOut->Mode->Attribute;\r
+ FormatWalker = mPostReplaceFormat2;\r
+ while (*FormatWalker != CHAR_NULL) {\r
+ //\r
+ // Find the next attribute change request\r
+ //\r
+ ResumeLocation = StrStr(FormatWalker, L"%");\r
+ if (ResumeLocation != NULL) {\r
+ *ResumeLocation = CHAR_NULL;\r
+ }\r
+ //\r
+ // print the current FormatWalker string\r
+ //\r
+ Status = InternalPrintTo(FormatWalker);\r
+ ASSERT_EFI_ERROR(Status);\r
+ //\r
+ // update the attribute\r
+ //\r
+ if (ResumeLocation != NULL) {\r
+ switch (*(ResumeLocation+1)) {\r
+ case (L'N'):\r
+ gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute);\r
+ break;\r
+ case (L'E'):\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ break;\r
+ case (L'H'):\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ break;\r
+ case (L'B'):\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ break;\r
+ case (L'V'):\r
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
+ break;\r
+ default:\r
+ //\r
+ // Print a simple '%' symbol\r
+ //\r
+ Status = InternalPrintTo(L"%");\r
+ ASSERT_EFI_ERROR(Status);\r
+ ResumeLocation = ResumeLocation - 1;\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // reset to normal now...\r
+ //\r
+ gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute);\r
+ break;\r
+ }\r
+\r
+ //\r
+ // update FormatWalker to Resume + 2 (skip the % and the indicator)\r
+ //\r
+ FormatWalker = ResumeLocation + 2;\r
+ }\r
+\r
+ return (Return);\r
+}\r
+\r
+/**\r
+ Print at a specific location on the screen.\r
+\r
+ This function will move the cursor to a given screen location and print the specified string.\r
+ \r
+ If -1 is specified for either the Row or Col the current screen location for BOTH \r
+ will be used.\r
+\r
+ If either Row or Col is out of range for the current console, then ASSERT.\r
+ If Format is NULL, then ASSERT.\r
+\r
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports \r
+ the following additional flags:\r
+ %N - Set output attribute to normal\r
+ %H - Set output attribute to highlight\r
+ %E - Set output attribute to error\r
+ %B - Set output attribute to blue color\r
+ %V - Set output attribute to green color\r
+\r
+ Note: The background color is controlled by the shell command cls.\r
+\r
+ @param[in] Row the row to print at\r
+ @param[in] Col the column to print at\r
+ @param[in] Format the format string\r
+\r
+ @return the number of characters printed to the screen\r
+**/\r
+\r
+UINTN\r
+EFIAPI\r
+ShellPrintEx(\r
+ IN INT32 Col OPTIONAL,\r
+ IN INT32 Row OPTIONAL,\r
+ IN CONST CHAR16 *Format,\r
+ ...\r
+ ) \r
+{\r
+ VA_LIST Marker;\r
+ EFI_STATUS Status;\r
+ VA_START (Marker, Format);\r
+ Status = InternalShellPrintWorker(Col, Row, Format, Marker);\r
+ VA_END(Marker);\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Print at a specific location on the screen.\r
+\r
+ This function will move the cursor to a given screen location and print the specified string.\r
+ \r
+ If -1 is specified for either the Row or Col the current screen location for BOTH \r
+ will be used.\r
+\r
+ If either Row or Col is out of range for the current console, then ASSERT.\r
+ If Format is NULL, then ASSERT.\r
+\r
+ In addition to the standard %-based flags as supported by UefiLib Print() this supports \r
+ the following additional flags:\r
+ %N - Set output attribute to normal\r
+ %H - Set output attribute to highlight\r
+ %E - Set output attribute to error\r
+ %B - Set output attribute to blue color\r
+ %V - Set output attribute to green color\r
+\r
+ Note: The background color is controlled by the shell command cls.\r
+\r
+ @param[in] Row the row to print at\r
+ @param[in] Col the column to print at\r
+ @param[in] HiiFormatStringId the format string Id for getting from Hii\r
+ @param[in] HiiFormatHandle the format string Handle for getting from Hii\r
+\r
+ @return the number of characters printed to the screen\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellPrintHiiEx(\r
+ IN INT32 Col OPTIONAL,\r
+ IN INT32 Row OPTIONAL,\r
+ IN CONST EFI_STRING_ID HiiFormatStringId,\r
+ IN CONST EFI_HANDLE HiiFormatHandle,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Marker;\r
+ CHAR16 *HiiFormatString;\r
+ UINTN RetVal;\r
+\r
+ VA_START (Marker, HiiFormatHandle);\r
+ HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);\r
+ ASSERT(HiiFormatString != NULL);\r
+\r
+ RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);\r
+\r
+ FreePool(HiiFormatString);\r
+ VA_END(Marker);\r
+\r
+ return (RetVal);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file or a directory.\r
+\r
+ @param[in] DirName Path to directory to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a directory\r
+ @retval EFI_NOT_FOUND The Path does not represent a directory\r
+ @return other The path failed to open\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsDirectory(\r
+ IN CONST CHAR16 *DirName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE Handle;\r
+\r
+ ASSERT(DirName != NULL);\r
+\r
+ Handle = NULL;\r
+\r
+ Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file.\r
+\r
+ @param[in] Name Path to file to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a file.\r
+ @retval EFI_NOT_FOUND The Path does not represent a file.\r
+ @retval other The path failed to open.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsFile(\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE Handle;\r
+\r
+ ASSERT(Name != NULL);\r
+\r
+ Handle = NULL;\r
+\r
+ Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ ShellCloseFile(&Handle);\r
+ return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+ Function to determine if a given filename represents a file.\r
+\r
+ This will search the CWD and then the Path.\r
+\r
+ If Name is NULL, then ASSERT.\r
+\r
+ @param[in] Name Path to file to test.\r
+\r
+ @retval EFI_SUCCESS The Path represents a file.\r
+ @retval EFI_NOT_FOUND The Path does not represent a file.\r
+ @retval other The path failed to open.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsFileInPath(\r
+ IN CONST CHAR16 *Name\r
+ ) {\r
+ CHAR16 *NewName;\r
+ EFI_STATUS Status;\r
+\r
+ if (!EFI_ERROR(ShellIsFile(Name))) {\r
+ return (TRUE);\r
+ }\r
+\r
+ NewName = ShellFindFilePath(Name);\r
+ if (NewName == NULL) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+ Status = ShellIsFile(NewName);\r
+ FreePool(NewName);\r
+ return (Status);\r
+}\r
+/**\r
+ Function to determine whether a string is decimal or hex representation of a number \r
+ and return the number converted from the string.\r
+\r
+ @param[in] String String representation of a number\r
+\r
+ @retval all the number\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellStrToUintn(\r
+ IN CONST CHAR16 *String\r
+ )\r
+{\r
+ CONST CHAR16 *Walker;\r
+ for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);\r
+ if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){\r
+ return (StrHexToUintn(Walker));\r
+ }\r
+ return (StrDecimalToUintn(Walker));\r
+}\r
+\r
+/**\r
+ Safely append with automatic string resizing given length of Destination and\r
+ desired length of copy from Source.\r
+\r
+ append the first D characters of Source to the end of Destination, where D is\r
+ the lesser of Count and the StrLen() of Source. If appending those D characters\r
+ will fit within Destination (whose Size is given as CurrentSize) and\r
+ still leave room for a null terminator, then those characters are appended,\r
+ starting at the original terminating null of Destination, and a new terminating\r
+ null is appended.\r
+\r
+ If appending D characters onto Destination will result in a overflow of the size\r
+ given in CurrentSize the string will be grown such that the copy can be performed\r
+ and CurrentSize will be updated to the new size.\r
+\r
+ If Source is NULL, there is nothing to append, just return the current buffer in\r
+ Destination.\r
+\r
+ if Destination is NULL, then ASSERT()\r
+ if Destination's current length (including NULL terminator) is already more then\r
+ CurrentSize, then ASSERT()\r
+\r
+ @param[in,out] Destination The String to append onto\r
+ @param[in,out] CurrentSize on call the number of bytes in Destination. On\r
+ return possibly the new size (still in bytes). if NULL\r
+ then allocate whatever is needed.\r
+ @param[in] Source The String to append from\r
+ @param[in] Count Maximum number of characters to append. if 0 then\r
+ all are appended.\r
+\r
+ @return Destination return the resultant string.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+StrnCatGrow (\r
+ IN OUT CHAR16 **Destination,\r
+ IN OUT UINTN *CurrentSize,\r
+ IN CONST CHAR16 *Source,\r
+ IN UINTN Count\r
+ )\r
+{\r
+ UINTN DestinationStartSize;\r
+ UINTN NewSize;\r
+\r
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT(Destination != NULL);\r
+\r
+ //\r
+ // If there's nothing to do then just return Destination\r
+ //\r
+ if (Source == NULL) {\r
+ return (*Destination);\r
+ }\r
+\r
+ //\r
+ // allow for un-initialized pointers, based on size being 0\r
+ //\r
+ if (CurrentSize != NULL && *CurrentSize == 0) {\r
+ *Destination = NULL;\r
+ }\r
+\r
+ //\r
+ // allow for NULL pointers address as Destination\r
+ //\r
+ if (*Destination != NULL) {\r
+ ASSERT(CurrentSize != 0);\r
+ DestinationStartSize = StrSize(*Destination);\r
+ ASSERT(DestinationStartSize <= *CurrentSize);\r
+ } else {\r
+ DestinationStartSize = 0;\r
+// ASSERT(*CurrentSize == 0);\r
+ }\r
+\r
+ //\r
+ // Append all of Source?\r
+ //\r
+ if (Count == 0) {\r
+ Count = StrLen(Source);\r
+ }\r
+\r
+ //\r
+ // Test and grow if required\r
+ //\r
+ if (CurrentSize != NULL) {\r
+ NewSize = *CurrentSize;\r
+ while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {\r
+ NewSize += 2 * Count * sizeof(CHAR16);\r
+ }\r
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+ *CurrentSize = NewSize;\r
+ } else {\r
+ *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));\r
+ }\r
+\r
+ //\r
+ // Now use standard StrnCat on a big enough buffer\r
+ //\r
+ return StrnCat(*Destination, Source, Count);\r
+}\r