VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c

Last change on this file was 108794, checked in by vboxsync, 3 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 15.7 KB
Line 
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**/
33EFI_STATUS
34LexicalInsertIntoList (
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**/
112EFI_STATUS
113CopyListOfCommandNames (
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**/
143STATIC
144EFI_STATUS
145CopyListOfCommandNamesWithDynamic (
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**/
200EFI_STATUS
201PrintDynamicCommandHelp (
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
282STATIC 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**/
296SHELL_STATUS
297EFIAPI
298ShellCommandRunHelp (
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 BOOLEAN Found;
312 BOOLEAN PrintCommandText;
313 UINTN SortedCommandListSize;
314
315 PrintCommandText = TRUE;
316 ProblemParam = NULL;
317 ShellStatus = SHELL_SUCCESS;
318 CommandToGetHelpOn = NULL;
319 SectionToGetHelpOn = NULL;
320 SortedCommandList = NULL;
321 Found = FALSE;
322
323 //
324 // initialize the shell lib (we must be in non-auto-init...)
325 //
326 Status = ShellInitialize ();
327 ASSERT_EFI_ERROR (Status);
328
329 Status = CommandInit ();
330 ASSERT_EFI_ERROR (Status);
331
332 //
333 // parse the command line
334 //
335 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
336 if (EFI_ERROR (Status)) {
337 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
338 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"help", ProblemParam);
339 FreePool (ProblemParam);
340 ShellStatus = SHELL_INVALID_PARAMETER;
341 } else {
342 ASSERT (FALSE);
343 }
344 } else {
345 //
346 // Check for conflicting parameters.
347 //
348 if ( ShellCommandLineGetFlag (Package, L"-usage")
349 && ShellCommandLineGetFlag (Package, L"-section")
350 && (ShellCommandLineGetFlag (Package, L"-verbose") || ShellCommandLineGetFlag (Package, L"-v"))
351 )
352 {
353 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel3HiiHandle, L"help");
354 ShellStatus = SHELL_INVALID_PARAMETER;
355 } else if (ShellCommandLineGetRawValue (Package, 2) != NULL) {
356 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle, L"help");
357 ShellStatus = SHELL_INVALID_PARAMETER;
358 } else {
359 //
360 // Get the command name we are getting help on
361 //
362 ASSERT (CommandToGetHelpOn == NULL);
363 StrnCatGrow (&CommandToGetHelpOn, NULL, ShellCommandLineGetRawValue (Package, 1), 0);
364 if ((CommandToGetHelpOn == NULL) && ShellCommandLineGetFlag (Package, L"-?")) {
365 //
366 // If we dont have a command and we got a simple -?
367 // we are looking for help on help command.
368 //
369 StrnCatGrow (&CommandToGetHelpOn, NULL, L"help", 0);
370 }
371
372 if (CommandToGetHelpOn == NULL) {
373 StrnCatGrow (&CommandToGetHelpOn, NULL, L"*", 0);
374 ASSERT (SectionToGetHelpOn == NULL);
375 StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME", 0);
376 } else {
377 PrintCommandText = FALSE;
378 ASSERT (SectionToGetHelpOn == NULL);
379 //
380 // Get the section name for the given command name
381 //
382 if (ShellCommandLineGetFlag (Package, L"-section")) {
383 StrnCatGrow (&SectionToGetHelpOn, NULL, ShellCommandLineGetValue (Package, L"-section"), 0);
384 } else if (ShellCommandLineGetFlag (Package, L"-usage")) {
385 StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0);
386 } else if (ShellCommandLineGetFlag (Package, L"-verbose") || ShellCommandLineGetFlag (Package, L"-v")) {
387 } else {
388 //
389 // The output of help <command> will display NAME, SYNOPSIS, OPTIONS, DESCRIPTION, and EXAMPLES sections.
390 //
391 StrnCatGrow (&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS,OPTIONS,DESCRIPTION,EXAMPLES", 0);
392 }
393 }
394
395 if (gUnicodeCollation->StriColl (gUnicodeCollation, CommandToGetHelpOn, L"special") == 0) {
396 //
397 // we need info on the special characters
398 //
399 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_HEADER), gShellLevel3HiiHandle);
400 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_DATA), gShellLevel3HiiHandle);
401 Found = TRUE;
402 } else {
403 SortedCommandList = NULL;
404 SortedCommandListSize = 0;
405 CopyListOfCommandNames (&SortedCommandList, &SortedCommandListSize, ShellCommandGetCommandList (TRUE));
406 CopyListOfCommandNamesWithDynamic (&SortedCommandList, &SortedCommandListSize);
407
408 for (CurrentCommand = SortedCommandList
409 ; CurrentCommand != NULL && CurrentCommand < SortedCommandList + SortedCommandListSize/sizeof (CHAR16) && *CurrentCommand != CHAR_NULL
410 ; CurrentCommand += StrLen (CurrentCommand) + 1
411 )
412 {
413 //
414 // Checking execution break flag when print multiple command help information.
415 //
416 if (ShellGetExecutionBreakFlag ()) {
417 break;
418 }
419
420 if ((gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)CurrentCommand, CommandToGetHelpOn)) ||
421 ((gEfiShellProtocol->GetAlias (CommandToGetHelpOn, NULL) != NULL) && (gUnicodeCollation->MetaiMatch (gUnicodeCollation, (CHAR16 *)CurrentCommand, (CHAR16 *)(gEfiShellProtocol->GetAlias (CommandToGetHelpOn, NULL))))))
422 {
423 //
424 // We have a command to look for help on.
425 //
426 Status = ShellPrintHelp (CurrentCommand, SectionToGetHelpOn, PrintCommandText);
427 if (EFI_ERROR (Status)) {
428 //
429 // now try to match against the dynamic command list and print help
430 //
431 Status = PrintDynamicCommandHelp (CurrentCommand, SectionToGetHelpOn, PrintCommandText);
432 }
433
434 if (Status == EFI_DEVICE_ERROR) {
435 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CurrentCommand);
436 } else if (EFI_ERROR (Status)) {
437 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CurrentCommand);
438 } else {
439 Found = TRUE;
440 }
441 }
442 }
443
444 //
445 // Search the .man file for Shell applications (Shell external commands).
446 //
447 if (!Found) {
448 Status = ShellPrintHelp (CommandToGetHelpOn, SectionToGetHelpOn, FALSE);
449 if (Status == EFI_DEVICE_ERROR) {
450 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_INV), gShellLevel3HiiHandle, CommandToGetHelpOn);
451 } else if (EFI_ERROR (Status)) {
452 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CommandToGetHelpOn);
453 } else {
454 Found = TRUE;
455 }
456 }
457 }
458
459 if (!Found) {
460 ShellStatus = SHELL_NOT_FOUND;
461 }
462
463 //
464 // free the command line package
465 //
466 ShellCommandLineFreeVarList (Package);
467 }
468 }
469
470 if ((CommandToGetHelpOn != NULL) && (StrCmp (CommandToGetHelpOn, L"*") == 0)) {
471 //
472 // If '*' then the command entered was 'Help' without qualifiers, This footer
473 // provides additional info on help switches
474 //
475 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HELP_FOOTER), gShellLevel3HiiHandle);
476 }
477
478 if (CommandToGetHelpOn != NULL) {
479 FreePool (CommandToGetHelpOn);
480 }
481
482 if (SectionToGetHelpOn != NULL) {
483 FreePool (SectionToGetHelpOn);
484 }
485
486 SHELL_FREE_NON_NULL (SortedCommandList);
487
488 return (ShellStatus);
489}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette