2 Main file for Help shell level 3 function.
4 Copyright (c) 2009 - 2015, 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 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "UefiShellLevel3CommandsLib.h"
20 #include <Library/ShellLib.h>
21 #include <Library/HandleParsingLib.h>
23 #include <Protocol/ShellDynamicCommand.h>
26 function to insert string items into a list in the correct alphabetical place
28 the resultant list is a double NULL terminated list of NULL terminated strings.
30 upon successful return the memory must be caller freed (unless passed back in
31 via a loop where it will get reallocated).
33 @param[in,out] DestList double pointer to the list. may be NULL.
34 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
35 @param[in] Item the item to insert.
37 @retval EFI_SUCCESS the operation was successful.
40 LexicalInsertIntoList(
41 IN OUT CHAR16
**DestList
,
42 IN OUT UINTN
*DestSize
,
47 INTN LexicalMatchValue
;
49 UINTN SizeOfAddedNameInBytes
;
52 // If there are none, then just return with success
54 if (Item
== NULL
|| *Item
== CHAR_NULL
|| StrLen(Item
)==0) {
60 SizeOfAddedNameInBytes
= StrSize(Item
);
61 NewList
= ReallocatePool(*DestSize
, (*DestSize
) + SizeOfAddedNameInBytes
, NewList
);
62 (*DestSize
) = (*DestSize
) + SizeOfAddedNameInBytes
;
65 // Find the correct spot in the list
67 for (LexicalSpot
= NewList
68 ; LexicalSpot
!= NULL
&& LexicalSpot
< NewList
+ (*DestSize
)
69 ; LexicalSpot
+= StrLen(LexicalSpot
) + 1
72 // Get Lexical Comparison Value between PrevCommand and Command list entry
74 LexicalMatchValue
= gUnicodeCollation
->StriColl (
76 (CHAR16
*)LexicalSpot
,
80 // The new item goes before this one.
82 if (LexicalMatchValue
> 0 || StrLen(LexicalSpot
) == 0) {
83 if (StrLen(LexicalSpot
) != 0) {
85 // Move this and all other items out of the way
88 LexicalSpot
+ (SizeOfAddedNameInBytes
/sizeof(CHAR16
)),
90 (*DestSize
) - SizeOfAddedNameInBytes
- ((LexicalSpot
- NewList
) * sizeof(CHAR16
))
95 // Stick this one in place
97 StrCpyS(LexicalSpot
, SizeOfAddedNameInBytes
/sizeof(CHAR16
), Item
);
103 return (EFI_SUCCESS
);
107 function to add each command name from the linked list to the string list.
109 the resultant list is a double NULL terminated list of NULL terminated strings.
111 @param[in,out] DestList double pointer to the list. may be NULL.
112 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
113 @param[in] SourceList the double linked list of commands.
115 @retval EFI_SUCCESS the operation was successful.
118 CopyListOfCommandNames(
119 IN OUT CHAR16
**DestList
,
120 IN OUT UINTN
*DestSize
,
121 IN CONST COMMAND_LIST
*SourceList
124 CONST COMMAND_LIST
*Node
;
126 for ( Node
= (COMMAND_LIST
*)GetFirstNode(&SourceList
->Link
)
127 ; SourceList
!= NULL
&& !IsListEmpty(&SourceList
->Link
) && !IsNull(&SourceList
->Link
, &Node
->Link
)
128 ; Node
= (COMMAND_LIST
*)GetNextNode(&SourceList
->Link
, &Node
->Link
)
130 LexicalInsertIntoList(DestList
, DestSize
, Node
->CommandString
);
132 return (EFI_SUCCESS
);
136 function to add each dynamic command name to the string list.
138 the resultant list is a double NULL terminated list of NULL terminated strings.
140 @param[in,out] DestList double pointer to the list. may be NULL.
141 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
143 @retval EFI_SUCCESS the operation was successful.
144 @return an error from HandleProtocol
148 CopyListOfCommandNamesWithDynamic(
149 IN OUT CHAR16
** DestList
,
150 IN OUT UINTN
*DestSize
153 EFI_HANDLE
*CommandHandleList
;
154 CONST EFI_HANDLE
*NextCommand
;
155 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
158 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
161 // If there are none, then just return with success
163 if (CommandHandleList
== NULL
) {
164 return (EFI_SUCCESS
);
167 Status
= EFI_SUCCESS
;
170 // Append those to the list.
172 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
&& !EFI_ERROR(Status
) ; NextCommand
++) {
173 Status
= gBS
->HandleProtocol(
175 &gEfiShellDynamicCommandProtocolGuid
,
176 (VOID
**)&DynamicCommand
179 if (EFI_ERROR(Status
)) {
183 Status
= LexicalInsertIntoList(DestList
, DestSize
, DynamicCommand
->CommandName
);
186 SHELL_FREE_NON_NULL(CommandHandleList
);
192 Attempt to print help from a dynamically added command.
194 @param[in] CommandToGetHelpOn The unicode name of the command that help is
196 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
197 @param[in] PrintCommandText Print the command followed by the help content
200 @retval EFI_SUCCESS The help was displayed
201 @retval EFI_NOT_FOUND The command name could not be found
202 @retval EFI_DEVICE_ERROR The help data format was incorrect.
205 PrintDynamicCommandHelp(
206 IN CONST CHAR16
*CommandToGetHelpOn
,
207 IN CONST CHAR16
*SectionToGetHelpOn
,
208 IN BOOLEAN PrintCommandText
213 EFI_HANDLE
*CommandHandleList
;
214 EFI_HANDLE
*NextCommand
;
215 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
217 Status
= EFI_NOT_FOUND
;
219 CommandHandleList
= NULL
;
221 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
223 if (CommandHandleList
== NULL
) {
225 // not found or out of resources
230 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
231 Status
= gBS
->HandleProtocol(
233 &gEfiShellDynamicCommandProtocolGuid
,
234 (VOID
**)&DynamicCommand
237 if (EFI_ERROR(Status
)) {
242 // Check execution break flag when printing multiple command help information.
244 if (ShellGetExecutionBreakFlag ()) {
248 if ((gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)CommandToGetHelpOn
)) ||
249 (gEfiShellProtocol
->GetAlias (CommandToGetHelpOn
, NULL
) != NULL
&& (gUnicodeCollation
->MetaiMatch (gUnicodeCollation
, (CHAR16
*)DynamicCommand
->CommandName
, (CHAR16
*)(gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
)))))) {
250 // Print as Shell Help if in ManPage format.
251 Status
= ShellPrintHelp (DynamicCommand
->CommandName
, SectionToGetHelpOn
,
253 if (Status
== EFI_DEVICE_ERROR
) {
254 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
),
255 gShellLevel3HiiHandle
, DynamicCommand
->CommandName
);
256 } else if (EFI_ERROR(Status
)) {
257 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
),
258 gShellLevel3HiiHandle
, DynamicCommand
->CommandName
);
265 SHELL_FREE_NON_NULL(CommandHandleList
);
267 return (Found
? EFI_SUCCESS
: Status
);
271 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
272 {L
"-usage", TypeFlag
},
273 {L
"-section", TypeMaxValue
},
274 {L
"-verbose", TypeFlag
},
280 Function for 'help' command.
282 @param[in] ImageHandle Handle to the Image (NULL if Internal).
283 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
287 ShellCommandRunHelp (
288 IN EFI_HANDLE ImageHandle
,
289 IN EFI_SYSTEM_TABLE
*SystemTable
294 CHAR16
*ProblemParam
;
295 SHELL_STATUS ShellStatus
;
296 CHAR16
*SortedCommandList
;
297 CONST CHAR16
*CurrentCommand
;
298 CHAR16
*CommandToGetHelpOn
;
299 CHAR16
*SectionToGetHelpOn
;
302 BOOLEAN PrintCommandText
;
303 UINTN SortedCommandListSize
;
305 PrintCommandText
= TRUE
;
307 ShellStatus
= SHELL_SUCCESS
;
308 CommandToGetHelpOn
= NULL
;
309 SectionToGetHelpOn
= NULL
;
310 SortedCommandList
= NULL
;
314 // initialize the shell lib (we must be in non-auto-init...)
316 Status
= ShellInitialize();
317 ASSERT_EFI_ERROR(Status
);
319 Status
= CommandInit();
320 ASSERT_EFI_ERROR(Status
);
323 // parse the command line
325 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
326 if (EFI_ERROR(Status
)) {
327 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
328 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel3HiiHandle
, L
"help", ProblemParam
);
329 FreePool(ProblemParam
);
330 ShellStatus
= SHELL_INVALID_PARAMETER
;
336 // Check for conflicting parameters.
338 if (ShellCommandLineGetFlag(Package
, L
"-usage")
339 &&ShellCommandLineGetFlag(Package
, L
"-section")
340 &&(ShellCommandLineGetFlag(Package
, L
"-verbose") || ShellCommandLineGetFlag(Package
, L
"-v"))
342 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_CON
), gShellLevel3HiiHandle
, L
"help");
343 ShellStatus
= SHELL_INVALID_PARAMETER
;
344 } else if (ShellCommandLineGetRawValue(Package
, 2) != NULL
) {
345 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel3HiiHandle
, L
"help");
346 ShellStatus
= SHELL_INVALID_PARAMETER
;
349 // Get the command name we are getting help on
351 ASSERT(CommandToGetHelpOn
== NULL
);
352 StrnCatGrow(&CommandToGetHelpOn
, NULL
, ShellCommandLineGetRawValue(Package
, 1), 0);
353 if (CommandToGetHelpOn
== NULL
&& ShellCommandLineGetFlag(Package
, L
"-?")) {
355 // If we dont have a command and we got a simple -?
356 // we are looking for help on help command.
358 StrnCatGrow(&CommandToGetHelpOn
, NULL
, L
"help", 0);
361 if (CommandToGetHelpOn
== NULL
) {
362 StrnCatGrow(&CommandToGetHelpOn
, NULL
, L
"*", 0);
363 ASSERT(SectionToGetHelpOn
== NULL
);
364 StrnCatGrow(&SectionToGetHelpOn
, NULL
, L
"NAME", 0);
366 PrintCommandText
= FALSE
;
367 ASSERT(SectionToGetHelpOn
== NULL
);
369 // Get the section name for the given command name
371 if (ShellCommandLineGetFlag(Package
, L
"-section")) {
372 StrnCatGrow(&SectionToGetHelpOn
, NULL
, ShellCommandLineGetValue(Package
, L
"-section"), 0);
373 } else if (ShellCommandLineGetFlag(Package
, L
"-usage")) {
374 StrnCatGrow(&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS", 0);
375 } else if (ShellCommandLineGetFlag(Package
, L
"-verbose") || ShellCommandLineGetFlag(Package
, L
"-v")) {
378 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
380 StrnCatGrow (&SectionToGetHelpOn
, NULL
, L
"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
384 if (gUnicodeCollation
->StriColl(gUnicodeCollation
, CommandToGetHelpOn
, L
"special") == 0) {
386 // we need info on the special characters
388 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_SC_HEADER
), gShellLevel3HiiHandle
);
389 HiiString
= HiiGetString(gShellLevel3HiiHandle
, STRING_TOKEN(STR_HELP_SC_DATA
), NULL
);
390 ShellPrintEx(-1, -1, L
"%s", HiiString
);
394 SortedCommandList
= NULL
;
395 SortedCommandListSize
= 0;
396 CopyListOfCommandNames(&SortedCommandList
, &SortedCommandListSize
, ShellCommandGetCommandList(TRUE
));
397 CopyListOfCommandNamesWithDynamic(&SortedCommandList
, &SortedCommandListSize
);
399 for (CurrentCommand
= SortedCommandList
400 ; CurrentCommand
!= NULL
&& *CurrentCommand
!= CHAR_NULL
&& CurrentCommand
< SortedCommandList
+ SortedCommandListSize
/sizeof(CHAR16
)
401 ; CurrentCommand
+= StrLen(CurrentCommand
) + 1
404 // Checking execution break flag when print multiple command help information.
406 if (ShellGetExecutionBreakFlag ()) {
410 if ((gUnicodeCollation
->MetaiMatch(gUnicodeCollation
, (CHAR16
*)CurrentCommand
, CommandToGetHelpOn
)) ||
411 (gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
) != NULL
&& (gUnicodeCollation
->MetaiMatch(gUnicodeCollation
, (CHAR16
*)CurrentCommand
, (CHAR16
*)(gEfiShellProtocol
->GetAlias(CommandToGetHelpOn
, NULL
)))))) {
413 // We have a command to look for help on.
415 Status
= ShellPrintHelp(CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
416 if (EFI_ERROR(Status
)) {
418 // now try to match against the dynamic command list and print help
420 Status
= PrintDynamicCommandHelp (CurrentCommand
, SectionToGetHelpOn
, PrintCommandText
);
422 if (Status
== EFI_DEVICE_ERROR
) {
423 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CurrentCommand
);
424 } else if (EFI_ERROR(Status
)) {
425 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CurrentCommand
);
433 // Search the .man file for Shell applications (Shell external commands).
436 Status
= ShellPrintHelp(CommandToGetHelpOn
, SectionToGetHelpOn
, FALSE
);
437 if (Status
== EFI_DEVICE_ERROR
) {
438 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_INV
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
439 } else if (EFI_ERROR(Status
)) {
440 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_NF
), gShellLevel3HiiHandle
, CommandToGetHelpOn
);
448 ShellStatus
= SHELL_NOT_FOUND
;
452 // free the command line package
454 ShellCommandLineFreeVarList (Package
);
458 if (CommandToGetHelpOn
!= NULL
&& StrCmp(CommandToGetHelpOn
, L
"*") == 0){
460 // If '*' then the command entered was 'Help' without qualifiers, This footer
461 // provides additional info on help switches
463 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_HELP_FOOTER
), gShellLevel3HiiHandle
);
465 if (CommandToGetHelpOn
!= NULL
) {
466 FreePool(CommandToGetHelpOn
);
468 if (SectionToGetHelpOn
!= NULL
) {
469 FreePool(SectionToGetHelpOn
);
471 SHELL_FREE_NON_NULL(SortedCommandList
);
473 return (ShellStatus
);