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
67 // Get Lexical Comparison Value between PrevCommand and Command list entry
69 LexicalMatchValue
= gUnicodeCollation
->StriColl (
71 (CHAR16
*)LexicalSpot
,
75 // The new item goes before this one.
77 if ((LexicalMatchValue
> 0) || (StrLen (LexicalSpot
) == 0)) {
78 if (StrLen (LexicalSpot
) != 0) {
80 // Move this and all other items out of the way
83 LexicalSpot
+ (SizeOfAddedNameInBytes
/sizeof (CHAR16
)),
85 (*DestSize
) - SizeOfAddedNameInBytes
- ((LexicalSpot
- NewList
) * sizeof (CHAR16
))
90 // Stick this one in place
92 StrCpyS (LexicalSpot
, SizeOfAddedNameInBytes
/sizeof (CHAR16
), Item
);
102 function to add each command name from the linked list to the string list.
104 the resultant list is a double NULL terminated list of NULL terminated strings.
106 @param[in,out] DestList double pointer to the list. may be NULL.
107 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
108 @param[in] SourceList the double linked list of commands.
110 @retval EFI_SUCCESS the operation was successful.
113 CopyListOfCommandNames (
114 IN OUT CHAR16
**DestList
,
115 IN OUT UINTN
*DestSize
,
116 IN CONST COMMAND_LIST
*SourceList
119 CONST COMMAND_LIST
*Node
;
121 for ( Node
= (COMMAND_LIST
*)GetFirstNode (&SourceList
->Link
)
122 ; SourceList
!= NULL
&& !IsListEmpty (&SourceList
->Link
) && !IsNull (&SourceList
->Link
, &Node
->Link
)
123 ; Node
= (COMMAND_LIST
*)GetNextNode (&SourceList
->Link
, &Node
->Link
)
126 LexicalInsertIntoList (DestList
, DestSize
, Node
->CommandString
);
129 return (EFI_SUCCESS
);
133 function to add each dynamic command name to the string list.
135 the resultant list is a double NULL terminated list of NULL terminated strings.
137 @param[in,out] DestList double pointer to the list. may be NULL.
138 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
140 @retval EFI_SUCCESS the operation was successful.
141 @return an error from HandleProtocol
145 CopyListOfCommandNamesWithDynamic (
146 IN OUT CHAR16
**DestList
,
147 IN OUT UINTN
*DestSize
150 EFI_HANDLE
*CommandHandleList
;
151 CONST EFI_HANDLE
*NextCommand
;
152 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
155 CommandHandleList
= GetHandleListByProtocol (&gEfiShellDynamicCommandProtocolGuid
);
158 // If there are none, then just return with success
160 if (CommandHandleList
== NULL
) {
161 return (EFI_SUCCESS
);
164 Status
= EFI_SUCCESS
;
167 // Append those to the list.
169 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
&& !EFI_ERROR (Status
); NextCommand
++) {
170 Status
= gBS
->HandleProtocol (
172 &gEfiShellDynamicCommandProtocolGuid
,
173 (VOID
**)&DynamicCommand
176 if (EFI_ERROR (Status
)) {
180 Status
= LexicalInsertIntoList (DestList
, DestSize
, DynamicCommand
->CommandName
);
183 SHELL_FREE_NON_NULL (CommandHandleList
);
188 Attempt to print help from a dynamically added command.
190 @param[in] CommandToGetHelpOn The unicode name of the command that help is
192 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
193 @param[in] PrintCommandText Print the command followed by the help content
196 @retval EFI_SUCCESS The help was displayed
197 @retval EFI_NOT_FOUND The command name could not be found
198 @retval EFI_DEVICE_ERROR The help data format was incorrect.
201 PrintDynamicCommandHelp (
202 IN CONST CHAR16
*CommandToGetHelpOn
,
203 IN CONST CHAR16
*SectionToGetHelpOn
,
204 IN BOOLEAN PrintCommandText
209 EFI_HANDLE
*CommandHandleList
;
210 EFI_HANDLE
*NextCommand
;
211 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
213 Status
= EFI_NOT_FOUND
;
215 CommandHandleList
= NULL
;
217 CommandHandleList
= GetHandleListByProtocol (&gEfiShellDynamicCommandProtocolGuid
);
219 if (CommandHandleList
== NULL
) {
221 // not found or out of resources
226 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
227 Status
= gBS
->HandleProtocol (
229 &gEfiShellDynamicCommandProtocolGuid
,
230 (VOID
**)&DynamicCommand
233 if (EFI_ERROR (Status
)) {
238 // Check execution break flag when printing multiple command help information.
240 if (ShellGetExecutionBreakFlag ()) {
244 if ((gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)CommandToGetHelpOn
)) ||
245 ((gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
) != NULL
) && (gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)(gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
))))))
247 // Print as Shell Help if in ManPage format.
248 Status
= ShellPrintHelp (
249 DynamicCommand
->CommandName
,
253 if (Status
== EFI_DEVICE_ERROR
) {
258 STRING_TOKEN (STR_HELP_INV
),
259 gShellLevel3HiiHandle
,
260 DynamicCommand
->CommandName
262 } else if (EFI_ERROR (Status
)) {
267 STRING_TOKEN (STR_HELP_NF
),
268 gShellLevel3HiiHandle
,
269 DynamicCommand
->CommandName
277 SHELL_FREE_NON_NULL (CommandHandleList
);
279 return (Found
? EFI_SUCCESS
: Status
);
282 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
283 { L
"-usage", TypeFlag
},
284 { L
"-section", TypeMaxValue
},
285 { L
"-verbose", TypeFlag
},
291 Function for 'help' command.
293 @param[in] ImageHandle Handle to the Image (NULL if Internal).
294 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
298 ShellCommandRunHelp (
299 IN EFI_HANDLE ImageHandle
,
300 IN EFI_SYSTEM_TABLE
*SystemTable
305 CHAR16
*ProblemParam
;
306 SHELL_STATUS ShellStatus
;
307 CHAR16
*SortedCommandList
;
308 CONST CHAR16
*CurrentCommand
;
309 CHAR16
*CommandToGetHelpOn
;
310 CHAR16
*SectionToGetHelpOn
;
313 BOOLEAN PrintCommandText
;
314 UINTN SortedCommandListSize
;
316 PrintCommandText
= TRUE
;
318 ShellStatus
= SHELL_SUCCESS
;
319 CommandToGetHelpOn
= NULL
;
320 SectionToGetHelpOn
= NULL
;
321 SortedCommandList
= NULL
;
325 // initialize the shell lib (we must be in non-auto-init...)
327 Status
= ShellInitialize ();
328 ASSERT_EFI_ERROR (Status
);
330 Status
= CommandInit ();
331 ASSERT_EFI_ERROR (Status
);
334 // parse the command line
336 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
337 if (EFI_ERROR (Status
)) {
338 if ((Status
== EFI_VOLUME_CORRUPTED
) && (ProblemParam
!= NULL
)) {
339 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel3HiiHandle
, L
"help", ProblemParam
);
340 FreePool (ProblemParam
);
341 ShellStatus
= SHELL_INVALID_PARAMETER
;
347 // Check for conflicting parameters.
349 if ( ShellCommandLineGetFlag (Package
, L
"-usage")
350 && ShellCommandLineGetFlag (Package
, L
"-section")
351 && (ShellCommandLineGetFlag (Package
, L
"-verbose") || ShellCommandLineGetFlag (Package
, L
"-v"))
354 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_CON
), gShellLevel3HiiHandle
, L
"help");
355 ShellStatus
= SHELL_INVALID_PARAMETER
;
356 } else if (ShellCommandLineGetRawValue (Package
, 2) != NULL
) {
357 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel3HiiHandle
, L
"help");
358 ShellStatus
= SHELL_INVALID_PARAMETER
;
361 // Get the command name we are getting help on
363 ASSERT (CommandToGetHelpOn
== NULL
);
364 StrnCatGrow (&CommandToGetHelpOn
, NULL
, ShellCommandLineGetRawValue (Package
, 1), 0);
365 if ((CommandToGetHelpOn
== NULL
) && ShellCommandLineGetFlag (Package
, L
"-?")) {
367 // If we dont have a command and we got a simple -?
368 // we are looking for help on help command.
370 StrnCatGrow (&CommandToGetHelpOn
, NULL
, L
"help", 0);
373 if (CommandToGetHelpOn
== NULL
) {
374 StrnCatGrow (&CommandToGetHelpOn
, NULL
, L
"*", 0);
375 ASSERT (SectionToGetHelpOn
== NULL
);
376 StrnCatGrow (&SectionToGetHelpOn
, NULL
, L
"NAME", 0);
378 PrintCommandText
= FALSE
;
379 ASSERT (SectionToGetHelpOn
== NULL
);
381 // Get the section name for the given command name
383 if (ShellCommandLineGetFlag (Package
, L
"-section")) {
384 StrnCatGrow (&SectionToGetHelpOn
, NULL
, ShellCommandLineGetValue (Package
, L
"-section"), 0);
385 } else if (ShellCommandLineGetFlag (Package
, L
"-usage")) {
386 StrnCatGrow (&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS", 0);
387 } else if (ShellCommandLineGetFlag (Package
, L
"-verbose") || ShellCommandLineGetFlag (Package
, L
"-v")) {
390 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
392 StrnCatGrow (&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
396 if (gUnicodeCollation
->StriColl (gUnicodeCollation
, CommandToGetHelpOn
, L
"special") == 0) {
398 // we need info on the special characters
400 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_SC_HEADER
), gShellLevel3HiiHandle
);
401 HiiString
= HiiGetString (gShellLevel3HiiHandle
, STRING_TOKEN (STR_HELP_SC_DATA
), NULL
);
402 ShellPrintEx (-1, -1, L
"%s", HiiString
);
403 FreePool (HiiString
);
406 SortedCommandList
= NULL
;
407 SortedCommandListSize
= 0;
408 CopyListOfCommandNames (&SortedCommandList
, &SortedCommandListSize
, ShellCommandGetCommandList (TRUE
));
409 CopyListOfCommandNamesWithDynamic (&SortedCommandList
, &SortedCommandListSize
);
411 for (CurrentCommand
= SortedCommandList
412 ; CurrentCommand
!= NULL
&& CurrentCommand
< SortedCommandList
+ SortedCommandListSize
/sizeof (CHAR16
) && *CurrentCommand
!= CHAR_NULL
413 ; CurrentCommand
+= StrLen (CurrentCommand
) + 1
417 // Checking execution break flag when print multiple command help information.
419 if (ShellGetExecutionBreakFlag ()) {
423 if ((gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)CurrentCommand
, CommandToGetHelpOn
)) ||
424 ((gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
) != NULL
) && (gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)CurrentCommand
, (CHAR16
*)(gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
))))))
427 // We have a command to look for help on.
429 Status
= ShellPrintHelp (CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
430 if (EFI_ERROR (Status
)) {
432 // now try to match against the dynamic command list and print help
434 Status
= PrintDynamicCommandHelp (CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
437 if (Status
== EFI_DEVICE_ERROR
) {
438 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CurrentCommand
);
439 } else if (EFI_ERROR (Status
)) {
440 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CurrentCommand
);
448 // Search the .man file for Shell applications (Shell external commands).
451 Status
= ShellPrintHelp (CommandToGetHelpOn
, SectionToGetHelpOn
, FALSE
);
452 if (Status
== EFI_DEVICE_ERROR
) {
453 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
454 } else if (EFI_ERROR (Status
)) {
455 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
463 ShellStatus
= SHELL_NOT_FOUND
;
467 // free the command line package
469 ShellCommandLineFreeVarList (Package
);
473 if ((CommandToGetHelpOn
!= NULL
) && (StrCmp (CommandToGetHelpOn
, L
"*") == 0)) {
475 // If '*' then the command entered was 'Help' without qualifiers, This footer
476 // provides additional info on help switches
478 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_FOOTER
), gShellLevel3HiiHandle
);
481 if (CommandToGetHelpOn
!= NULL
) {
482 FreePool (CommandToGetHelpOn
);
485 if (SectionToGetHelpOn
!= NULL
) {
486 FreePool (SectionToGetHelpOn
);
489 SHELL_FREE_NON_NULL (SortedCommandList
);
491 return (ShellStatus
);