]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLib/UefiShellLib.c
Fix the issue that accessing for unaligned address break IPF
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
index b1128ffc14ed2aef5376d2f3d8b0b4183483d6f6..db46b80f9aa2868a5143509b548ea115b2e9e74e 100644 (file)
@@ -1,37 +1,17 @@
 /** @file\r
   Provides interface to shell functionality for shell commands and applications.\r
 \r
-Copyright (c) 2006 - 2009, 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
+  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 <Library/PrintLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/HiiLib.h>\r
-\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 "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
@@ -54,6 +34,8 @@ STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;
 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
@@ -71,7 +53,7 @@ STATIC UINTN                         mTotalParameterCount;
 **/\r
 BOOLEAN\r
 EFIAPI\r
-ShellInternalIsHexaDecimalDigitCharacter (\r
+ShellIsHexaDecimalDigitCharacter (\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
@@ -160,6 +142,12 @@ ShellLibConstructorWorker (
   ) {\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
@@ -266,6 +254,8 @@ ShellLibConstructor (
   mEfiShellParametersProtocol = NULL;\r
   mEfiShellInterface          = NULL;\r
   mEfiShellEnvironment2Handle = NULL;\r
+  mPostReplaceFormat          = NULL;\r
+  mPostReplaceFormat2         = NULL;\r
 \r
   //\r
   // verify that auto initialize is not set false\r
@@ -315,6 +305,16 @@ ShellLibDestructor (
     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
@@ -1468,9 +1468,9 @@ ShellCloseFileMetaArg (
 /**\r
   Find a file by searching the CWD and then the path.\r
 \r
-  if FileName is NULL then ASSERT.\r
+  If FileName is NULL then ASSERT.\r
 \r
-  if the return value is not NULL then the memory must be caller freed.\r
+  If the return value is not NULL then the memory must be caller freed.\r
 \r
   @param FileName               Filename string.\r
 \r
@@ -1538,6 +1538,65 @@ ShellFindFilePath (
   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
+  UINTN             Size;\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
+  Size =  StrSize(FileName);\r
+  Size += StrSize(FileExtension);\r
+  TestPath = AllocateZeroPool(Size);\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     Link;\r
   CHAR16         *Name;\r
@@ -1628,7 +1687,7 @@ InternalIsFlag (
   //\r
   // If we accept numbers then dont return TRUE. (they will be values)\r
   //\r
-  if (((Name[0] == L'-' || Name[0] == L'+') && ShellInternalIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers == TRUE) {\r
+  if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers != FALSE) {\r
     return (FALSE);\r
   }\r
 \r
@@ -1719,7 +1778,7 @@ InternalCommandLineParse (
       //\r
       // do nothing for NULL argv\r
       //\r
-    } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {\r
+    } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) != FALSE) {\r
       //\r
       // We might have leftover if last parameter didnt have optional value\r
       //\r
@@ -2181,9 +2240,11 @@ ShellCommandLineCheckDuplicate (
 }\r
 \r
 /**\r
-  This is a find and replace function.  it will return the NewString as a copy of \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
@@ -2191,26 +2252,29 @@ ShellCommandLineCheckDuplicate (
   @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
+  @param[in] SkipPreCarrot            If TRUE will skip a FindTarget that has a '^'\r
+                                      immediately before it.\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
+                                      the new string (truncation occurred).\r
+  @retval EFI_SUCCESS                 the string was sucessfully copied with replacement.\r
 **/\r
 \r
 EFI_STATUS\r
 EFIAPI\r
-CopyReplace(\r
+ShellCopySearchAndReplace2(\r
   IN CHAR16 CONST                     *SourceString,\r
   IN CHAR16                           *NewString,\r
   IN UINTN                            NewSize,\r
   IN CONST CHAR16                     *FindTarget,\r
-  IN CONST CHAR16                     *ReplaceWith\r
+  IN CONST CHAR16                     *ReplaceWith,\r
+  IN CONST BOOLEAN                    SkipPreCarrot\r
   ) \r
 {\r
   UINTN Size;\r
@@ -2225,7 +2289,13 @@ CopyReplace(
   }\r
   NewString = SetMem16(NewString, NewSize, CHAR_NULL);\r
   while (*SourceString != CHAR_NULL) {\r
-    if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0) {\r
+    //\r
+    // if we find the FindTarget and either Skip == FALSE or Skip == TRUE and we \r
+    // dont have a carrot do a replace...\r
+    //\r
+    if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0 \r
+      && ((SkipPreCarrot && *(SourceString-1) != L'^') || SkipPreCarrot == FALSE)\r
+      ){\r
       SourceString += StrLen(FindTarget);\r
       Size = StrSize(NewString);\r
       if ((Size + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) {\r
@@ -2244,6 +2314,38 @@ CopyReplace(
   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
@@ -2282,41 +2384,30 @@ InternalShellPrintWorker(
   VA_LIST                 Marker\r
   ) \r
 {\r
-  UINTN             BufferSize;\r
-  CHAR16            *PostReplaceFormat;\r
-  CHAR16            *PostReplaceFormat2;\r
   UINTN             Return;\r
   EFI_STATUS        Status;\r
   UINTN             NormalAttribute;\r
   CHAR16            *ResumeLocation;\r
   CHAR16            *FormatWalker;\r
   \r
-  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);\r
-  PostReplaceFormat = AllocateZeroPool (BufferSize);\r
-  ASSERT (PostReplaceFormat != NULL);\r
-  PostReplaceFormat2 = AllocateZeroPool (BufferSize);\r
-  ASSERT (PostReplaceFormat2 != NULL);\r
-\r
   //\r
   // Back and forth each time fixing up 1 of our flags...\r
   //\r
-  Status = CopyReplace(Format,             PostReplaceFormat,  BufferSize, L"%N", L"%%N");\r
+  Status = ShellLibCopySearchAndReplace(Format,             mPostReplaceFormat,  PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N");\r
   ASSERT_EFI_ERROR(Status);\r
-  Status = CopyReplace(PostReplaceFormat,  PostReplaceFormat2, BufferSize, L"%E", L"%%E");\r
+  Status = ShellLibCopySearchAndReplace(mPostReplaceFormat,  mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E");\r
   ASSERT_EFI_ERROR(Status);\r
-  Status = CopyReplace(PostReplaceFormat2, PostReplaceFormat,  BufferSize, L"%H", L"%%H");\r
+  Status = ShellLibCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat,  PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H");\r
   ASSERT_EFI_ERROR(Status);\r
-  Status = CopyReplace(PostReplaceFormat,  PostReplaceFormat2, BufferSize, L"%B", L"%%B");\r
+  Status = ShellLibCopySearchAndReplace(mPostReplaceFormat,  mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B");\r
   ASSERT_EFI_ERROR(Status);\r
-  Status = CopyReplace(PostReplaceFormat2, PostReplaceFormat,  BufferSize, L"%V", L"%%V");\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 (PostReplaceFormat2, BufferSize, PostReplaceFormat, Marker);\r
-\r
-  FreePool(PostReplaceFormat);\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
@@ -2324,7 +2415,7 @@ InternalShellPrintWorker(
   }\r
 \r
   NormalAttribute = gST->ConOut->Mode->Attribute;\r
-  FormatWalker = PostReplaceFormat2;\r
+  FormatWalker = mPostReplaceFormat2;\r
   while (*FormatWalker != CHAR_NULL) {\r
     //\r
     // Find the next attribute change request\r
@@ -2336,7 +2427,7 @@ InternalShellPrintWorker(
     //\r
     // print the current FormatWalker string\r
     //\r
-    Status = gST->ConOut->OutputString(gST->ConOut, FormatWalker);\r
+    Status = InternalPrintTo(FormatWalker);\r
     ASSERT_EFI_ERROR(Status);\r
     //\r
     // update the attribute\r
@@ -2359,7 +2450,12 @@ InternalShellPrintWorker(
           gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
           break;\r
         default:\r
-          ASSERT(FALSE);\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
@@ -2376,21 +2472,19 @@ InternalShellPrintWorker(
     FormatWalker = ResumeLocation + 2;\r
   }\r
 \r
-  FreePool(PostReplaceFormat2);\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
+  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
+  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
@@ -2419,21 +2513,23 @@ ShellPrintEx(
   ) \r
 {\r
   VA_LIST           Marker;\r
+  EFI_STATUS        Status;\r
   VA_START (Marker, Format);\r
-  return (InternalShellPrintWorker(Col, Row, Format, Marker));\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, print the specified string, \r
-  and return the cursor to the original locaiton.  \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 and the cursor's position will not be moved back to an original location.\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
+  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
@@ -2473,6 +2569,7 @@ ShellPrintHiiEx(
   RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);\r
 \r
   FreePool(HiiFormatString);\r
+  VA_END(Marker);\r
 \r
   return (RetVal);\r
 }\r
@@ -2495,6 +2592,8 @@ ShellIsDirectory(
   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
@@ -2528,6 +2627,8 @@ ShellIsFile(
   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
@@ -2543,6 +2644,39 @@ ShellIsFile(
   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
@@ -2558,7 +2692,7 @@ ShellStrToUintn(
   )\r
 {\r
   CONST CHAR16  *Walker;\r
-  for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker = Walker + 1);\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