]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c
ShellPkg: Fix dynamic command help
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel3CommandsLib / Help.c
1 /** @file
2 Main file for Help shell level 3 function.
3
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
5 Copyright (c) 2014, ARM Limited. All rights reserved. <BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UefiShellLevel3CommandsLib.h"
17
18 #include <Library/ShellLib.h>
19 #include <Library/HandleParsingLib.h>
20
21 #include <Protocol/EfiShellDynamicCommand.h>
22
23 /**
24 Attempt to print help from a dynamically added command.
25
26 @param[in] CommandToGetHelpOn The unicode name of the command that help is
27 requested on.
28 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
29 @param[in] PrintCommandText Print the command followed by the help content
30 or just help.
31
32 @retval EFI_SUCCESS The help was displayed
33 @retval EFI_NOT_FOUND The command name could not be found
34 @retval EFI_DEVICE_ERROR The help data format was incorrect.
35 **/
36 EFI_STATUS
37 EFIAPI
38 PrintDynamicCommandHelp(
39 IN CHAR16 *CommandToGetHelpOn,
40 IN CHAR16 *SectionToGetHelpOn,
41 IN BOOLEAN PrintCommandText
42 )
43 {
44 EFI_STATUS Status;
45 BOOLEAN Found;
46 EFI_HANDLE *CommandHandleList;
47 EFI_HANDLE *NextCommand;
48 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
49
50 Status = EFI_NOT_FOUND;
51 Found = FALSE;
52 CommandHandleList = NULL;
53
54 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);
55
56 if (CommandHandleList == NULL) {
57 //
58 // not found or out of resources
59 //
60 return Status;
61 }
62
63 for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {
64 Status = gBS->HandleProtocol(
65 *NextCommand,
66 &gEfiShellDynamicCommandProtocolGuid,
67 (VOID **)&DynamicCommand
68 );
69
70 if (EFI_ERROR(Status)) {
71 continue;
72 }
73
74 //
75 // Check execution break flag when printing multiple command help information.
76 //
77 if (ShellGetExecutionBreakFlag ()) {
78 break;
79 }
80
81 if ((gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, CommandToGetHelpOn)) ||
82 (gEfiShellProtocol->GetAlias (CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) {
83 // Print as Shell Help if in ManPage format.
84 Status = ShellPrintHelp (DynamicCommand->CommandName, SectionToGetHelpOn,
85 PrintCommandText);
86 if (Status == EFI_DEVICE_ERROR) {
87 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_INV),
88 gShellLevel3HiiHandle, DynamicCommand->CommandName);
89 } else if (EFI_ERROR(Status)) {
90 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_NF),
91 gShellLevel3HiiHandle, DynamicCommand->CommandName);
92 } else {
93 Found = TRUE;
94 }
95 }
96 }
97
98 return (Found ? EFI_SUCCESS : Status);
99
100 }
101
102 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
103 {L"-usage", TypeFlag},
104 {L"-section", TypeMaxValue},
105 {L"-verbose", TypeFlag},
106 {L"-v", TypeFlag},
107 {NULL, TypeMax}
108 };
109
110 /**
111 Function for 'help' command.
112
113 @param[in] ImageHandle Handle to the Image (NULL if Internal).
114 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
115 **/
116 SHELL_STATUS
117 EFIAPI
118 ShellCommandRunHelp (
119 IN EFI_HANDLE ImageHandle,
120 IN EFI_SYSTEM_TABLE *SystemTable
121 )
122 {
123 EFI_STATUS Status;
124 LIST_ENTRY *Package;
125 CHAR16 *ProblemParam;
126 SHELL_STATUS ShellStatus;
127 CONST COMMAND_LIST *CommandList;
128 CONST COMMAND_LIST *Node;
129 CHAR16 *CommandToGetHelpOn;
130 CHAR16 *SectionToGetHelpOn;
131 CHAR16 *HiiString;
132 BOOLEAN Found;
133 BOOLEAN PrintCommandText;
134
135 PrintCommandText = TRUE;
136 ProblemParam = NULL;
137 ShellStatus = SHELL_SUCCESS;
138 CommandToGetHelpOn = NULL;
139 SectionToGetHelpOn = NULL;
140 Found = FALSE;
141
142 //
143 // initialize the shell lib (we must be in non-auto-init...)
144 //
145 Status = ShellInitialize();
146 ASSERT_EFI_ERROR(Status);
147
148 Status = CommandInit();
149 ASSERT_EFI_ERROR(Status);
150
151 //
152 // parse the command line
153 //
154 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
155 if (EFI_ERROR(Status)) {
156 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
157 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam);
158 FreePool(ProblemParam);
159 ShellStatus = SHELL_INVALID_PARAMETER;
160 } else {
161 ASSERT(FALSE);
162 }
163 } else {
164 //
165 // Check for conflicting parameters.
166 //
167 if (ShellCommandLineGetFlag(Package, L"-usage")
168 &&ShellCommandLineGetFlag(Package, L"-section")
169 &&(ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v"))
170 ){
171 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel3HiiHandle);
172 ShellStatus = SHELL_INVALID_PARAMETER;
173 } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
174 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle);
175 ShellStatus = SHELL_INVALID_PARAMETER;
176 } else {
177 //
178 // Get the command name we are getting help on
179 //
180 ASSERT(CommandToGetHelpOn == NULL);
181 StrnCatGrow(&CommandToGetHelpOn, NULL, ShellCommandLineGetRawValue(Package, 1), 0);
182 if (CommandToGetHelpOn == NULL && ShellCommandLineGetFlag(Package, L"-?")) {
183 //
184 // If we dont have a command and we got a simple -?
185 // we are looking for help on help command.
186 //
187 StrnCatGrow(&CommandToGetHelpOn, NULL, L"help", 0);
188 }
189
190 if (CommandToGetHelpOn == NULL) {
191 StrnCatGrow(&CommandToGetHelpOn, NULL, L"*", 0);
192 ASSERT(SectionToGetHelpOn == NULL);
193 StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME", 0);
194 } else {
195 PrintCommandText = FALSE;
196 ASSERT(SectionToGetHelpOn == NULL);
197 //
198 // Get the section name for the given command name
199 //
200 if (ShellCommandLineGetFlag(Package, L"-section")) {
201 StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0);
202 } else if (ShellCommandLineGetFlag(Package, L"-usage")) {
203 StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0);
204 } else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) {
205 } else {
206 //
207 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
208 //
209 StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
210 }
211 }
212
213 if (gUnicodeCollation->StriColl(gUnicodeCollation, CommandToGetHelpOn, L"special") == 0) {
214 //
215 // we need info on the special characters
216 //
217 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_HEADER), gShellLevel3HiiHandle);
218 HiiString = HiiGetString(gShellLevel3HiiHandle, STRING_TOKEN(STR_HELP_SC_DATA), NULL);
219 ShellPrintEx(-1, -1, L"%s", HiiString);
220 FreePool(HiiString);
221 Found = TRUE;
222 } else {
223 CommandList = ShellCommandGetCommandList(TRUE);
224 ASSERT(CommandList != NULL);
225 for ( Node = (COMMAND_LIST*)GetFirstNode(&CommandList->Link)
226 ; CommandList != NULL && !IsListEmpty(&CommandList->Link) && !IsNull(&CommandList->Link, &Node->Link)
227 ; Node = (COMMAND_LIST*)GetNextNode(&CommandList->Link, &Node->Link)
228 ){
229 //
230 // Checking execution break flag when print multiple command help information.
231 //
232 if (ShellGetExecutionBreakFlag ()) {
233 break;
234 }
235 if ((gUnicodeCollation->MetaiMatch(gUnicodeCollation, Node->CommandString, CommandToGetHelpOn)) ||
236 (gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch(gUnicodeCollation, Node->CommandString, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) {
237 //
238 // We have a command to look for help on.
239 //
240 Status = ShellPrintHelp(Node->CommandString, SectionToGetHelpOn, PrintCommandText);
241 if (Status == EFI_DEVICE_ERROR) {
242 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, Node->CommandString);
243 } else if (EFI_ERROR(Status)) {
244 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, Node->CommandString);
245 } else {
246 Found = TRUE;
247 }
248 }
249 }
250
251 //
252 // now try to match against the dynamic command list and print help
253 //
254 Status = PrintDynamicCommandHelp (CommandToGetHelpOn, SectionToGetHelpOn,
255 PrintCommandText);
256 if (!EFI_ERROR(Status)) {
257 Found = TRUE;
258 }
259
260 //
261 // Search the .man file for Shell applications (Shell external commands).
262 //
263 if (!Found) {
264 Status = ShellPrintHelp(CommandToGetHelpOn, SectionToGetHelpOn, FALSE);
265 if (Status == EFI_DEVICE_ERROR) {
266 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CommandToGetHelpOn);
267 } else if (EFI_ERROR(Status)) {
268 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CommandToGetHelpOn);
269 } else {
270 Found = TRUE;
271 }
272 }
273 }
274
275 if (!Found) {
276 ShellStatus = SHELL_NOT_FOUND;
277 }
278
279 //
280 // free the command line package
281 //
282 ShellCommandLineFreeVarList (Package);
283 }
284 }
285
286 if (CommandToGetHelpOn != NULL && StrCmp(CommandToGetHelpOn, L"*") == 0){
287 //
288 // If '*' then the command entered was 'Help' without qualifiers, This footer
289 // provides additional info on help switches
290 //
291 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_FOOTER), gShellLevel3HiiHandle);
292 }
293 if (CommandToGetHelpOn != NULL) {
294 FreePool(CommandToGetHelpOn);
295 }
296 if (SectionToGetHelpOn != NULL) {
297 FreePool(SectionToGetHelpOn);
298 }
299
300 return (ShellStatus);
301 }