UEFI Shell scandalizes the help message in spec level so that a standalone
UEFI shell application can never get "-?" switch, instead the Shell core
(interpreter) detects the "-?" and finds .MAN file for that shell
application in certain spec defined paths, then show the help extracted
from that .MAN file.

But it means distributing a UEFI shell application not only means
distributing a .EFI file but also distributing a .MAN file. If the text
formatted .MAN file is corrupted (edited by user by mistake), or is
missing (deleted by user by mistake), no help will be shown to user.

So this patch enhance the Shell to make it support finding help message
imbedded in resource section of application image.

Difference with previous version:
1. Use HiiLib HiiGetString() API to get string value instead of parse HII 
string package

Cc: Jaben Carsey <[email protected]>
Cc: Ruiyu Ni <[email protected]>
Cc: Liming Gao <[email protected]>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Qiu Shumin <[email protected]>
Reviewed-by: Liming Gao <[email protected]>
Reviewed-by: Ruiyu Ni <[email protected]>
---
 ShellPkg/Application/Shell/Shell.h          |  15 +-
 ShellPkg/Application/Shell/Shell.inf        |   5 +-
 ShellPkg/Application/Shell/ShellManParser.c | 252 ++++++++++++++++++++++++++--
 ShellPkg/Include/Guid/ShellManHiiGuid.h     |  25 +++
 ShellPkg/ShellPkg.dec                       |   3 +-
 5 files changed, 282 insertions(+), 18 deletions(-)
 create mode 100644 ShellPkg/Include/Guid/ShellManHiiGuid.h

diff --git a/ShellPkg/Application/Shell/Shell.h 
b/ShellPkg/Application/Shell/Shell.h
index 351b941..57d3f32 100644
--- a/ShellPkg/Application/Shell/Shell.h
+++ b/ShellPkg/Application/Shell/Shell.h
@@ -2,7 +2,7 @@
   function definitions for internal to shell functions.
 
   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -21,6 +21,7 @@
 
 #include <Guid/ShellVariableGuid.h>
 #include <Guid/ShellAliasGuid.h>
+#include <Guid/ShellManHiiGuid.h>
 
 #include <Protocol/LoadedImage.h>
 #include <Protocol/SimpleTextOut.h>
@@ -29,6 +30,7 @@
 #include <Protocol/EfiShellEnvironment2.h>
 #include <Protocol/EfiShellParameters.h>
 #include <Protocol/BlockIo.h>
+#include <Protocol/HiiPackageList.h>
 
 #include <Library/BaseLib.h>
 #include <Library/UefiApplicationEntryPoint.h>
@@ -47,6 +49,7 @@
 #include <Library/PrintLib.h>
 #include <Library/HandleParsingLib.h>
 #include <Library/FileHandleLib.h>
+#include <Library/UefiHiiServicesLib.h>
 
 #include "ShellParametersProtocol.h"
 #include "ShellProtocol.h"
@@ -122,6 +125,16 @@ typedef struct {
   BOOLEAN                       HaltOutput;           ///< TRUE to start a 
CTRL-S halt.
 } SHELL_INFO;
 
+#pragma pack(1)
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+  VENDOR_DEVICE_PATH             VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL       End;
+} SHELL_MAN_HII_VENDOR_DEVICE_PATH;
+#pragma pack()
+
 extern SHELL_INFO ShellInfoObject;
 
 /**
diff --git a/ShellPkg/Application/Shell/Shell.inf 
b/ShellPkg/Application/Shell/Shell.inf
index 253bfdb..7d866ea 100644
--- a/ShellPkg/Application/Shell/Shell.inf
+++ b/ShellPkg/Application/Shell/Shell.inf
@@ -2,7 +2,7 @@
 #  This is the shell application
 #
 #  (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
-#  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
 #
 #  This program and the accompanying materials
 #  are licensed and made available under the terms and conditions of the BSD 
License
@@ -70,11 +70,13 @@
   HiiLib
   SortLib
   HandleParsingLib
+  UefiHiiServicesLib
 
 [Guids]
   gShellVariableGuid                                      ## CONSUMES ## GUID
   gShellMapGuid                                           ## CONSUMES ## GUID
   gShellAliasGuid                                         ## CONSUMES ## GUID
+  gShellManHiiGuid                                        ## 
SOMETIMES_PRODUCES ## GUID
 
 [Protocols]
   gEfiShellProtocolGuid                                   ## PRODUCES
@@ -93,6 +95,7 @@
   gEfiComponentName2ProtocolGuid                          ## CONSUMES
   gEfiUnicodeCollation2ProtocolGuid                       ## CONSUMES
   gEfiDevicePathProtocolGuid                              ## CONSUMES
+  gEfiHiiPackageListProtocolGuid                          ## SOMETIMES_PRODUCES
 
 [Pcd]
   gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel           ## CONSUMES
diff --git a/ShellPkg/Application/Shell/ShellManParser.c 
b/ShellPkg/Application/Shell/ShellManParser.c
index 222cdaf..8c0c6c8 100644
--- a/ShellPkg/Application/Shell/ShellManParser.c
+++ b/ShellPkg/Application/Shell/ShellManParser.c
@@ -1,7 +1,7 @@
 /** @file
   Provides interface to shell MAN file parser.
 
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
   Copyright 2015 Dell Inc.
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -15,6 +15,32 @@
 
 #include "Shell.h"
 
+EFI_HII_HANDLE  mShellManHiiHandle    = NULL;
+EFI_HANDLE      mShellManDriverHandle = NULL;
+
+SHELL_MAN_HII_VENDOR_DEVICE_PATH  mShellManHiiDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+      }
+    },
+    SHELL_MAN_HII_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH),
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+    }
+  }
+};
+
+
 /**
   Convert a Unicode character to upper case only if
   it maps to a valid small-case ASCII character.
@@ -37,6 +63,58 @@ InternalShellCharToUpper (
   );
 
 /**
+  Verifies that the filename has .EFI on the end.
+
+  allocates a new buffer and copies the name (appending .EFI if necessary).
+  Caller to free the buffer.
+
+  @param[in] NameString            original name string
+
+  @return                          the new filename with .efi as the extension.
+**/
+CHAR16 *
+EFIAPI
+GetExecuatableFileName (
+  IN CONST CHAR16    *NameString
+  )
+{
+  CHAR16  *Buffer;
+  CHAR16  *SuffixStr;
+  if (NameString == NULL) {
+    return (NULL);
+  }
+
+  //
+  // Fix the file name
+  //
+  if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".efi"), L".efi", 
StrLen(L".efi"))==0) {
+    Buffer = AllocateCopyPool(StrSize(NameString), NameString);
+  } else if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".man"), L".man", 
StrLen(L".man"))==0) {
+    Buffer = AllocateCopyPool(StrSize(NameString), NameString);
+    if (Buffer != NULL) {
+      SuffixStr = Buffer+StrLen(Buffer)-StrLen(L".man");
+      StrnCpyS (SuffixStr, StrSize(L".man")/sizeof(CHAR16), L".efi", 
StrLen(L".efi"));
+    }
+  } else {
+    Buffer = AllocateZeroPool(StrSize(NameString) + 
StrLen(L".efi")*sizeof(CHAR16));
+    if (Buffer != NULL) {
+      StrnCpyS( Buffer,
+                (StrSize(NameString) + 
StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16),
+                NameString,
+                StrLen(NameString)
+                );
+      StrnCatS( Buffer,
+                (StrSize(NameString) + 
StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16),
+                L".efi",
+                StrLen(L".efi")
+                );
+    }
+  }
+  return (Buffer);
+
+}
+
+/**
   Verifies that the filename has .MAN on the end.
 
   allocates a new buffer and copies the name (appending .MAN if necessary)
@@ -381,7 +459,7 @@ ManFileFindSections(
 
   Upon a sucessful return the caller is responsible to free the memory in 
*BriefDesc
 
-  @param[in] Handle             Buffer to read from
+  @param[in] Buffer             Buffer to read from
   @param[in] Command            name of command's section to find
   @param[in] BriefDesc          pointer to pointer to string where description 
goes.
   @param[in] BriefSize          pointer to size of allocated BriefDesc
@@ -404,6 +482,7 @@ ManBufferFindTitleSection(
   CHAR16        *TitleEnd;
   CHAR16        *CurrentLocation;
   UINTN         TitleLength;
+  UINTN         Start;
   CONST CHAR16  StartString[] = L".TH ";
   CONST CHAR16  EndString[]   = L" 0 ";
 
@@ -417,15 +496,26 @@ ManBufferFindTitleSection(
   Status    = EFI_SUCCESS;
 
   //
+  // Do not pass any leading path information that may be present to 
IsTitleHeader().
+  //
+  Start = StrLen(Command);
+  while ((Start != 0)
+         && (*(Command + Start - 1) != L'\\')
+         && (*(Command + Start - 1) != L'/')
+         && (*(Command + Start - 1) != L':')) {
+    --Start;
+  }
+
+  //
   // more characters for StartString and EndString
   //
-  TitleLength = StrSize(Command) + (StrLen(StartString) + StrLen(EndString)) * 
sizeof(CHAR16);
+  TitleLength = StrSize(Command + Start) + (StrLen(StartString) + 
StrLen(EndString)) * sizeof(CHAR16);
   TitleString = AllocateZeroPool(TitleLength);
   if (TitleString == NULL) {
     return (EFI_OUT_OF_RESOURCES);
   }
   StrCpyS(TitleString, TitleLength/sizeof(CHAR16), StartString);
-  StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command);
+  StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command + Start);
   StrCatS(TitleString, TitleLength/sizeof(CHAR16), EndString);
 
   CurrentLocation = StrStr(*Buffer, TitleString);
@@ -720,13 +810,19 @@ ProcessManFile(
 {
   CHAR16            *TempString;
   SHELL_FILE_HANDLE FileHandle;
+  EFI_HANDLE        CmdFileImgHandle;
   EFI_STATUS        Status;
   UINTN             HelpSize;
   UINTN             BriefSize;
+  UINTN             StringIdWalker;
   BOOLEAN           Ascii;
   CHAR16            *TempString2;
-  EFI_DEVICE_PATH_PROTOCOL  *FileDevPath;
-  EFI_DEVICE_PATH_PROTOCOL  *DevPath;
+  CHAR16            *CmdFileName;
+  CHAR16            *CmdFilePathName;
+  CHAR16            *StringBuff;
+  EFI_DEVICE_PATH_PROTOCOL      *FileDevPath;
+  EFI_DEVICE_PATH_PROTOCOL      *DevPath;
+  EFI_HII_PACKAGE_LIST_HEADER   *PackageListHeader;
 
   if ( ManFileName == NULL
     || Command     == NULL
@@ -735,10 +831,19 @@ ProcessManFile(
     return (EFI_INVALID_PARAMETER);
   }
 
-  HelpSize    = 0;
-  BriefSize   = 0;
-  TempString  = NULL;
-  Ascii       = FALSE;
+  HelpSize          = 0;
+  BriefSize         = 0;
+  StringIdWalker    = 0;
+  TempString        = NULL;
+  Ascii             = FALSE;
+  CmdFileName       = NULL;
+  CmdFilePathName   = NULL;
+  CmdFileImgHandle  = NULL;
+  StringBuff        = NULL;
+  PackageListHeader = NULL;
+  FileDevPath       = NULL;
+  DevPath           = NULL;
+
   //
   // See if it's in HII first
   //
@@ -750,6 +855,9 @@ ProcessManFile(
       Status = ManBufferFindSections(TempString2, Sections, HelpText, 
&HelpSize);
     }
   } else {
+    //
+    // If the image is a external app, check .MAN file first.
+    //
     FileHandle    = NULL;
     TempString  = GetManFileName(ManFileName);
     if (TempString == NULL) {
@@ -761,8 +869,8 @@ ProcessManFile(
       FileDevPath = FileDevicePath(NULL, TempString);
       DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath);
       Status = InternalOpenFileDevicePath(DevPath, &FileHandle, 
EFI_FILE_MODE_READ, 0);
-      FreePool(FileDevPath);
-      FreePool(DevPath);
+      SHELL_FREE_NON_NULL(FileDevPath);
+      SHELL_FREE_NON_NULL(DevPath);
     }
 
     if (!EFI_ERROR(Status)) {
@@ -773,13 +881,127 @@ ProcessManFile(
         Status = ManFileFindSections(FileHandle, Sections, HelpText, 
&HelpSize, Ascii);
       }
       ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);
-    } else {
+      if (!EFI_ERROR(Status)) {
+        //
+        // Get help text from .MAN file success.
+        //
+        goto Done;
+      }
+    }
+
+    //
+    // Load the app image to check  EFI_HII_PACKAGE_LIST_PROTOCOL.
+    //
+    CmdFileName     = GetExecuatableFileName(TempString);
+       if (CmdFileName == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+         goto Done;
+       }
+    //
+    // If the file in CWD then use the file name, else use the full
+    // path name.
+    //
+    CmdFilePathName = ShellFindFilePath(CmdFileName);
+    if (CmdFilePathName == NULL) {
+      Status = EFI_NOT_FOUND;
+      goto Done;
+    }
+    DevPath = 
ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CmdFilePathName);
+    Status      = gBS->LoadImage(FALSE, gImageHandle, DevPath, NULL, 0, 
&CmdFileImgHandle);
+    if(EFI_ERROR(Status)) {
       *HelpText = NULL;
+      goto Done;
     }
+    Status = gBS->OpenProtocol(
+                    CmdFileImgHandle,
+                    &gEfiHiiPackageListProtocolGuid,
+                    (VOID**)&PackageListHeader,
+                    gImageHandle,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if(EFI_ERROR(Status)) {
+      *HelpText = NULL;
+      goto Done;
+    }
+
+    //
+    // If get package list on image handle, install it on HiiDatabase.
+    //
+    Status = gBS->InstallProtocolInterface (
+                    &mShellManDriverHandle,
+                    &gEfiDevicePathProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mShellManHiiDevicePath
+                    );
+    if (EFI_ERROR(Status)) {
+      goto Done;
+    }
+
+    Status = gHiiDatabase->NewPackageList (
+                            gHiiDatabase,
+                            PackageListHeader,
+                            mShellManDriverHandle,
+                            &mShellManHiiHandle
+                            );
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+
+    StringIdWalker = 1;
+    do {
+        SHELL_FREE_NON_NULL(StringBuff);
+        if (BriefDesc != NULL) {
+          SHELL_FREE_NON_NULL(*BriefDesc);
+        }
+        StringBuff = HiiGetString (mShellManHiiHandle, 
(EFI_STRING_ID)StringIdWalker, NULL);
+        if (StringBuff == NULL) {
+          Status = EFI_NOT_FOUND;
+          goto Done;
+        }
+        TempString2 = StringBuff;
+        Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, 
&BriefSize);
+        if (!EFI_ERROR(Status) && HelpText != NULL){
+          Status = ManBufferFindSections(TempString2, Sections, HelpText, 
&HelpSize);
+        }
+        if (!EFI_ERROR(Status)){
+          //
+          // Found what we need and return
+          //
+          goto Done;
+        }
+
+        StringIdWalker += 1;
+    } while (StringIdWalker < 0xFFFF && StringBuff != NULL);
+
   }
-  if (TempString != NULL) {
-    FreePool(TempString);
+
+Done:
+  if (mShellManDriverHandle != NULL) {
+    gBS->UninstallProtocolInterface (
+            mShellManDriverHandle,
+            &gEfiDevicePathProtocolGuid,
+            &mShellManHiiDevicePath
+           );
+    mShellManDriverHandle = NULL;
+  }
+
+  if (mShellManHiiHandle != NULL) {
+    HiiRemovePackages (mShellManHiiHandle);
+    mShellManHiiHandle = NULL;
   }
 
+  if (CmdFileImgHandle != NULL) {
+    Status = gBS->UnloadImage (CmdFileImgHandle);
+  }
+
+  SHELL_FREE_NON_NULL(StringBuff);
+  SHELL_FREE_NON_NULL(TempString);
+  SHELL_FREE_NON_NULL(CmdFileName);
+  SHELL_FREE_NON_NULL(CmdFilePathName);
+  SHELL_FREE_NON_NULL(FileDevPath);
+  SHELL_FREE_NON_NULL(DevPath);
+
   return (Status);
 }
+
diff --git a/ShellPkg/Include/Guid/ShellManHiiGuid.h 
b/ShellPkg/Include/Guid/ShellManHiiGuid.h
new file mode 100644
index 0000000..df4dad6
--- /dev/null
+++ b/ShellPkg/Include/Guid/ShellManHiiGuid.h
@@ -0,0 +1,25 @@
+/** @file
+  GUID for Shell Help string in HII database.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SHELL_MAN_HII_GUID_H_
+#define _SHELL_MAN_HII_GUID_H_
+
+#define SHELL_MAN_HII_GUID \
+{ \
+  0xf62ccd0c, 0x2449, 0x453c, { 0x8a, 0xcb, 0x8c, 0xc5, 0x7c, 0xf0, 0x2a, 0x97 
} \
+}
+
+extern EFI_GUID gShellManHiiGuid;
+
+#endif
diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec
index 76a2b7d..3a9ff68 100644
--- a/ShellPkg/ShellPkg.dec
+++ b/ShellPkg/ShellPkg.dec
@@ -2,7 +2,7 @@
 # This Package provides all definitions for EFI and UEFI Shell
 #
 # (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
 #
 # This program and the accompanying materials are licensed and made available 
under
 # the terms and conditions of the BSD License which accompanies this 
distribution.
@@ -55,6 +55,7 @@
   gShellNetwork1HiiGuid           = {0xf3d301bb, 0xf4a5, 0x45a8, {0xb0, 0xb7, 
0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae}}
   gShellTftpHiiGuid               = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 
0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
   gShellBcfgHiiGuid               = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 
0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
+  gShellManHiiGuid                = {0xf62ccd0c, 0x2449, 0x453c, {0x8a, 0xcb, 
0x8c, 0xc5, 0x7c, 0xf0, 0x2a, 0x97}}
 
 [Protocols]
   gEfiShellProtocolGuid               = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 
0xac, 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}}
-- 
2.7.1.windows.2

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to