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