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