]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellManParser.c
ShellPkg/Application: Fix various typos
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellManParser.c
index ce471cffdaf44b13d08c040c7adc1a3f2bcd0b58..d5a85cb8cc3f8b5543445aa63efb88793f2d3d10 100644 (file)
@@ -1,21 +1,95 @@
 /** @file\r
   Provides interface to shell MAN file parser.\r
 \r
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
   Copyright 2015 Dell Inc.\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "Shell.h"\r
 \r
-CHAR16 EFIAPI InternalShellCharToUpper (IN CHAR16  Char);\r
+#define SHELL_MAN_HII_GUID \\r
+{ \\r
+  0xf62ccd0c, 0x2449, 0x453c, { 0x8a, 0xcb, 0x8c, 0xc5, 0x7c, 0xf0, 0x2a, 0x97 } \\r
+}\r
+\r
+EFI_HII_HANDLE  mShellManHiiHandle    = NULL;\r
+EFI_HANDLE      mShellManDriverHandle = NULL;\r
+\r
+\r
+SHELL_MAN_HII_VENDOR_DEVICE_PATH  mShellManHiiDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    SHELL_MAN_HII_GUID\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+/**\r
+  Verifies that the filename has .EFI on the end.\r
+\r
+  allocates a new buffer and copies the name (appending .EFI if necessary).\r
+  Caller to free the buffer.\r
+\r
+  @param[in] NameString            original name string\r
+\r
+  @return                          the new filename with .efi as the extension.\r
+**/\r
+CHAR16 *\r
+GetExecuatableFileName (\r
+  IN CONST CHAR16    *NameString\r
+  )\r
+{\r
+  CHAR16  *Buffer;\r
+  CHAR16  *SuffixStr;\r
+  if (NameString == NULL) {\r
+    return (NULL);\r
+  }\r
+\r
+  //\r
+  // Fix the file name\r
+  //\r
+  if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".efi"), L".efi", StrLen(L".efi"))==0) {\r
+    Buffer = AllocateCopyPool(StrSize(NameString), NameString);\r
+  } else if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".man"), L".man", StrLen(L".man"))==0) {\r
+    Buffer = AllocateCopyPool(StrSize(NameString), NameString);\r
+    if (Buffer != NULL) {\r
+      SuffixStr = Buffer+StrLen(Buffer)-StrLen(L".man");\r
+      StrnCpyS (SuffixStr, StrSize(L".man")/sizeof(CHAR16), L".efi", StrLen(L".efi"));\r
+    }\r
+  } else {\r
+    Buffer = AllocateZeroPool(StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16));\r
+    if (Buffer != NULL) {\r
+      StrnCpyS( Buffer,\r
+                (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16),\r
+                NameString,\r
+                StrLen(NameString)\r
+                );\r
+      StrnCatS( Buffer,\r
+                (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16),\r
+                L".efi",\r
+                StrLen(L".efi")\r
+                );\r
+    }\r
+  }\r
+  return (Buffer);\r
+\r
+}\r
 \r
 /**\r
   Verifies that the filename has .MAN on the end.\r
@@ -29,7 +103,6 @@ CHAR16 EFIAPI InternalShellCharToUpper (IN CHAR16  Char);
   @return the new filename with .man as the extension.\r
 **/\r
 CHAR16 *\r
-EFIAPI\r
 GetManFileName(\r
   IN CONST CHAR16 *ManFileName\r
   )\r
@@ -46,14 +119,14 @@ GetManFileName(
   } else {\r
     Buffer = AllocateZeroPool(StrSize(ManFileName) + 4*sizeof(CHAR16));\r
     if (Buffer != NULL) {\r
-      StrnCpyS( Buffer, \r
-                (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16), \r
-                ManFileName, \r
+      StrnCpyS( Buffer,\r
+                (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16),\r
+                ManFileName,\r
                 StrLen(ManFileName)\r
                 );\r
-      StrnCatS( Buffer, \r
+      StrnCatS( Buffer,\r
                 (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16),\r
-                L".man", \r
+                L".man",\r
                 4\r
                 );\r
     }\r
@@ -76,7 +149,6 @@ GetManFileName(
   @retval EFI_NOT_FOUND         The file was not found.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 SearchPathForFile(\r
   IN CONST CHAR16             *FileName,\r
   OUT SHELL_FILE_HANDLE       *Handle\r
@@ -107,143 +179,12 @@ SearchPathForFile(
 }\r
 \r
 /**\r
-  parses through Buffer (which is MAN file formatted) and returns the\r
-  detailed help for any sub section specified in the comma seperated list of\r
+  Parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
+  detailed help for any sub section specified in the comma separated list of\r
   sections provided.  If the end of the file or a .TH section is found then\r
   return.\r
 \r
-  Upon a sucessful return the caller is responsible to free the memory in *HelpText\r
-\r
-  @param[in] Buffer             Buffer to read from\r
-  @param[in] Sections           name of command's sub sections to find\r
-  @param[in] HelpText           pointer to pointer to string where text goes.\r
-  @param[in] HelpSize           pointer to size of allocated HelpText (may be updated)\r
-\r
-  @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.\r
-  @retval EFI_SUCCESS           the section was found and its description sotred in\r
-                                an alloceted buffer.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ManBufferFindSections(\r
-  IN CONST CHAR16 *Buffer,\r
-  IN CONST CHAR16 *Sections,\r
-  IN CHAR16       **HelpText,\r
-  IN UINTN        *HelpSize\r
-  )\r
-{\r
-  EFI_STATUS          Status;\r
-  CONST CHAR16        *CurrentLocation;\r
-  BOOLEAN             CurrentlyReading;\r
-  CHAR16              *SectionName;\r
-  UINTN               SectionLen;\r
-  BOOLEAN             Found;\r
-  CHAR16              *TempString;\r
-  CHAR16              *TempString2;\r
-\r
-  if ( Buffer     == NULL\r
-    || HelpText   == NULL\r
-    || HelpSize   == NULL\r
-   ){\r
-    return (EFI_INVALID_PARAMETER);\r
-  }\r
-\r
-  Status            = EFI_SUCCESS;\r
-  CurrentlyReading  = FALSE;\r
-  Found             = FALSE;\r
-\r
-  for (CurrentLocation = Buffer,TempString = NULL\r
-    ;  CurrentLocation != NULL && *CurrentLocation != CHAR_NULL\r
-    ;  CurrentLocation=StrStr(CurrentLocation, L"\r\n"),TempString = NULL\r
-   ){\r
-    while(CurrentLocation[0] == L'\r' || CurrentLocation[0] == L'\n') {\r
-      CurrentLocation++;\r
-    }\r
-    if (CurrentLocation[0] == L'#') {\r
-      //\r
-      // Skip comment lines\r
-      //\r
-      continue;\r
-    }\r
-    if (StrnCmp(CurrentLocation, L".TH", 3) == 0) {\r
-      //\r
-      // we hit the end of this commands section so stop.\r
-      //\r
-      break;\r
-    }\r
-    if (StrnCmp(CurrentLocation, L".SH ", 4) == 0) {\r
-      if (Sections == NULL) {\r
-        CurrentlyReading = TRUE;\r
-        continue;\r
-      } else if (CurrentlyReading) {\r
-        CurrentlyReading = FALSE;\r
-      }\r
-      CurrentLocation += 4;\r
-      //\r
-      // is this a section we want to read in?\r
-      //\r
-      if (StrLen(CurrentLocation)!=0) {\r
-        TempString2 = StrStr(CurrentLocation, L" ");\r
-        TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\r"));\r
-        TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));\r
-        ASSERT(TempString == NULL);\r
-        TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);\r
-        if (TempString == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-          break;\r
-        }\r
-        SectionName = TempString;\r
-        SectionLen = StrLen(SectionName);\r
-        SectionName = StrStr(Sections, SectionName);\r
-        if (SectionName == NULL) {\r
-          continue;\r
-        }\r
-        if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') {\r
-          CurrentlyReading = TRUE;\r
-        }\r
-      }\r
-    } else if (CurrentlyReading) {\r
-      Found = TRUE;\r
-      if (StrLen(CurrentLocation)!=0) {\r
-        TempString2 = StrStr(CurrentLocation, L"\r");\r
-        TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));\r
-        ASSERT(TempString == NULL);\r
-        TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);\r
-        if (TempString == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-          break;\r
-        }\r
-        //\r
-        // copy and save the current line.\r
-        //\r
-        ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL));\r
-        StrnCatGrow (HelpText, HelpSize, TempString, 0);\r
-        if (HelpText == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-          break;\r
-        }\r
-        StrnCatGrow (HelpText, HelpSize, L"\r\n", 0);\r
-        if (HelpText == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-          break;\r
-        }\r
-      }\r
-    }\r
-    SHELL_FREE_NON_NULL(TempString);\r
-  }\r
-  if (!Found && !EFI_ERROR(Status)) {\r
-    return (EFI_NOT_FOUND);\r
-  }\r
-  return (Status);\r
-}\r
-\r
-/**\r
-  parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
-  detailed help for any sub section specified in the comma seperated list of\r
-  sections provided.  If the end of the file or a .TH section is found then\r
-  return.\r
-\r
-  Upon a sucessful return the caller is responsible to free the memory in *HelpText\r
+  Upon a successful return the caller is responsible to free the memory in *HelpText\r
 \r
   @param[in] Handle             FileHandle to read from\r
   @param[in] Sections           name of command's sub sections to find\r
@@ -252,11 +193,10 @@ ManBufferFindSections(
   @param[in] Ascii              TRUE if the file is ASCII, FALSE otherwise.\r
 \r
   @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.\r
-  @retval EFI_SUCCESS           the section was found and its description sotred in\r
-                                an alloceted buffer.\r
+  @retval EFI_SUCCESS           the section was found and its description stored in\r
+                                an allocated buffer.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ManFileFindSections(\r
   IN SHELL_FILE_HANDLE  Handle,\r
   IN CONST CHAR16       *Sections,\r
@@ -353,108 +293,14 @@ ManFileFindSections(
   return (Status);\r
 }\r
 \r
-/**\r
-  parses through the MAN file formatted Buffer and returns the\r
-  "Brief Description" for the .TH section as specified by Command.  If the\r
-  command section is not found return EFI_NOT_FOUND.\r
-\r
-  Upon a sucessful return the caller is responsible to free the memory in *BriefDesc\r
-\r
-  @param[in] Handle             Buffer to read from\r
-  @param[in] Command            name of command's section to find\r
-  @param[in] BriefDesc          pointer to pointer to string where description goes.\r
-  @param[in] BriefSize          pointer to size of allocated BriefDesc\r
-\r
-  @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.\r
-  @retval EFI_SUCCESS           the section was found and its description sotred in\r
-                                an alloceted buffer.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ManBufferFindTitleSection(\r
-  IN CHAR16         **Buffer,\r
-  IN CONST CHAR16   *Command,\r
-  IN CHAR16         **BriefDesc,\r
-  IN UINTN          *BriefSize\r
-  )\r
-{\r
-  EFI_STATUS    Status;\r
-  CHAR16        *TitleString;\r
-  CHAR16        *TitleEnd;\r
-  CHAR16        *CurrentLocation;\r
-  UINTN         TitleLength;\r
-  CONST CHAR16  StartString[] = L".TH ";\r
-  CONST CHAR16  EndString[]   = L" 0 ";\r
-\r
-  if ( Buffer     == NULL\r
-    || Command    == NULL\r
-    || (BriefDesc != NULL && BriefSize == NULL)\r
-   ){\r
-    return (EFI_INVALID_PARAMETER);\r
-  }\r
-\r
-  Status    = EFI_SUCCESS;\r
-\r
-  //\r
-  // more characters for StartString and EndString\r
-  //\r
-  TitleLength = StrSize(Command) + (StrLen(StartString) + StrLen(EndString)) * sizeof(CHAR16);\r
-  TitleString = AllocateZeroPool(TitleLength);\r
-  if (TitleString == NULL) {\r
-    return (EFI_OUT_OF_RESOURCES);\r
-  }\r
-  StrCpyS(TitleString, TitleLength/sizeof(CHAR16), StartString);\r
-  StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command);\r
-  StrCatS(TitleString, TitleLength/sizeof(CHAR16), EndString);\r
-\r
-  CurrentLocation = StrStr(*Buffer, TitleString);\r
-  if (CurrentLocation == NULL){\r
-    Status = EFI_NOT_FOUND;\r
-  } else {\r
-    //\r
-    // we found it so copy out the rest of the line into BriefDesc\r
-    // After skipping any spaces or zeroes\r
-    //\r
-    for (CurrentLocation += StrLen(TitleString)\r
-      ;  *CurrentLocation == L' ' || *CurrentLocation == L'0' || *CurrentLocation == L'1' || *CurrentLocation == L'\"'\r
-      ;  CurrentLocation++);\r
-\r
-    TitleEnd = StrStr(CurrentLocation, L"\"");\r
-    if (TitleEnd == NULL) {\r
-      Status = EFI_DEVICE_ERROR;\r
-    } else {\r
-      if (BriefDesc != NULL) {\r
-        *BriefSize = StrSize(TitleEnd);\r
-        *BriefDesc = AllocateZeroPool(*BriefSize);\r
-        if (*BriefDesc == NULL) {\r
-          Status = EFI_OUT_OF_RESOURCES;\r
-        } else {\r
-          StrnCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), CurrentLocation, TitleEnd-CurrentLocation);\r
-        }\r
-      }\r
-\r
-      for (CurrentLocation = TitleEnd\r
-        ;  *CurrentLocation != L'\n'\r
-        ;  CurrentLocation++);\r
-      for (\r
-        ;  *CurrentLocation == L' ' || *CurrentLocation == L'\n' || *CurrentLocation == L'\r'\r
-        ;  CurrentLocation++);\r
-      *Buffer = CurrentLocation;\r
-    }\r
-  }\r
-\r
-  FreePool(TitleString);\r
-  return (Status);\r
-}\r
-\r
 /**\r
   Parses a line from a MAN file to see if it is the Title Header. If it is, then\r
   if the "Brief Description" is desired, allocate a buffer for it and return a\r
-  copy. Upon a sucessful return the caller is responsible to free the memory in\r
+  copy. Upon a successful return the caller is responsible to free the memory in\r
   *BriefDesc\r
 \r
   Uses a simple state machine that allows "unlimited" whitespace before and after the\r
-  ".TH", compares Command and the MAN file commnd name without respect to case, and\r
+  ".TH", compares Command and the MAN file command name without respect to case, and\r
   allows "unlimited" whitespace and '0' and '1' characters before the Short Description.\r
   The PCRE regex describing this functionality is: ^\s*\.TH\s+(\S)\s[\s01]*(.*)$\r
   where group 1 is the Command Name and group 2 is the Short Description.\r
@@ -543,7 +389,7 @@ IsTitleHeader(
           ReturnFound = TRUE;  // This is the desired command's title header line.\r
           State = (BriefDesc == NULL) ? Final : GetBriefDescription;\r
         }\r
-        else if (InternalShellCharToUpper (*Line) != InternalShellCharToUpper (*(Command + CommandIndex++))) {\r
+        else if (CharToUpper (*Line) != CharToUpper (*(Command + CommandIndex++))) {\r
           State = Final;\r
         }\r
         Line++;\r
@@ -564,6 +410,8 @@ IsTitleHeader(
         Line++;\r
       break;\r
 \r
+      default:\r
+       break;\r
     }\r
 \r
   } while (State < Final);\r
@@ -573,11 +421,11 @@ IsTitleHeader(
 }\r
 \r
 /**\r
-  parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
+  Parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
   "Brief Description" for the .TH section as specified by Command.  If the\r
   command section is not found return EFI_NOT_FOUND.\r
 \r
-  Upon a sucessful return the caller is responsible to free the memory in *BriefDesc\r
+  Upon a successful return the caller is responsible to free the memory in *BriefDesc\r
 \r
   @param[in] Handle              FileHandle to read from\r
   @param[in] Command             name of command's section to find as entered on the\r
@@ -593,7 +441,6 @@ IsTitleHeader(
                                 an allocated buffer if requested.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ManFileFindTitleSection(\r
   IN SHELL_FILE_HANDLE  Handle,\r
   IN CONST CHAR16       *Command,\r
@@ -628,7 +475,7 @@ ManFileFindTitleSection(
   // Do not pass any leading path information that may be present to IsTitleHeader().\r
   //\r
   Start = StrLen(Command);\r
-  while (Start\r
+  while ((Start != 0)\r
          && (*(Command + Start - 1) != L'\\')\r
          && (*(Command + Start - 1) != L'/')\r
          && (*(Command + Start - 1) != L':')) {\r
@@ -665,7 +512,7 @@ ManFileFindTitleSection(
   information will be returned. If Sections is NULL, then all help text information\r
   available will be returned.\r
 \r
-  if BriefDesc is NULL, then the breif description will not be savedd seperatly,\r
+  if BriefDesc is NULL, then the breif description will not be saved separately,\r
   but placed first in the main HelpText.\r
 \r
   @param[in] ManFileName        Points to the NULL-terminated UEFI Shell MAN file name.\r
@@ -686,7 +533,6 @@ ManFileFindTitleSection(
   @retval EFI_NOT_FOUND         There is no help text available for Command.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ProcessManFile(\r
   IN CONST CHAR16 *ManFileName,\r
   IN CONST CHAR16 *Command,\r
@@ -697,13 +543,17 @@ ProcessManFile(
 {\r
   CHAR16            *TempString;\r
   SHELL_FILE_HANDLE FileHandle;\r
+  EFI_HANDLE        CmdFileImgHandle;\r
   EFI_STATUS        Status;\r
   UINTN             HelpSize;\r
   UINTN             BriefSize;\r
+  UINTN             StringIdWalker;\r
   BOOLEAN           Ascii;\r
-  CHAR16            *TempString2;\r
-  EFI_DEVICE_PATH_PROTOCOL  *FileDevPath;\r
-  EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
+  CHAR16            *CmdFileName;\r
+  CHAR16            *CmdFilePathName;\r
+  EFI_DEVICE_PATH_PROTOCOL      *FileDevPath;\r
+  EFI_DEVICE_PATH_PROTOCOL      *DevPath;\r
+  EFI_HII_PACKAGE_LIST_HEADER   *PackageListHeader;\r
 \r
   if ( ManFileName == NULL\r
     || Command     == NULL\r
@@ -712,21 +562,38 @@ ProcessManFile(
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
-  HelpSize    = 0;\r
-  BriefSize   = 0;\r
-  TempString  = NULL;\r
-  Ascii       = FALSE;\r
+  HelpSize          = 0;\r
+  BriefSize         = 0;\r
+  StringIdWalker    = 0;\r
+  TempString        = NULL;\r
+  Ascii             = FALSE;\r
+  CmdFileName       = NULL;\r
+  CmdFilePathName   = NULL;\r
+  CmdFileImgHandle  = NULL;\r
+  PackageListHeader = NULL;\r
+  FileDevPath       = NULL;\r
+  DevPath           = NULL;\r
+\r
   //\r
   // See if it's in HII first\r
   //\r
   TempString = ShellCommandGetCommandHelp(Command);\r
   if (TempString != NULL) {\r
-    TempString2 = TempString;\r
-    Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, &BriefSize);\r
+    FileHandle = ConvertEfiFileProtocolToShellHandle (CreateFileInterfaceMem (TRUE), NULL);\r
+    HelpSize = StrLen (TempString) * sizeof (CHAR16);\r
+    ShellWriteFile (FileHandle, &HelpSize, TempString);\r
+    ShellSetFilePosition (FileHandle, 0);\r
+    HelpSize  = 0;\r
+    BriefSize = 0;\r
+    Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii);\r
     if (!EFI_ERROR(Status) && HelpText != NULL){\r
-      Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize);\r
+      Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii);\r
     }\r
+    ShellCloseFile (&FileHandle);\r
   } else {\r
+    //\r
+    // If the image is a external app, check .MAN file first.\r
+    //\r
     FileHandle    = NULL;\r
     TempString  = GetManFileName(ManFileName);\r
     if (TempString == NULL) {\r
@@ -738,8 +605,8 @@ ProcessManFile(
       FileDevPath = FileDevicePath(NULL, TempString);\r
       DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath);\r
       Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
-      FreePool(FileDevPath);\r
-      FreePool(DevPath);\r
+      SHELL_FREE_NON_NULL(FileDevPath);\r
+      SHELL_FREE_NON_NULL(DevPath);\r
     }\r
 \r
     if (!EFI_ERROR(Status)) {\r
@@ -750,13 +617,141 @@ ProcessManFile(
         Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii);\r
       }\r
       ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
-    } else {\r
+      if (!EFI_ERROR(Status)) {\r
+        //\r
+        // Get help text from .MAN file success.\r
+        //\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Load the app image to check  EFI_HII_PACKAGE_LIST_PROTOCOL.\r
+    //\r
+    CmdFileName     = GetExecuatableFileName(TempString);\r
+    if (CmdFileName == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+    //\r
+    // If the file in CWD then use the file name, else use the full\r
+    // path name.\r
+    //\r
+    CmdFilePathName = ShellFindFilePath(CmdFileName);\r
+    if (CmdFilePathName == NULL) {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
+    }\r
+    DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CmdFilePathName);\r
+    Status      = gBS->LoadImage(FALSE, gImageHandle, DevPath, NULL, 0, &CmdFileImgHandle);\r
+    if(EFI_ERROR(Status)) {\r
+      //\r
+      // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created\r
+      // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.\r
+      // If the caller doesn't have the option to defer the execution of an image, we should\r
+      // unload image for the EFI_SECURITY_VIOLATION to avoid the resource leak.\r
+      //\r
+      if (Status == EFI_SECURITY_VIOLATION) {\r
+        gBS->UnloadImage (CmdFileImgHandle);\r
+      }\r
+      *HelpText = NULL;\r
+      goto Done;\r
+    }\r
+    Status = gBS->OpenProtocol(\r
+                    CmdFileImgHandle,\r
+                    &gEfiHiiPackageListProtocolGuid,\r
+                    (VOID**)&PackageListHeader,\r
+                    gImageHandle,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if(EFI_ERROR(Status)) {\r
       *HelpText = NULL;\r
+      goto Done;\r
     }\r
+\r
+    //\r
+    // If get package list on image handle, install it on HiiDatabase.\r
+    //\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &mShellManDriverHandle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &mShellManHiiDevicePath\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Status = gHiiDatabase->NewPackageList (\r
+                            gHiiDatabase,\r
+                            PackageListHeader,\r
+                            mShellManDriverHandle,\r
+                            &mShellManHiiHandle\r
+                            );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    StringIdWalker = 1;\r
+    do {\r
+        SHELL_FREE_NON_NULL(TempString);\r
+        if (BriefDesc != NULL) {\r
+          SHELL_FREE_NON_NULL(*BriefDesc);\r
+        }\r
+        TempString = HiiGetString (mShellManHiiHandle, (EFI_STRING_ID)StringIdWalker, NULL);\r
+        if (TempString == NULL) {\r
+          Status = EFI_NOT_FOUND;\r
+          goto Done;\r
+        }\r
+        FileHandle = ConvertEfiFileProtocolToShellHandle (CreateFileInterfaceMem (TRUE), NULL);\r
+        HelpSize = StrLen (TempString) * sizeof (CHAR16);\r
+        ShellWriteFile (FileHandle, &HelpSize, TempString);\r
+        ShellSetFilePosition (FileHandle, 0);\r
+        HelpSize  = 0;\r
+        BriefSize = 0;\r
+        Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii);\r
+        if (!EFI_ERROR(Status) && HelpText != NULL){\r
+          Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii);\r
+        }\r
+        ShellCloseFile (&FileHandle);\r
+        if (!EFI_ERROR(Status)){\r
+          //\r
+          // Found what we need and return\r
+          //\r
+          goto Done;\r
+        }\r
+\r
+        StringIdWalker += 1;\r
+    } while (StringIdWalker < 0xFFFF && TempString != NULL);\r
+\r
   }\r
-  if (TempString != NULL) {\r
-    FreePool(TempString);\r
+\r
+Done:\r
+  if (mShellManDriverHandle != NULL) {\r
+    gBS->UninstallProtocolInterface (\r
+            mShellManDriverHandle,\r
+            &gEfiDevicePathProtocolGuid,\r
+            &mShellManHiiDevicePath\r
+           );\r
+    mShellManDriverHandle = NULL;\r
   }\r
 \r
+  if (mShellManHiiHandle != NULL) {\r
+    HiiRemovePackages (mShellManHiiHandle);\r
+    mShellManHiiHandle = NULL;\r
+  }\r
+\r
+  if (CmdFileImgHandle != NULL) {\r
+    Status = gBS->UnloadImage (CmdFileImgHandle);\r
+  }\r
+\r
+  SHELL_FREE_NON_NULL(TempString);\r
+  SHELL_FREE_NON_NULL(CmdFileName);\r
+  SHELL_FREE_NON_NULL(CmdFilePathName);\r
+  SHELL_FREE_NON_NULL(FileDevPath);\r
+  SHELL_FREE_NON_NULL(DevPath);\r
+\r
   return (Status);\r
 }\r
+\r