UEFI shell의 모든 명령어를 보면, -? 옵션을 추가하면, 도움말 메시지를 출력할 수 있다. 예를 들어,
Shell> reset -?
Resets the system.
RESET [-w [string]]
RESET [-s [string]]
RESET [-c [string]]
-s - Performs a shutdown.
-w - Performs a warm boot.
-c - Performs a cold boot.
string - Describes a reason for the reset.
NOTES:
1. This command resets the system.
2. The default is to perform a cold reset unless the -w parameter is
specified.
3. If a reset string is specified, it is passed into the Reset()
function, and the system records the reason for the system reset.
이번 장에서는 help/man 기능을 애플리케이션에 추가하는 방법을 알아볼 것이다.
man finding 및 파싱을 담당하는 Shell 모듈은 ShellManParser이다.
기억할 것이라 생각하지만, ShellManParser는 gEfiHiiPackageListProtocolGuid 프로토콜 데이터에서 maunal 문자열을 검색했다. 따라서 manual 문자열을 이미지 리소스 Section(HIIStringsMan.inf)에 직접 포함해야 한다.
다음은 문자열 파일에 최소화된 내용만을 담은 코드이다.
애플리케이션을 빌드하고, 실행하려고 하면 더 이상 아무런 도움이 되지 않는다는 것을 볼 수 있다.
이는 프로그램이 문자열 토큰을 참조하지 않고, 빌드 프로세스(HIIStringsManStrDefs.h)에서 최적화되었기 때문이다.
이를 수정하려면, 다음 코드를 HIIStringsMan.c에 추가하면 된다.
현재 문자열이 최적화되지 않았음을 빌드 이후에 확인할 수 있다.
애플리케이션을 실행하고 나면, 다음과 같은 결과를 확인할 수 있다.
우리의 Manual을 확장하기
manual에 들어갈 수 있는 모든 섹션을 추가해보자.
여기까지 빌드하고, 실행하면 다음 내용이 출력되는 것을 확인할 수 있다.
보다시피, 넣어준 모든 섹션에 대한 print가 되지 않았다는 것을 알 수 있다. 그 이유에 대해 알아보자.
먼저 명령어에 -? 옵션을 추가해주면, 어떤 일이 일어나는지 알아보도록 하자. shell의 소스코드를 보면 shell이 -?를 명령 인수 중 하나로, command 및 나머지 모든 인수를 Shell.c의 도움말 명령으로 리다이렉트한다.
프로그램에 직접 help 명령을 사용하면, 결과가 동일하게 출력되는지 확인할 수 있다.
이제 도움말 명령 소스 코드(Help.c)를 살펴보자.
여기에서 help를 넣어줄 인수를 파싱하는 방법을 찾아볼 수 있다.
기본적으로 NAME, SYNOPSIS, OPTIONS, DESCRIPTION, EXAMPLES 섹션이 프린트된다.
-section <SECTION NAME> 인수를 사용해 특정 섹션을 출력할 수 있다.
-verbose 혹은 -v 인수를 사용해 모든 섹션들을 출력할 수 있다.
Shell에서 이 내용을 직접 확인해 볼 수 있다.
-? 옵션도 마찬가지다.
ShellManParser가 호출되는 방식
ShellManParser가 애플리케이션 문자열을 파싱한 것이라는 가정으로, 이번 장을 시작했었다. 도움말 프로그램이 이 모듈을 사용하여, 어떻게 끝나는 지 조사해보자.
모든 걸 따져보면, ShellCommandRunHelp는 ShellPrintHelp 함수(Help.c)를 호출한다.
이 ShellPrintHelp 함수는 UefiShellLib.c에 정의되어 있다. 주로 EFI_SHELL_PROTOCOL에서 GetHelpText 함수를 호출한다.
다음은 UEFI Shell 규격에서의 위 함수에 대한 설명이다.
EDKII의 EFI_SHELL_PROTOCOL structure에 대한 프로토타입은 Shell.h에 나와있다.
이 프로토콜에 대한 초기화는 ShellProtocol.c에 있다.
이 함수는 위의 동일한 파일에 정의되어 있으며, 정의를 읽어보면 ProcessManFile 모듈에서 함수를 호출하고 있음을 알 수 있다.
#langdef en-US "English"
#string STR_HELP #language en-US ""
".TH HIIStringsMan 0 "Simple application with a manual inside."\r\n"
".SH NAME\r\n"
"HIIStringsMan application.\r\n"
".SH SYNOPSIS\r\n"
"This is the synopsis section.\r\n"
".SH DESCRIPTION\r\n"
"This is the description section.\r\n"
".SH OPTIONS\r\n"
"This is the options section.\r\n"
".SH RETURN VALUES\r\n"
"This is the return values section.\r\n"
".SH ENVIRONMENT VARIABLES\r\n"
"This is the section for used environment variables\r\n"
".SH FILES\r\n"
"This is the section for files associated with the subject.\r\n"
".SH EXAMPLES\r\n"
"This is the section for examples and suggestions.\r\n"
".SH ERRORS\r\n"
"This is the section for errors reported by the command.\r\n"
".SH STANDARDS\r\n"
"This is the section for conformance to applicable standards.\r\n"
".SH BUGS\r\n"
"This is the section for errors and caveats.\r\n"
".SH CATEGORY\r\n"
"This is the section for categories.\r\n"
".SH CUSTOMSECTION\r\n"
"This is an example of a custom section.\r\n"
FS0:\> HIIStringsMan.efi -?
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the section for examples and suggestions.
$ cat ShellPkg/Application/Shell/Shell.c
---
/**
Reprocess the command line to direct all -? to the help command.
if found, will add "help" as argv[0], and move the rest later.
@param[in,out] CmdLine pointer to the command line to update
**/
EFI_STATUS
DoHelpUpdate(
IN OUT CHAR16 **CmdLine
)
{
...
if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {
CurrentParameter[0] = L' ';
CurrentParameter[1] = L' ';
NewCmdLineSize = StrSize(L"help ") + StrSize(*CmdLine);
NewCommandLine = AllocateZeroPool(NewCmdLineSize);
if (NewCommandLine == NULL) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
//
// We know the space is sufficient since we just calculated it.
//
StrnCpyS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), L"help ", 5);
StrnCatS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), *CmdLine, StrLen(*CmdLine));
SHELL_FREE_NON_NULL(*CmdLine);
*CmdLine = NewCommandLine;
break;
}
...
}
FS0:\> help HIIStringsMan.efi
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the section for examples and suggestions.
$ cat ShellPkg/Library/UefiShellLevel3CommmandsLib/Help.c
---
SHELL_STATUS
EFIAPI
ShellCommandRunHelp (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
...
//
// Get the section name for the given command name
//
if (ShellCommandLineGetFlag(Package, L"-section")) {
StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0);
} else if (ShellCommandLineGetFlag(Package, L"-usage")) {
StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0);
} else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) {
} else {
//
// The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
//
StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
}
...
}
FS0:\> help HIIStringsMan.efi -v
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the return values section.
This is the section for used environment variables
This is the section for files associated with the subject.
This is the section for examples and suggestions.
This is the section for errors reported by the command.
This is the section for conformance to applicable standards.
This is the section for errors and caveats.
This is the section for categories.
This is an example of a custom section.
FS0:\> help HIIStringsMan.efi -section BUGS
This is the section for errors and caveats.
FS0:\> HIIStringsMan.efi -? -section "RETURN VALUES"
This is the return values section.
FS0:\> HIIStringsMan.efi -? -verbose
HIIStringsMan application.
This is the synopsis section.
This is the description section.
This is the options section.
This is the return values section.
This is the section for used environment variables
This is the section for files associated with the subject.
This is the section for examples and suggestions.
This is the section for errors reported by the command.
This is the section for conformance to applicable standards.
This is the section for errors and caveats.
This is the section for categories.
This is an example of a custom section.
$ cat ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c
---
SHELL_STATUS
EFIAPI
ShellCommandRunHelp (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
...
Status = ShellPrintHelp(CommandToGetHelpOn, SectionToGetHelpOn, FALSE);
...
}
EFI_STATUS
EFIAPI
ShellPrintHelp (
IN CONST CHAR16 *CommandToGetHelpOn,
IN CONST CHAR16 *SectionToGetHelpOn,
IN BOOLEAN PrintCommandText
)
{
...
Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
...
}
EFI_SHELL_PROTOCOL.GetHelpText()
Summary:
Return help information about a specific command.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_SHELL_GET_HELP_TEXT) (
IN CONST CHAR16 *Command,
IN CONST CHAR16 *Sections,
OUT CHAR16 **HelpText
);
Parameters:
Command Points to the null-terminated UEFI Shell command name.
Sections Points to the null-terminated comma-delimited section names to return. If NULL, then all sections will be returned.
HelpText On return, points to a callee-allocated buffer containing all specified help text.