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