]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellManParser.c
ShellPkg: Fix the bug that handling Ctrl-C improperly
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellManParser.c
index 222cdafd6ebe71c7bb5d89684d4c140604928621..7a290e16f670828a58fc61fe902d1e948d09d0f8 100644 (file)
@@ -1,7 +1,7 @@
 /** @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 - 2016, 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
 \r
 #include "Shell.h"\r
 \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
 /**\r
   Convert a Unicode character to upper case only if\r
   it maps to a valid small-case ASCII character.\r
 \r
 **/\r
 CHAR16\r
-EFIAPI \r
 InternalShellCharToUpper (\r
   IN CHAR16  Char\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
 \r
@@ -48,7 +130,6 @@ InternalShellCharToUpper (
   @return the new filename with .man as the extension.\r
 **/\r
 CHAR16 *\r
-EFIAPI\r
 GetManFileName(\r
   IN CONST CHAR16 *ManFileName\r
   )\r
@@ -95,7 +176,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
@@ -143,7 +223,6 @@ SearchPathForFile(
                                 an alloceted buffer.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ManBufferFindSections(\r
   IN CONST CHAR16 *Buffer,\r
   IN CONST CHAR16 *Sections,\r
@@ -277,7 +356,6 @@ ManBufferFindSections(
                                 an alloceted buffer.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ManFileFindSections(\r
   IN SHELL_FILE_HANDLE  Handle,\r
   IN CONST CHAR16       *Sections,\r
@@ -381,7 +459,7 @@ ManFileFindSections(
 \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] Buffer             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
@@ -391,7 +469,6 @@ ManFileFindSections(
                                 an alloceted buffer.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ManBufferFindTitleSection(\r
   IN CHAR16         **Buffer,\r
   IN CONST CHAR16   *Command,\r
@@ -404,6 +481,7 @@ ManBufferFindTitleSection(
   CHAR16        *TitleEnd;\r
   CHAR16        *CurrentLocation;\r
   UINTN         TitleLength;\r
+  UINTN         Start;\r
   CONST CHAR16  StartString[] = L".TH ";\r
   CONST CHAR16  EndString[]   = L" 0 ";\r
 \r
@@ -416,16 +494,27 @@ ManBufferFindTitleSection(
 \r
   Status    = EFI_SUCCESS;\r
 \r
+  //\r
+  // Do not pass any leading path information that may be present to IsTitleHeader().\r
+  //\r
+  Start = StrLen(Command);\r
+  while ((Start != 0)\r
+         && (*(Command + Start - 1) != L'\\')\r
+         && (*(Command + Start - 1) != L'/')\r
+         && (*(Command + Start - 1) != L':')) {\r
+    --Start;\r
+  }\r
+\r
   //\r
   // more characters for StartString and EndString\r
   //\r
-  TitleLength = StrSize(Command) + (StrLen(StartString) + StrLen(EndString)) * sizeof(CHAR16);\r
+  TitleLength = StrSize(Command + Start) + (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), Command + Start);\r
   StrCatS(TitleString, TitleLength/sizeof(CHAR16), EndString);\r
 \r
   CurrentLocation = StrStr(*Buffer, TitleString);\r
@@ -616,7 +705,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
@@ -709,7 +797,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
@@ -720,13 +807,19 @@ 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
+  CHAR16            *StringBuff;\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
@@ -735,10 +828,19 @@ 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
+  StringBuff        = NULL;\r
+  PackageListHeader = NULL;\r
+  FileDevPath       = NULL;\r
+  DevPath           = NULL;\r
+\r
   //\r
   // See if it's in HII first\r
   //\r
@@ -750,6 +852,9 @@ ProcessManFile(
       Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize);\r
     }\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
@@ -761,8 +866,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
@@ -773,13 +878,127 @@ 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
+      *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(StringBuff);\r
+        if (BriefDesc != NULL) {\r
+          SHELL_FREE_NON_NULL(*BriefDesc);\r
+        }\r
+        StringBuff = HiiGetString (mShellManHiiHandle, (EFI_STRING_ID)StringIdWalker, NULL);\r
+        if (StringBuff == NULL) {\r
+          Status = EFI_NOT_FOUND;\r
+          goto Done;\r
+        }\r
+        TempString2 = StringBuff;\r
+        Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, &BriefSize);\r
+        if (!EFI_ERROR(Status) && HelpText != NULL){\r
+          Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize);\r
+        }\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 && StringBuff != 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(StringBuff);\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