]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c
ShellPkg: Update help output for correct alphabetical
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel3CommandsLib / Help.c
1 /** @file
2 Main file for Help shell level 3 function.
3
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>
7
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
12
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.
15
16 **/
17
18 #include "UefiShellLevel3CommandsLib.h"
19
20 #include <Library/ShellLib.h>
21 #include <Library/HandleParsingLib.h>
22
23 #include <Protocol/EfiShellDynamicCommand.h>
24
25 /**
26 function to insert string items into a list in the correct alphabetical place
27
28 the resultant list is a double NULL terminated list of NULL terminated strings.
29
30 upon successful return the memory must be caller freed (unless passed back in
31 via a loop where it will get reallocated).
32
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.
36
37 @retval EFI_SUCCESS the operation was successful.
38 **/
39 EFI_STATUS
40 EFIAPI
41 LexicalInsertIntoList(
42 IN OUT CHAR16 **DestList,
43 IN OUT UINTN *DestSize,
44 IN CONST CHAR16 *Item
45 )
46 {
47 CHAR16 *NewList;
48 INTN LexicalMatchValue;
49 CHAR16 *LexicalSpot;
50 UINTN SizeOfAddedNameInBytes;
51
52 //
53 // If there are none, then just return with success
54 //
55 if (Item == NULL || *Item == CHAR_NULL || StrLen(Item)==0) {
56 return (EFI_SUCCESS);
57 }
58
59 NewList = *DestList;
60
61 SizeOfAddedNameInBytes = StrSize(Item);
62 NewList = ReallocatePool(*DestSize, (*DestSize) + SizeOfAddedNameInBytes, NewList);
63 (*DestSize) = (*DestSize) + SizeOfAddedNameInBytes;
64
65 //
66 // Find the correct spot in the list
67 //
68 for (LexicalSpot = NewList
69 ; LexicalSpot != NULL && LexicalSpot < NewList + (*DestSize)
70 ; LexicalSpot += StrLen(LexicalSpot) + 1
71 ) {
72 //
73 // Get Lexical Comparison Value between PrevCommand and Command list entry
74 //
75 LexicalMatchValue = gUnicodeCollation->StriColl (
76 gUnicodeCollation,
77 (CHAR16 *)LexicalSpot,
78 (CHAR16 *)Item
79 );
80 //
81 // The new item goes before this one.
82 //
83 if (LexicalMatchValue > 0 || StrLen(LexicalSpot) == 0) {
84 if (StrLen(LexicalSpot) != 0) {
85 //
86 // Move this and all other items out of the way
87 //
88 CopyMem(
89 LexicalSpot + (SizeOfAddedNameInBytes/sizeof(CHAR16)),
90 LexicalSpot,
91 (*DestSize) - SizeOfAddedNameInBytes - ((LexicalSpot - NewList) * sizeof(CHAR16))
92 );
93 }
94
95 //
96 // Stick this one in place
97 //
98 StrCpyS(LexicalSpot, SizeOfAddedNameInBytes/sizeof(CHAR16), Item);
99 break;
100 }
101 }
102
103 *DestList = NewList;
104 return (EFI_SUCCESS);
105 }
106
107 /**
108 function to add each command name from the linked list to the string list.
109
110 the resultant list is a double NULL terminated list of NULL terminated strings.
111
112 @param[in,out] DestList double pointer to the list. may be NULL.
113 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
114 @param[in] SourceList the double linked list of commands.
115
116 @retval EFI_SUCCESS the operation was successful.
117 **/
118 EFI_STATUS
119 EFIAPI
120 CopyListOfCommandNames(
121 IN OUT CHAR16 **DestList,
122 IN OUT UINTN *DestSize,
123 IN CONST COMMAND_LIST *SourceList
124 )
125 {
126 CONST COMMAND_LIST *Node;
127
128 for ( Node = (COMMAND_LIST*)GetFirstNode(&SourceList->Link)
129 ; SourceList != NULL && !IsListEmpty(&SourceList->Link) && !IsNull(&SourceList->Link, &Node->Link)
130 ; Node = (COMMAND_LIST*)GetNextNode(&SourceList->Link, &Node->Link)
131 ) {
132 LexicalInsertIntoList(DestList, DestSize, Node->CommandString);
133 }
134 return (EFI_SUCCESS);
135 }
136
137 /**
138 function to add each dynamic command name to the string list.
139
140 the resultant list is a double NULL terminated list of NULL terminated strings.
141
142 @param[in,out] DestList double pointer to the list. may be NULL.
143 @param[in,out] DestSize pointer to the size of list. may be 0, if DestList is NULL.
144
145 @retval EFI_SUCCESS the operation was successful.
146 @return an error from HandleProtocol
147 **/
148 STATIC
149 EFI_STATUS
150 EFIAPI
151 CopyListOfCommandNamesWithDynamic(
152 IN OUT CHAR16** DestList,
153 IN OUT UINTN *DestSize
154 )
155 {
156 EFI_HANDLE *CommandHandleList;
157 CONST EFI_HANDLE *NextCommand;
158 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
159 EFI_STATUS Status;
160
161 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);
162
163 //
164 // If there are none, then just return with success
165 //
166 if (CommandHandleList == NULL) {
167 return (EFI_SUCCESS);
168 }
169
170 Status = EFI_SUCCESS;
171
172 //
173 // Append those to the list.
174 //
175 for (NextCommand = CommandHandleList ; *NextCommand != NULL && !EFI_ERROR(Status) ; NextCommand++) {
176 Status = gBS->HandleProtocol(
177 *NextCommand,
178 &gEfiShellDynamicCommandProtocolGuid,
179 (VOID **)&DynamicCommand
180 );
181
182 if (EFI_ERROR(Status)) {
183 continue;
184 }
185
186 Status = LexicalInsertIntoList(DestList, DestSize, DynamicCommand->CommandName);
187 }
188
189 SHELL_FREE_NON_NULL(CommandHandleList);
190 return (Status);
191 }
192
193
194 /**
195 Attempt to print help from a dynamically added command.
196
197 @param[in] CommandToGetHelpOn The unicode name of the command that help is
198 requested on.
199 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
200 @param[in] PrintCommandText Print the command followed by the help content
201 or just help.
202
203 @retval EFI_SUCCESS The help was displayed
204 @retval EFI_NOT_FOUND The command name could not be found
205 @retval EFI_DEVICE_ERROR The help data format was incorrect.
206 **/
207 EFI_STATUS
208 EFIAPI
209 PrintDynamicCommandHelp(
210 IN CONST CHAR16 *CommandToGetHelpOn,
211 IN CONST CHAR16 *SectionToGetHelpOn,
212 IN BOOLEAN PrintCommandText
213 )
214 {
215 EFI_STATUS Status;
216 BOOLEAN Found;
217 EFI_HANDLE *CommandHandleList;
218 EFI_HANDLE *NextCommand;
219 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
220
221 Status = EFI_NOT_FOUND;
222 Found = FALSE;
223 CommandHandleList = NULL;
224
225 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);
226
227 if (CommandHandleList == NULL) {
228 //
229 // not found or out of resources
230 //
231 return Status;
232 }
233
234 for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {
235 Status = gBS->HandleProtocol(
236 *NextCommand,
237 &gEfiShellDynamicCommandProtocolGuid,
238 (VOID **)&DynamicCommand
239 );
240
241 if (EFI_ERROR(Status)) {
242 continue;
243 }
244
245 //
246 // Check execution break flag when printing multiple command help information.
247 //
248 if (ShellGetExecutionBreakFlag ()) {
249 break;
250 }
251
252 if ((gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, (CHAR16*)CommandToGetHelpOn)) ||
253 (gEfiShellProtocol->GetAlias (CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)DynamicCommand->CommandName, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) {
254 // Print as Shell Help if in ManPage format.
255 Status = ShellPrintHelp (DynamicCommand->CommandName, SectionToGetHelpOn,
256 PrintCommandText);
257 if (Status == EFI_DEVICE_ERROR) {
258 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_INV),
259 gShellLevel3HiiHandle, DynamicCommand->CommandName);
260 } else if (EFI_ERROR(Status)) {
261 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_NF),
262 gShellLevel3HiiHandle, DynamicCommand->CommandName);
263 } else {
264 Found = TRUE;
265 }
266 }
267 }
268
269 SHELL_FREE_NON_NULL(CommandHandleList);
270
271 return (Found ? EFI_SUCCESS : Status);
272
273 }
274
275 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
276 {L"-usage", TypeFlag},
277 {L"-section", TypeMaxValue},
278 {L"-verbose", TypeFlag},
279 {L"-v", TypeFlag},
280 {NULL, TypeMax}
281 };
282
283 /**
284 Function for 'help' command.
285
286 @param[in] ImageHandle Handle to the Image (NULL if Internal).
287 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
288 **/
289 SHELL_STATUS
290 EFIAPI
291 ShellCommandRunHelp (
292 IN EFI_HANDLE ImageHandle,
293 IN EFI_SYSTEM_TABLE *SystemTable
294 )
295 {
296 EFI_STATUS Status;
297 LIST_ENTRY *Package;
298 CHAR16 *ProblemParam;
299 SHELL_STATUS ShellStatus;
300 CHAR16 *SortedCommandList;
301 CONST CHAR16 *CurrentCommand;
302 CHAR16 *CommandToGetHelpOn;
303 CHAR16 *SectionToGetHelpOn;
304 CHAR16 *HiiString;
305 BOOLEAN Found;
306 BOOLEAN PrintCommandText;
307 UINTN SortedCommandListSize;
308
309 PrintCommandText = TRUE;
310 ProblemParam = NULL;
311 ShellStatus = SHELL_SUCCESS;
312 CommandToGetHelpOn = NULL;
313 SectionToGetHelpOn = NULL;
314 Found = FALSE;
315
316 //
317 // initialize the shell lib (we must be in non-auto-init...)
318 //
319 Status = ShellInitialize();
320 ASSERT_EFI_ERROR(Status);
321
322 Status = CommandInit();
323 ASSERT_EFI_ERROR(Status);
324
325 //
326 // parse the command line
327 //
328 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
329 if (EFI_ERROR(Status)) {
330 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
331 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"help", ProblemParam);
332 FreePool(ProblemParam);
333 ShellStatus = SHELL_INVALID_PARAMETER;
334 } else {
335 ASSERT(FALSE);
336 }
337 } else {
338 //
339 // Check for conflicting parameters.
340 //
341 if (ShellCommandLineGetFlag(Package, L"-usage")
342 &&ShellCommandLineGetFlag(Package, L"-section")
343 &&(ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v"))
344 ){
345 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel3HiiHandle, L"help");
346 ShellStatus = SHELL_INVALID_PARAMETER;
347 } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
348 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"help");
349 ShellStatus = SHELL_INVALID_PARAMETER;
350 } else {
351 //
352 // Get the command name we are getting help on
353 //
354 ASSERT(CommandToGetHelpOn == NULL);
355 StrnCatGrow(&CommandToGetHelpOn, NULL, ShellCommandLineGetRawValue(Package, 1), 0);
356 if (CommandToGetHelpOn == NULL && ShellCommandLineGetFlag(Package, L"-?")) {
357 //
358 // If we dont have a command and we got a simple -?
359 // we are looking for help on help command.
360 //
361 StrnCatGrow(&CommandToGetHelpOn, NULL, L"help", 0);
362 }
363
364 if (CommandToGetHelpOn == NULL) {
365 StrnCatGrow(&CommandToGetHelpOn, NULL, L"*", 0);
366 ASSERT(SectionToGetHelpOn == NULL);
367 StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME", 0);
368 } else {
369 PrintCommandText = FALSE;
370 ASSERT(SectionToGetHelpOn == NULL);
371 //
372 // Get the section name for the given command name
373 //
374 if (ShellCommandLineGetFlag(Package, L"-section")) {
375 StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0);
376 } else if (ShellCommandLineGetFlag(Package, L"-usage")) {
377 StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0);
378 } else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) {
379 } else {
380 //
381 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
382 //
383 StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
384 }
385 }
386
387 if (gUnicodeCollation->StriColl(gUnicodeCollation, CommandToGetHelpOn, L"special") == 0) {
388 //
389 // we need info on the special characters
390 //
391 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_HEADER), gShellLevel3HiiHandle);
392 HiiString = HiiGetString(gShellLevel3HiiHandle, STRING_TOKEN(STR_HELP_SC_DATA), NULL);
393 ShellPrintEx(-1, -1, L"%s", HiiString);
394 FreePool(HiiString);
395 Found = TRUE;
396 } else {
397 SortedCommandList = NULL;
398 SortedCommandListSize = 0;
399 CopyListOfCommandNames(&SortedCommandList, &SortedCommandListSize, ShellCommandGetCommandList(TRUE));
400 CopyListOfCommandNamesWithDynamic(&SortedCommandList, &SortedCommandListSize);
401
402 for (CurrentCommand = SortedCommandList
403 ; CurrentCommand != NULL && *CurrentCommand != CHAR_NULL && CurrentCommand < SortedCommandList + SortedCommandListSize/sizeof(CHAR16)
404 ; CurrentCommand += StrLen(CurrentCommand) + 1
405 ) {
406 //
407 // Checking execution break flag when print multiple command help information.
408 //
409 if (ShellGetExecutionBreakFlag ()) {
410 break;
411 }
412
413 if ((gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)CurrentCommand, CommandToGetHelpOn)) ||
414 (gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL) != NULL && (gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)CurrentCommand, (CHAR16*)(gEfiShellProtocol->GetAlias(CommandToGetHelpOn, NULL)))))) {
415 //
416 // We have a command to look for help on.
417 //
418 Status = ShellPrintHelp(CurrentCommand, SectionToGetHelpOn, PrintCommandText);
419 if (EFI_ERROR(Status)) {
420 //
421 // now try to match against the dynamic command list and print help
422 //
423 Status = PrintDynamicCommandHelp (CurrentCommand, SectionToGetHelpOn, PrintCommandText);
424 }
425 if (Status == EFI_DEVICE_ERROR) {
426 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CurrentCommand);
427 } else if (EFI_ERROR(Status)) {
428 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CurrentCommand);
429 } else {
430 Found = TRUE;
431 }
432 }
433 }
434
435 //
436 // Search the .man file for Shell applications (Shell external commands).
437 //
438 if (!Found) {
439 Status = ShellPrintHelp(CommandToGetHelpOn, SectionToGetHelpOn, FALSE);
440 if (Status == EFI_DEVICE_ERROR) {
441 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CommandToGetHelpOn);
442 } else if (EFI_ERROR(Status)) {
443 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CommandToGetHelpOn);
444 } else {
445 Found = TRUE;
446 }
447 }
448 }
449
450 if (!Found) {
451 ShellStatus = SHELL_NOT_FOUND;
452 }
453
454 //
455 // free the command line package
456 //
457 ShellCommandLineFreeVarList (Package);
458 }
459 }
460
461 if (CommandToGetHelpOn != NULL && StrCmp(CommandToGetHelpOn, L"*") == 0){
462 //
463 // If '*' then the command entered was 'Help' without qualifiers, This footer
464 // provides additional info on help switches
465 //
466 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_FOOTER), gShellLevel3HiiHandle);
467 }
468 if (CommandToGetHelpOn != NULL) {
469 FreePool(CommandToGetHelpOn);
470 }
471 if (SectionToGetHelpOn != NULL) {
472 FreePool(SectionToGetHelpOn);
473 }
474
475 return (ShellStatus);
476 }