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