2 Main file for Help shell level 3 function.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved. <BR>
5 Copyright (c) 2014, ARM Limited. All rights reserved. <BR>
6 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "UefiShellLevel3CommandsLib.h"
14 #include <Library/ShellLib.h>
15 #include <Library/HandleParsingLib.h>
17 #include <Protocol/ShellDynamicCommand.h>
20 function to insert string items into a list in the correct alphabetical place
22 the resultant list is a double NULL terminated list of NULL terminated strings.
24 upon successful return the memory must be caller freed (unless passed back in
25 via a loop where it will get reallocated).
27 @param[in,out] DestList double pointer to the list. may be NULL.
28 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
29 @param[in] Item the item to insert.
31 @retval EFI_SUCCESS the operation was successful.
34 LexicalInsertIntoList(
35 IN OUT CHAR16
**DestList
,
36 IN OUT UINTN
*DestSize
,
41 INTN LexicalMatchValue
;
43 UINTN SizeOfAddedNameInBytes
;
46 // If there are none, then just return with success
48 if (Item
== NULL
|| *Item
== CHAR_NULL
|| StrLen(Item
)==0) {
54 SizeOfAddedNameInBytes
= StrSize(Item
);
55 NewList
= ReallocatePool(*DestSize
, (*DestSize
) + SizeOfAddedNameInBytes
, NewList
);
56 (*DestSize
) = (*DestSize
) + SizeOfAddedNameInBytes
;
59 // Find the correct spot in the list
61 for (LexicalSpot
= NewList
62 ; LexicalSpot
!= NULL
&& LexicalSpot
< NewList
+ (*DestSize
)
63 ; LexicalSpot
+= StrLen(LexicalSpot
) + 1
66 // Get Lexical Comparison Value between PrevCommand and Command list entry
68 LexicalMatchValue
= gUnicodeCollation
->StriColl (
70 (CHAR16
*)LexicalSpot
,
74 // The new item goes before this one.
76 if (LexicalMatchValue
> 0 || StrLen(LexicalSpot
) == 0) {
77 if (StrLen(LexicalSpot
) != 0) {
79 // Move this and all other items out of the way
82 LexicalSpot
+ (SizeOfAddedNameInBytes
/sizeof(CHAR16
)),
84 (*DestSize
) - SizeOfAddedNameInBytes
- ((LexicalSpot
- NewList
) * sizeof(CHAR16
))
89 // Stick this one in place
91 StrCpyS(LexicalSpot
, SizeOfAddedNameInBytes
/sizeof(CHAR16
), Item
);
101 function to add each command name from the linked list to the string list.
103 the resultant list is a double NULL terminated list of NULL terminated strings.
105 @param[in,out] DestList double pointer to the list. may be NULL.
106 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
107 @param[in] SourceList the double linked list of commands.
109 @retval EFI_SUCCESS the operation was successful.
112 CopyListOfCommandNames(
113 IN OUT CHAR16
**DestList
,
114 IN OUT UINTN
*DestSize
,
115 IN CONST COMMAND_LIST
*SourceList
118 CONST COMMAND_LIST
*Node
;
120 for ( Node
= (COMMAND_LIST
*)GetFirstNode(&SourceList
->Link
)
121 ; SourceList
!= NULL
&& !IsListEmpty(&SourceList
->Link
) && !IsNull(&SourceList
->Link
, &Node
->Link
)
122 ; Node
= (COMMAND_LIST
*)GetNextNode(&SourceList
->Link
, &Node
->Link
)
124 LexicalInsertIntoList(DestList
, DestSize
, Node
->CommandString
);
126 return (EFI_SUCCESS
);
130 function to add each dynamic command name to the string list.
132 the resultant list is a double NULL terminated list of NULL terminated strings.
134 @param[in,out] DestList double pointer to the list. may be NULL.
135 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
137 @retval EFI_SUCCESS the operation was successful.
138 @return an error from HandleProtocol
142 CopyListOfCommandNamesWithDynamic(
143 IN OUT CHAR16
** DestList
,
144 IN OUT UINTN
*DestSize
147 EFI_HANDLE
*CommandHandleList
;
148 CONST EFI_HANDLE
*NextCommand
;
149 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
152 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
155 // If there are none, then just return with success
157 if (CommandHandleList
== NULL
) {
158 return (EFI_SUCCESS
);
161 Status
= EFI_SUCCESS
;
164 // Append those to the list.
166 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
&& !EFI_ERROR(Status
) ; NextCommand
++) {
167 Status
= gBS
->HandleProtocol(
169 &gEfiShellDynamicCommandProtocolGuid
,
170 (VOID
**)&DynamicCommand
173 if (EFI_ERROR(Status
)) {
177 Status
= LexicalInsertIntoList(DestList
, DestSize
, DynamicCommand
->CommandName
);
180 SHELL_FREE_NON_NULL(CommandHandleList
);
186 Attempt to print help from a dynamically added command.
188 @param[in] CommandToGetHelpOn The unicode name of the command that help is
190 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
191 @param[in] PrintCommandText Print the command followed by the help content
194 @retval EFI_SUCCESS The help was displayed
195 @retval EFI_NOT_FOUND The command name could not be found
196 @retval EFI_DEVICE_ERROR The help data format was incorrect.
199 PrintDynamicCommandHelp(
200 IN CONST CHAR16
*CommandToGetHelpOn
,
201 IN CONST CHAR16
*SectionToGetHelpOn
,
202 IN BOOLEAN PrintCommandText
207 EFI_HANDLE
*CommandHandleList
;
208 EFI_HANDLE
*NextCommand
;
209 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
211 Status
= EFI_NOT_FOUND
;
213 CommandHandleList
= NULL
;
215 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
217 if (CommandHandleList
== NULL
) {
219 // not found or out of resources
224 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
225 Status
= gBS
->HandleProtocol(
227 &gEfiShellDynamicCommandProtocolGuid
,
228 (VOID
**)&DynamicCommand
231 if (EFI_ERROR(Status
)) {
236 // Check execution break flag when printing multiple command help information.
238 if (ShellGetExecutionBreakFlag ()) {
242 if ((gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)CommandToGetHelpOn
)) ||
243 (gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
) != NULL
&& (gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)(gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
)))))) {
244 // Print as Shell Help if in ManPage format.
245 Status
= ShellPrintHelp (DynamicCommand
->CommandName
, SectionToGetHelpOn
,
247 if (Status
== EFI_DEVICE_ERROR
) {
248 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
),
249 gShellLevel3HiiHandle
, DynamicCommand
->CommandName
);
250 } else if (EFI_ERROR(Status
)) {
251 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
),
252 gShellLevel3HiiHandle
, DynamicCommand
->CommandName
);
259 SHELL_FREE_NON_NULL(CommandHandleList
);
261 return (Found
? EFI_SUCCESS
: Status
);
265 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
266 {L
"-usage", TypeFlag
},
267 {L
"-section", TypeMaxValue
},
268 {L
"-verbose", TypeFlag
},
274 Function for 'help' command.
276 @param[in] ImageHandle Handle to the Image (NULL if Internal).
277 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
281 ShellCommandRunHelp (
282 IN EFI_HANDLE ImageHandle
,
283 IN EFI_SYSTEM_TABLE
*SystemTable
288 CHAR16
*ProblemParam
;
289 SHELL_STATUS ShellStatus
;
290 CHAR16
*SortedCommandList
;
291 CONST CHAR16
*CurrentCommand
;
292 CHAR16
*CommandToGetHelpOn
;
293 CHAR16
*SectionToGetHelpOn
;
296 BOOLEAN PrintCommandText
;
297 UINTN SortedCommandListSize
;
299 PrintCommandText
= TRUE
;
301 ShellStatus
= SHELL_SUCCESS
;
302 CommandToGetHelpOn
= NULL
;
303 SectionToGetHelpOn
= NULL
;
304 SortedCommandList
= NULL
;
308 // initialize the shell lib (we must be in non-auto-init...)
310 Status
= ShellInitialize();
311 ASSERT_EFI_ERROR(Status
);
313 Status
= CommandInit();
314 ASSERT_EFI_ERROR(Status
);
317 // parse the command line
319 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
320 if (EFI_ERROR(Status
)) {
321 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
322 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel3HiiHandle
, L
"help", ProblemParam
);
323 FreePool(ProblemParam
);
324 ShellStatus
= SHELL_INVALID_PARAMETER
;
330 // Check for conflicting parameters.
332 if (ShellCommandLineGetFlag(Package
, L
"-usage")
333 &&ShellCommandLineGetFlag(Package
, L
"-section")
334 &&(ShellCommandLineGetFlag(Package
, L
"-verbose") || ShellCommandLineGetFlag(Package
, L
"-v"))
336 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_CON
), gShellLevel3HiiHandle
, L
"help");
337 ShellStatus
= SHELL_INVALID_PARAMETER
;
338 } else if (ShellCommandLineGetRawValue(Package
, 2) != NULL
) {
339 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel3HiiHandle
, L
"help");
340 ShellStatus
= SHELL_INVALID_PARAMETER
;
343 // Get the command name we are getting help on
345 ASSERT(CommandToGetHelpOn
== NULL
);
346 StrnCatGrow(&CommandToGetHelpOn
, NULL
, ShellCommandLineGetRawValue(Package
, 1), 0);
347 if (CommandToGetHelpOn
== NULL
&& ShellCommandLineGetFlag(Package
, L
"-?")) {
349 // If we dont have a command and we got a simple -?
350 // we are looking for help on help command.
352 StrnCatGrow(&CommandToGetHelpOn
, NULL
, L
"help", 0);
355 if (CommandToGetHelpOn
== NULL
) {
356 StrnCatGrow(&CommandToGetHelpOn
, NULL
, L
"*", 0);
357 ASSERT(SectionToGetHelpOn
== NULL
);
358 StrnCatGrow(&SectionToGetHelpOn
, NULL
, L
"NAME", 0);
360 PrintCommandText
= FALSE
;
361 ASSERT(SectionToGetHelpOn
== NULL
);
363 // Get the section name for the given command name
365 if (ShellCommandLineGetFlag(Package
, L
"-section")) {
366 StrnCatGrow(&SectionToGetHelpOn
, NULL
, ShellCommandLineGetValue(Package
, L
"-section"), 0);
367 } else if (ShellCommandLineGetFlag(Package
, L
"-usage")) {
368 StrnCatGrow(&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS", 0);
369 } else if (ShellCommandLineGetFlag(Package
, L
"-verbose") || ShellCommandLineGetFlag(Package
, L
"-v")) {
372 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
374 StrnCatGrow (&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
378 if (gUnicodeCollation
->StriColl(gUnicodeCollation
, CommandToGetHelpOn
, L
"special") == 0) {
380 // we need info on the special characters
382 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_SC_HEADER
), gShellLevel3HiiHandle
);
383 HiiString
= HiiGetString(gShellLevel3HiiHandle
, STRING_TOKEN(STR_HELP_SC_DATA
), NULL
);
384 ShellPrintEx(-1, -1, L
"%s", HiiString
);
388 SortedCommandList
= NULL
;
389 SortedCommandListSize
= 0;
390 CopyListOfCommandNames(&SortedCommandList
, &SortedCommandListSize
, ShellCommandGetCommandList(TRUE
));
391 CopyListOfCommandNamesWithDynamic(&SortedCommandList
, &SortedCommandListSize
);
393 for (CurrentCommand
= SortedCommandList
394 ; CurrentCommand
!= NULL
&& CurrentCommand
< SortedCommandList
+ SortedCommandListSize
/sizeof(CHAR16
) && *CurrentCommand
!= CHAR_NULL
395 ; CurrentCommand
+= StrLen(CurrentCommand
) + 1
398 // Checking execution break flag when print multiple command help information.
400 if (ShellGetExecutionBreakFlag ()) {
404 if ((gUnicodeCollation
->MetaiMatch(gUnicodeCollation
, (CHAR16
*)CurrentCommand
, CommandToGetHelpOn
)) ||
405 (gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
) != NULL
&& (gUnicodeCollation
->MetaiMatch(gUnicodeCollation
, (CHAR16
*)CurrentCommand
, (CHAR16
*)(gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
)))))) {
407 // We have a command to look for help on.
409 Status
= ShellPrintHelp(CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
410 if (EFI_ERROR(Status
)) {
412 // now try to match against the dynamic command list and print help
414 Status
= PrintDynamicCommandHelp (CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
416 if (Status
== EFI_DEVICE_ERROR
) {
417 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CurrentCommand
);
418 } else if (EFI_ERROR(Status
)) {
419 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CurrentCommand
);
427 // Search the .man file for Shell applications (Shell external commands).
430 Status
= ShellPrintHelp(CommandToGetHelpOn
, SectionToGetHelpOn
, FALSE
);
431 if (Status
== EFI_DEVICE_ERROR
) {
432 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
433 } else if (EFI_ERROR(Status
)) {
434 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
442 ShellStatus
= SHELL_NOT_FOUND
;
446 // free the command line package
448 ShellCommandLineFreeVarList (Package
);
452 if (CommandToGetHelpOn
!= NULL
&& StrCmp(CommandToGetHelpOn
, L
"*") == 0){
454 // If '*' then the command entered was 'Help' without qualifiers, This footer
455 // provides additional info on help switches
457 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_FOOTER
), gShellLevel3HiiHandle
);
459 if (CommandToGetHelpOn
!= NULL
) {
460 FreePool(CommandToGetHelpOn
);
462 if (SectionToGetHelpOn
!= NULL
) {
463 FreePool(SectionToGetHelpOn
);
465 SHELL_FREE_NON_NULL(SortedCommandList
);
467 return (ShellStatus
);