/** @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
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
+EFIAPI\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
\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
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
\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
{\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
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
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
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
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