]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
BaseTools: Add support for parseing map files generated by CLANG9 in GenFv
[mirror_edk2.git] / ShellPkg / Library / UefiShellCommandLib / UefiShellCommandLib.c
CommitLineData
a405b86d 1/** @file\r
2 Provides interface to shell internal functions for shell commands.\r
3\r
d65f2cea 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
cf041fd7
RN
5 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
7\r
56ba3746 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a405b86d 9\r
10**/\r
11\r
12#include "UefiShellCommandLib.h"\r
13\r
a405b86d 14// STATIC local variables\r
15STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;\r
16STATIC SCRIPT_FILE_LIST mScriptList;\r
17STATIC ALIAS_LIST mAliasList;\r
18STATIC BOOLEAN mEchoState;\r
19STATIC BOOLEAN mExitRequested;\r
b6b22b13 20STATIC UINT64 mExitCode;\r
a405b86d 21STATIC BOOLEAN mExitScript;\r
22STATIC CHAR16 *mProfileList;\r
23STATIC UINTN mProfileListSize;\r
24STATIC UINTN mFsMaxCount = 0;\r
25STATIC UINTN mBlkMaxCount = 0;\r
26STATIC BUFFER_LIST mFileHandleList;\r
27\r
3bd89603
LE
28STATIC CONST CHAR8 Hex[] = {\r
29 '0',\r
30 '1',\r
31 '2',\r
32 '3',\r
33 '4',\r
34 '5',\r
35 '6',\r
36 '7',\r
37 '8',\r
38 '9',\r
39 'A',\r
40 'B',\r
41 'C',\r
42 'D',\r
43 'E',\r
44 'F'\r
45};\r
46\r
a405b86d 47// global variables required by library class.\r
a405b86d 48EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;\r
a405b86d 49SHELL_MAP_LIST gShellMapList;\r
9cf45187 50SHELL_MAP_LIST *gShellCurMapping = NULL;\r
a405b86d 51\r
52CONST CHAR16* SupportLevel[] = {\r
53 L"Minimal",\r
54 L"Scripting",\r
55 L"Basic",\r
56 L"Interactive"\r
57};\r
58\r
59/**\r
60 Function to make sure that the global protocol pointers are valid.\r
61 must be called after constructor before accessing the pointers.\r
62**/\r
63EFI_STATUS\r
64EFIAPI\r
65CommandInit(\r
66 VOID\r
67 )\r
68{\r
d65f2cea
RN
69 UINTN NumHandles;\r
70 EFI_HANDLE *Handles;\r
71 EFI_UNICODE_COLLATION_PROTOCOL *Uc;\r
72 CHAR8 *BestLanguage;\r
73 UINTN Index;\r
74 EFI_STATUS Status;\r
75 CHAR8 *PlatformLang;\r
ba0014b9 76\r
a405b86d 77 if (gUnicodeCollation == NULL) {\r
8b8e9158
HS
78\r
79 GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME, (VOID**)&PlatformLang, NULL);\r
80\r
d65f2cea
RN
81 Status = gBS->LocateHandleBuffer (\r
82 ByProtocol,\r
83 &gEfiUnicodeCollation2ProtocolGuid,\r
84 NULL,\r
85 &NumHandles,\r
86 &Handles\r
87 );\r
88 if (EFI_ERROR (Status)) {\r
89 NumHandles = 0;\r
90 Handles = NULL;\r
91 }\r
92 for (Index = 0; Index < NumHandles; Index++) {\r
93 //\r
94 // Open Unicode Collation Protocol\r
95 //\r
96 Status = gBS->OpenProtocol (\r
97 Handles[Index],\r
98 &gEfiUnicodeCollation2ProtocolGuid,\r
99 (VOID **) &Uc,\r
100 gImageHandle,\r
101 NULL,\r
102 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
103 );\r
104 if (EFI_ERROR (Status)) {\r
105 continue;\r
106 }\r
107\r
8b8e9158
HS
108 //\r
109 // Without clue provided use the first Unicode Collation2 protocol.\r
110 //\r
111 if (PlatformLang == NULL) {\r
112 gUnicodeCollation = Uc;\r
113 break;\r
114 }\r
115\r
d65f2cea
RN
116 //\r
117 // Find the best matching matching language from the supported languages\r
ba0014b9 118 // of Unicode Collation2 protocol.\r
d65f2cea
RN
119 //\r
120 BestLanguage = GetBestLanguage (\r
121 Uc->SupportedLanguages,\r
122 FALSE,\r
123 PlatformLang,\r
124 NULL\r
125 );\r
126 if (BestLanguage != NULL) {\r
127 FreePool (BestLanguage);\r
128 gUnicodeCollation = Uc;\r
129 break;\r
130 }\r
131 }\r
132 if (Handles != NULL) {\r
133 FreePool (Handles);\r
a405b86d 134 }\r
8b8e9158
HS
135 if (PlatformLang != NULL) {\r
136 FreePool (PlatformLang);\r
137 }\r
a405b86d 138 }\r
d65f2cea
RN
139\r
140 return (gUnicodeCollation == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;\r
a405b86d 141}\r
142\r
143/**\r
144 Constructor for the Shell Command library.\r
145\r
146 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.\r
147\r
148 @param ImageHandle the image handle of the process\r
149 @param SystemTable the EFI System Table pointer\r
150\r
151 @retval EFI_SUCCESS the initialization was complete sucessfully\r
152**/\r
153RETURN_STATUS\r
154EFIAPI\r
155ShellCommandLibConstructor (\r
156 IN EFI_HANDLE ImageHandle,\r
157 IN EFI_SYSTEM_TABLE *SystemTable\r
158 )\r
159{\r
160 EFI_STATUS Status;\r
161 InitializeListHead(&gShellMapList.Link);\r
162 InitializeListHead(&mCommandList.Link);\r
163 InitializeListHead(&mAliasList.Link);\r
164 InitializeListHead(&mScriptList.Link);\r
165 InitializeListHead(&mFileHandleList.Link);\r
166 mEchoState = TRUE;\r
167\r
168 mExitRequested = FALSE;\r
169 mExitScript = FALSE;\r
170 mProfileListSize = 0;\r
171 mProfileList = NULL;\r
172\r
d65f2cea
RN
173 Status = CommandInit ();\r
174 if (EFI_ERROR (Status)) {\r
175 return EFI_DEVICE_ERROR;\r
a405b86d 176 }\r
177\r
178 return (RETURN_SUCCESS);\r
179}\r
180\r
4f67c7ff
JC
181/**\r
182 Frees list of file handles.\r
183\r
184 @param[in] List The list to free.\r
185**/\r
186VOID\r
4f67c7ff
JC
187FreeFileHandleList (\r
188 IN BUFFER_LIST *List\r
189 )\r
190{\r
191 BUFFER_LIST *BufferListEntry;\r
192\r
193 if (List == NULL){\r
194 return;\r
195 }\r
196 //\r
197 // enumerate through the buffer list and free all memory\r
198 //\r
199 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
200 ; !IsListEmpty (&List->Link)\r
201 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
202 ){\r
203 RemoveEntryList(&BufferListEntry->Link);\r
204 ASSERT(BufferListEntry->Buffer != NULL);\r
205 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);\r
206 SHELL_FREE_NON_NULL(BufferListEntry->Buffer);\r
207 SHELL_FREE_NON_NULL(BufferListEntry);\r
208 }\r
209}\r
210\r
a405b86d 211/**\r
212 Destructor for the library. free any resources.\r
213\r
214 @param ImageHandle the image handle of the process\r
215 @param SystemTable the EFI System Table pointer\r
216\r
217 @retval RETURN_SUCCESS this function always returns success\r
218**/\r
219RETURN_STATUS\r
220EFIAPI\r
221ShellCommandLibDestructor (\r
222 IN EFI_HANDLE ImageHandle,\r
223 IN EFI_SYSTEM_TABLE *SystemTable\r
224 )\r
225{\r
226 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
3f869579 227 ALIAS_LIST *Node2;\r
a405b86d 228 SCRIPT_FILE_LIST *Node3;\r
229 SHELL_MAP_LIST *MapNode;\r
230 //\r
231 // enumerate throught the list and free all the memory\r
232 //\r
233 while (!IsListEmpty (&mCommandList.Link)) {\r
234 Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);\r
235 RemoveEntryList(&Node->Link);\r
236 SHELL_FREE_NON_NULL(Node->CommandString);\r
237 FreePool(Node);\r
238 DEBUG_CODE(Node = NULL;);\r
239 }\r
240\r
241 //\r
3f869579 242 // enumerate through the alias list and free all memory\r
a405b86d 243 //\r
244 while (!IsListEmpty (&mAliasList.Link)) {\r
3f869579 245 Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);\r
a405b86d 246 RemoveEntryList(&Node2->Link);\r
247 SHELL_FREE_NON_NULL(Node2->CommandString);\r
3f869579 248 SHELL_FREE_NON_NULL(Node2->Alias);\r
249 SHELL_FREE_NON_NULL(Node2);\r
a405b86d 250 DEBUG_CODE(Node2 = NULL;);\r
251 }\r
252\r
253 //\r
254 // enumerate throught the list and free all the memory\r
255 //\r
256 while (!IsListEmpty (&mScriptList.Link)) {\r
257 Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
258 RemoveEntryList(&Node3->Link);\r
259 DeleteScriptFileStruct(Node3->Data);\r
260 FreePool(Node3);\r
261 }\r
262\r
263 //\r
264 // enumerate throught the mappings list and free all the memory\r
265 //\r
266 if (!IsListEmpty(&gShellMapList.Link)) {\r
267 for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
268 ; !IsListEmpty (&gShellMapList.Link)\r
269 ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
270 ){\r
271 ASSERT(MapNode != NULL);\r
272 RemoveEntryList(&MapNode->Link);\r
273 SHELL_FREE_NON_NULL(MapNode->DevicePath);\r
274 SHELL_FREE_NON_NULL(MapNode->MapName);\r
275 SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);\r
276 FreePool(MapNode);\r
277 }\r
278 }\r
279 if (!IsListEmpty(&mFileHandleList.Link)){\r
4f67c7ff 280 FreeFileHandleList(&mFileHandleList);\r
a405b86d 281 }\r
282\r
283 if (mProfileList != NULL) {\r
284 FreePool(mProfileList);\r
285 }\r
286\r
1a63ec8f 287 gUnicodeCollation = NULL;\r
9cf45187 288 gShellCurMapping = NULL;\r
1a63ec8f 289\r
a405b86d 290 return (RETURN_SUCCESS);\r
291}\r
292\r
293/**\r
f5ba4007 294 Find a dynamic command protocol instance given a command name string.\r
cf812a20
JC
295\r
296 @param CommandString the command name string\r
297\r
298 @return instance the command protocol instance, if dynamic command instance found\r
299 @retval NULL no dynamic command protocol instance found for name\r
300**/\r
301CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *\r
cf812a20
JC
302ShellCommandFindDynamicCommand (\r
303 IN CONST CHAR16 *CommandString\r
304 )\r
305{\r
306 EFI_STATUS Status;\r
307 EFI_HANDLE *CommandHandleList;\r
308 EFI_HANDLE *NextCommand;\r
309 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
310\r
311 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);\r
312 if (CommandHandleList == NULL) {\r
313 //\r
314 // not found or out of resources\r
315 //\r
ba0014b9 316 return NULL;\r
cf812a20
JC
317 }\r
318\r
319 for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {\r
320 Status = gBS->HandleProtocol(\r
321 *NextCommand,\r
322 &gEfiShellDynamicCommandProtocolGuid,\r
323 (VOID **)&DynamicCommand\r
324 );\r
325\r
326 if (EFI_ERROR(Status)) {\r
327 continue;\r
328 }\r
329\r
330 if (gUnicodeCollation->StriColl(\r
331 gUnicodeCollation,\r
332 (CHAR16*)CommandString,\r
ba0014b9 333 (CHAR16*)DynamicCommand->CommandName) == 0\r
cf812a20
JC
334 ){\r
335 FreePool(CommandHandleList);\r
336 return (DynamicCommand);\r
337 }\r
338 }\r
339\r
340 FreePool(CommandHandleList);\r
341 return (NULL);\r
342}\r
343\r
344/**\r
345 Checks if a command exists as a dynamic command protocol instance\r
a405b86d 346\r
347 @param[in] CommandString The command string to check for on the list.\r
348**/\r
349BOOLEAN\r
cf812a20
JC
350ShellCommandDynamicCommandExists (\r
351 IN CONST CHAR16 *CommandString\r
352 )\r
353{\r
f5ba4007 354 return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));\r
cf812a20
JC
355}\r
356\r
357/**\r
358 Checks if a command is already on the internal command list.\r
359\r
360 @param[in] CommandString The command string to check for on the list.\r
361**/\r
362BOOLEAN\r
cf812a20
JC
363ShellCommandIsCommandOnInternalList(\r
364 IN CONST CHAR16 *CommandString\r
a405b86d 365 )\r
366{\r
367 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
368\r
369 //\r
370 // assert for NULL parameter\r
371 //\r
372 ASSERT(CommandString != NULL);\r
373\r
374 //\r
375 // check for the command\r
376 //\r
377 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
378 ; !IsNull(&mCommandList.Link, &Node->Link)\r
379 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
380 ){\r
381 ASSERT(Node->CommandString != NULL);\r
382 if (gUnicodeCollation->StriColl(\r
383 gUnicodeCollation,\r
384 (CHAR16*)CommandString,\r
385 Node->CommandString) == 0\r
386 ){\r
387 return (TRUE);\r
388 }\r
389 }\r
390 return (FALSE);\r
391}\r
392\r
393/**\r
cf812a20
JC
394 Checks if a command exists, either internally or through the dynamic command protocol.\r
395\r
396 @param[in] CommandString The command string to check for on the list.\r
397**/\r
398BOOLEAN\r
399EFIAPI\r
400ShellCommandIsCommandOnList(\r
401 IN CONST CHAR16 *CommandString\r
402 )\r
403{\r
404 if (ShellCommandIsCommandOnInternalList(CommandString)) {\r
405 return TRUE;\r
406 }\r
407\r
408 return ShellCommandDynamicCommandExists(CommandString);\r
409}\r
410\r
411/**\r
412 Get the help text for a dynamic command.\r
413\r
414 @param[in] CommandString The command name.\r
415\r
416 @retval NULL No help text was found.\r
417 @return String of help text. Caller required to free.\r
418**/\r
419CHAR16*\r
cf812a20
JC
420ShellCommandGetDynamicCommandHelp(\r
421 IN CONST CHAR16 *CommandString\r
422 )\r
423{\r
424 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
425\r
426 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
427 if (DynamicCommand == NULL) {\r
428 return (NULL);\r
429 }\r
430\r
431 //\r
432 // TODO: how to get proper language?\r
433 //\r
ba0014b9 434 return DynamicCommand->GetHelp(DynamicCommand, "en");\r
cf812a20
JC
435}\r
436\r
437/**\r
438 Get the help text for an internal command.\r
a405b86d 439\r
440 @param[in] CommandString The command name.\r
441\r
442 @retval NULL No help text was found.\r
443 @return String of help text. Caller reuiqred to free.\r
444**/\r
445CHAR16*\r
cf812a20 446ShellCommandGetInternalCommandHelp(\r
a405b86d 447 IN CONST CHAR16 *CommandString\r
448 )\r
449{\r
450 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
451\r
452 //\r
453 // assert for NULL parameter\r
454 //\r
455 ASSERT(CommandString != NULL);\r
456\r
457 //\r
458 // check for the command\r
459 //\r
460 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
461 ; !IsNull(&mCommandList.Link, &Node->Link)\r
462 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
463 ){\r
464 ASSERT(Node->CommandString != NULL);\r
465 if (gUnicodeCollation->StriColl(\r
466 gUnicodeCollation,\r
467 (CHAR16*)CommandString,\r
468 Node->CommandString) == 0\r
469 ){\r
470 return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));\r
471 }\r
472 }\r
473 return (NULL);\r
474}\r
475\r
cf812a20
JC
476/**\r
477 Get the help text for a command.\r
478\r
479 @param[in] CommandString The command name.\r
480\r
481 @retval NULL No help text was found.\r
482 @return String of help text.Caller reuiqred to free.\r
483**/\r
484CHAR16*\r
485EFIAPI\r
486ShellCommandGetCommandHelp (\r
487 IN CONST CHAR16 *CommandString\r
488 )\r
489{\r
490 CHAR16 *HelpStr;\r
491 HelpStr = ShellCommandGetInternalCommandHelp(CommandString);\r
492\r
493 if (HelpStr == NULL) {\r
494 HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);\r
495 }\r
496\r
497 return HelpStr;\r
498}\r
499\r
500\r
a405b86d 501/**\r
502 Registers handlers of type SHELL_RUN_COMMAND and\r
503 SHELL_GET_MAN_FILENAME for each shell command.\r
504\r
505 If the ShellSupportLevel is greater than the value of the\r
506 PcdShellSupportLevel then return RETURN_UNSUPPORTED.\r
507\r
508 Registers the handlers specified by GetHelpInfoHandler and CommandHandler\r
509 with the command specified by CommandString. If the command named by\r
510 CommandString has already been registered, then return\r
511 RETURN_ALREADY_STARTED.\r
512\r
513 If there are not enough resources available to register the handlers then\r
514 RETURN_OUT_OF_RESOURCES is returned.\r
515\r
516 If CommandString is NULL, then ASSERT().\r
517 If GetHelpInfoHandler is NULL, then ASSERT().\r
518 If CommandHandler is NULL, then ASSERT().\r
519 If ProfileName is NULL, then ASSERT().\r
520\r
521 @param[in] CommandString Pointer to the command name. This is the\r
522 name to look for on the command line in\r
523 the shell.\r
524 @param[in] CommandHandler Pointer to a function that runs the\r
525 specified command.\r
526 @param[in] GetManFileName Pointer to a function that provides man\r
527 filename.\r
528 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this\r
529 function.\r
530 @param[in] ProfileName profile name to require for support of this\r
531 function.\r
532 @param[in] CanAffectLE indicates whether this command's return value\r
533 can change the LASTERROR environment variable.\r
534 @param[in] HiiHandle Handle of this command's HII entry.\r
535 @param[in] ManFormatHelp HII locator for the help text.\r
536\r
537 @retval RETURN_SUCCESS The handlers were registered.\r
538 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
539 register the shell command.\r
540 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the\r
541 currently allowed support level.\r
542 @retval RETURN_ALREADY_STARTED The CommandString represents a command that\r
543 is already registered. Only 1 handler set for\r
544 a given command is allowed.\r
545 @sa SHELL_GET_MAN_FILENAME\r
546 @sa SHELL_RUN_COMMAND\r
547**/\r
548RETURN_STATUS\r
549EFIAPI\r
550ShellCommandRegisterCommandName (\r
551 IN CONST CHAR16 *CommandString,\r
552 IN SHELL_RUN_COMMAND CommandHandler,\r
553 IN SHELL_GET_MAN_FILENAME GetManFileName,\r
554 IN UINT32 ShellMinSupportLevel,\r
555 IN CONST CHAR16 *ProfileName,\r
556 IN CONST BOOLEAN CanAffectLE,\r
c44501b3 557 IN CONST EFI_HII_HANDLE HiiHandle,\r
a405b86d 558 IN CONST EFI_STRING_ID ManFormatHelp\r
559 )\r
560{\r
561 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
d51088b7 562 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;\r
563 SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;\r
564 INTN LexicalMatchValue;\r
565\r
566 //\r
567 // Initialize local variables.\r
568 //\r
569 Command = NULL;\r
570 PrevCommand = NULL;\r
571 LexicalMatchValue = 0;\r
a405b86d 572\r
573 //\r
574 // ASSERTs for NULL parameters\r
575 //\r
576 ASSERT(CommandString != NULL);\r
577 ASSERT(GetManFileName != NULL);\r
578 ASSERT(CommandHandler != NULL);\r
579 ASSERT(ProfileName != NULL);\r
580\r
581 //\r
582 // check for shell support level\r
583 //\r
584 if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {\r
585 return (RETURN_UNSUPPORTED);\r
586 }\r
587\r
588 //\r
589 // check for already on the list\r
590 //\r
591 if (ShellCommandIsCommandOnList(CommandString)) {\r
592 return (RETURN_ALREADY_STARTED);\r
593 }\r
594\r
595 //\r
596 // allocate memory for new struct\r
597 //\r
1a63ec8f 598 Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));\r
107d05a4
RN
599 if (Node == NULL) {\r
600 return RETURN_OUT_OF_RESOURCES;\r
601 }\r
53173337 602 Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);\r
107d05a4
RN
603 if (Node->CommandString == NULL) {\r
604 FreePool (Node);\r
605 return RETURN_OUT_OF_RESOURCES;\r
606 }\r
a405b86d 607\r
a405b86d 608 Node->GetManFileName = GetManFileName;\r
609 Node->CommandHandler = CommandHandler;\r
610 Node->LastError = CanAffectLE;\r
611 Node->HiiHandle = HiiHandle;\r
612 Node->ManFormatHelp = ManFormatHelp;\r
613\r
614 if ( StrLen(ProfileName)>0\r
615 && ((mProfileList != NULL\r
616 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)\r
617 ){\r
618 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));\r
619 if (mProfileList == NULL) {\r
620 //\r
621 // If this is the first make a leading ';'\r
622 //\r
623 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
624 }\r
625 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);\r
626 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
627 }\r
628\r
629 //\r
d51088b7 630 // Insert a new entry on top of the list\r
631 //\r
632 InsertHeadList (&mCommandList.Link, &Node->Link);\r
633\r
634 //\r
635 // Move a new registered command to its sorted ordered location in the list\r
a405b86d 636 //\r
d51088b7 637 for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),\r
638 PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)\r
639 ; !IsNull (&mCommandList.Link, &Command->Link)\r
640 ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {\r
641\r
642 //\r
643 // Get Lexical Comparison Value between PrevCommand and Command list entry\r
644 //\r
645 LexicalMatchValue = gUnicodeCollation->StriColl (\r
646 gUnicodeCollation,\r
647 PrevCommand->CommandString,\r
648 Command->CommandString\r
649 );\r
650\r
651 //\r
652 // Swap PrevCommand and Command list entry if PrevCommand list entry\r
653 // is alphabetically greater than Command list entry\r
654 //\r
655 if (LexicalMatchValue > 0){\r
656 Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);\r
657 } else if (LexicalMatchValue < 0) {\r
658 //\r
659 // PrevCommand entry is lexically lower than Command entry\r
660 //\r
661 break;\r
662 }\r
663 }\r
a405b86d 664\r
665 return (RETURN_SUCCESS);\r
666}\r
667\r
668/**\r
669 Function to get the current Profile string.\r
670\r
671 @retval NULL There are no installed profiles.\r
672 @return A semi-colon delimited list of profiles.\r
673**/\r
674CONST CHAR16 *\r
675EFIAPI\r
676ShellCommandGetProfileList (\r
677 VOID\r
678 )\r
679{\r
680 return (mProfileList);\r
681}\r
682\r
683/**\r
684 Checks if a command string has been registered for CommandString and if so it runs\r
685 the previously registered handler for that command with the command line.\r
686\r
687 If CommandString is NULL, then ASSERT().\r
688\r
689 If Sections is specified, then each section name listed will be compared in a casesensitive\r
690 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,\r
691 it will be appended to the returned help text. If the section does not exist, no\r
692 information will be returned. If Sections is NULL, then all help text information\r
693 available will be returned.\r
694\r
4ff7e37b
ED
695 @param[in] CommandString Pointer to the command name. This is the name\r
696 found on the command line in the shell.\r
697 @param[in, out] RetVal Pointer to the return vaule from the command handler.\r
a405b86d 698\r
4ff7e37b
ED
699 @param[in, out] CanAffectLE indicates whether this command's return value\r
700 needs to be placed into LASTERROR environment variable.\r
a405b86d 701\r
702 @retval RETURN_SUCCESS The handler was run.\r
703 @retval RETURN_NOT_FOUND The CommandString did not match a registered\r
704 command name.\r
705 @sa SHELL_RUN_COMMAND\r
706**/\r
707RETURN_STATUS\r
708EFIAPI\r
709ShellCommandRunCommandHandler (\r
710 IN CONST CHAR16 *CommandString,\r
711 IN OUT SHELL_STATUS *RetVal,\r
712 IN OUT BOOLEAN *CanAffectLE OPTIONAL\r
713 )\r
714{\r
cf812a20
JC
715 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
716 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
a405b86d 717\r
718 //\r
719 // assert for NULL parameters\r
720 //\r
721 ASSERT(CommandString != NULL);\r
722\r
723 //\r
724 // check for the command\r
725 //\r
726 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
727 ; !IsNull(&mCommandList.Link, &Node->Link)\r
728 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
729 ){\r
730 ASSERT(Node->CommandString != NULL);\r
731 if (gUnicodeCollation->StriColl(\r
732 gUnicodeCollation,\r
733 (CHAR16*)CommandString,\r
734 Node->CommandString) == 0\r
cf812a20 735 ){\r
a405b86d 736 if (CanAffectLE != NULL) {\r
737 *CanAffectLE = Node->LastError;\r
738 }\r
739 if (RetVal != NULL) {\r
740 *RetVal = Node->CommandHandler(NULL, gST);\r
741 } else {\r
742 Node->CommandHandler(NULL, gST);\r
743 }\r
744 return (RETURN_SUCCESS);\r
745 }\r
746 }\r
cf812a20
JC
747\r
748 //\r
749 // An internal command was not found, try to find a dynamic command\r
750 //\r
751 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
752 if (DynamicCommand != NULL) {\r
753 if (RetVal != NULL) {\r
754 *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
755 } else {\r
756 DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
757 }\r
758 return (RETURN_SUCCESS);\r
759 }\r
760\r
a405b86d 761 return (RETURN_NOT_FOUND);\r
762}\r
763\r
764/**\r
765 Checks if a command string has been registered for CommandString and if so it\r
766 returns the MAN filename specified for that command.\r
767\r
768 If CommandString is NULL, then ASSERT().\r
769\r
770 @param[in] CommandString Pointer to the command name. This is the name\r
771 found on the command line in the shell.\\r
772\r
773 @retval NULL the commandString was not a registered command.\r
774 @return other the name of the MAN file.\r
775 @sa SHELL_GET_MAN_FILENAME\r
776**/\r
777CONST CHAR16*\r
778EFIAPI\r
779ShellCommandGetManFileNameHandler (\r
780 IN CONST CHAR16 *CommandString\r
781 )\r
782{\r
783 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
784\r
785 //\r
786 // assert for NULL parameters\r
787 //\r
788 ASSERT(CommandString != NULL);\r
789\r
790 //\r
791 // check for the command\r
792 //\r
793 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
794 ; !IsNull(&mCommandList.Link, &Node->Link)\r
795 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
796 ){\r
797 ASSERT(Node->CommandString != NULL);\r
798 if (gUnicodeCollation->StriColl(\r
799 gUnicodeCollation,\r
800 (CHAR16*)CommandString,\r
801 Node->CommandString) == 0\r
802 ){\r
803 return (Node->GetManFileName());\r
804 }\r
805 }\r
806 return (NULL);\r
807}\r
808\r
809/**\r
810 Get the list of all available shell internal commands. This is a linked list\r
811 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
812 list functions. do not modify the values.\r
813\r
1a63ec8f 814 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.\r
815\r
a405b86d 816 @return a Linked list of all available shell commands.\r
817**/\r
818CONST COMMAND_LIST*\r
819EFIAPI\r
820ShellCommandGetCommandList (\r
1a63ec8f 821 IN CONST BOOLEAN Sort\r
a405b86d 822 )\r
823{\r
1a63ec8f 824// if (!Sort) {\r
825// return ((COMMAND_LIST*)(&mCommandList));\r
826// }\r
a405b86d 827 return ((COMMAND_LIST*)(&mCommandList));\r
828}\r
829\r
830/**\r
831 Registers aliases to be set as part of the initialization of the shell application.\r
832\r
833 If Command is NULL, then ASSERT().\r
834 If Alias is NULL, then ASSERT().\r
835\r
836 @param[in] Command Pointer to the Command\r
837 @param[in] Alias Pointer to Alias\r
838\r
839 @retval RETURN_SUCCESS The handlers were registered.\r
840 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
841 register the shell command.\r
842**/\r
843RETURN_STATUS\r
844EFIAPI\r
845ShellCommandRegisterAlias (\r
846 IN CONST CHAR16 *Command,\r
847 IN CONST CHAR16 *Alias\r
848 )\r
849{\r
850 ALIAS_LIST *Node;\r
4ba9b812 851 ALIAS_LIST *CommandAlias;\r
ba0014b9 852 ALIAS_LIST *PrevCommandAlias;\r
4ba9b812 853 INTN LexicalMatchValue;\r
a405b86d 854\r
855 //\r
856 // Asserts for NULL\r
857 //\r
858 ASSERT(Command != NULL);\r
859 ASSERT(Alias != NULL);\r
860\r
861 //\r
862 // allocate memory for new struct\r
863 //\r
1a63ec8f 864 Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
107d05a4
RN
865 if (Node == NULL) {\r
866 return RETURN_OUT_OF_RESOURCES;\r
867 }\r
53173337 868 Node->CommandString = AllocateCopyPool(StrSize(Command), Command);\r
107d05a4
RN
869 if (Node->CommandString == NULL) {\r
870 FreePool (Node);\r
871 return RETURN_OUT_OF_RESOURCES;\r
872 }\r
53173337 873 Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);\r
107d05a4
RN
874 if (Node->Alias == NULL) {\r
875 FreePool (Node->CommandString);\r
876 FreePool (Node);\r
877 return RETURN_OUT_OF_RESOURCES;\r
878 }\r
a405b86d 879\r
4ba9b812
TS
880 InsertHeadList (&mAliasList.Link, &Node->Link);\r
881\r
a405b86d 882 //\r
4ba9b812 883 // Move a new pre-defined registered alias to its sorted ordered location in the list\r
a405b86d 884 //\r
4ba9b812
TS
885 for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),\r
886 PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)\r
887 ; !IsNull (&mAliasList.Link, &CommandAlias->Link)\r
888 ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {\r
889 //\r
890 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry\r
891 //\r
892 LexicalMatchValue = gUnicodeCollation->StriColl (\r
893 gUnicodeCollation,\r
894 PrevCommandAlias->Alias,\r
895 CommandAlias->Alias\r
896 );\r
897\r
898 //\r
899 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry\r
900 // is alphabetically greater than CommandAlias list entry\r
ba0014b9 901 //\r
4ba9b812
TS
902 if (LexicalMatchValue > 0) {\r
903 CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);\r
904 } else if (LexicalMatchValue < 0) {\r
905 //\r
906 // PrevCommandAlias entry is lexically lower than CommandAlias entry\r
907 //\r
908 break;\r
909 }\r
910 }\r
a405b86d 911\r
912 return (RETURN_SUCCESS);\r
913}\r
914\r
915/**\r
916 Get the list of all shell alias commands. This is a linked list\r
917 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
918 list functions. do not modify the values.\r
919\r
920 @return a Linked list of all requested shell alias'.\r
921**/\r
922CONST ALIAS_LIST*\r
923EFIAPI\r
924ShellCommandGetInitAliasList (\r
925 VOID\r
926 )\r
927{\r
928 return (&mAliasList);\r
929}\r
930\r
931/**\r
1a63ec8f 932 Determine if a given alias is on the list of built in alias'.\r
a405b86d 933\r
934 @param[in] Alias The alias to test for\r
935\r
936 @retval TRUE The alias is a built in alias\r
937 @retval FALSE The alias is not a built in alias\r
938**/\r
939BOOLEAN\r
940EFIAPI\r
941ShellCommandIsOnAliasList(\r
942 IN CONST CHAR16 *Alias\r
943 )\r
944{\r
945 ALIAS_LIST *Node;\r
946\r
947 //\r
948 // assert for NULL parameter\r
949 //\r
950 ASSERT(Alias != NULL);\r
951\r
952 //\r
953 // check for the Alias\r
954 //\r
955 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)\r
956 ; !IsNull(&mAliasList.Link, &Node->Link)\r
957 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)\r
958 ){\r
959 ASSERT(Node->CommandString != NULL);\r
960 ASSERT(Node->Alias != NULL);\r
961 if (gUnicodeCollation->StriColl(\r
962 gUnicodeCollation,\r
963 (CHAR16*)Alias,\r
964 Node->CommandString) == 0\r
965 ){\r
966 return (TRUE);\r
967 }\r
968 if (gUnicodeCollation->StriColl(\r
969 gUnicodeCollation,\r
970 (CHAR16*)Alias,\r
971 Node->Alias) == 0\r
972 ){\r
973 return (TRUE);\r
974 }\r
975 }\r
976 return (FALSE);\r
977}\r
978\r
979/**\r
cceb4ebd 980 Function to determine current state of ECHO. Echo determines if lines from scripts\r
a405b86d 981 and ECHO commands are enabled.\r
982\r
983 @retval TRUE Echo is currently enabled\r
984 @retval FALSE Echo is currently disabled\r
985**/\r
986BOOLEAN\r
987EFIAPI\r
988ShellCommandGetEchoState(\r
989 VOID\r
990 )\r
991{\r
992 return (mEchoState);\r
993}\r
994\r
995/**\r
cceb4ebd 996 Function to set current state of ECHO. Echo determines if lines from scripts\r
a405b86d 997 and ECHO commands are enabled.\r
998\r
999 If State is TRUE, Echo will be enabled.\r
1000 If State is FALSE, Echo will be disabled.\r
1a63ec8f 1001\r
1002 @param[in] State How to set echo.\r
a405b86d 1003**/\r
1004VOID\r
1005EFIAPI\r
1006ShellCommandSetEchoState(\r
1007 IN BOOLEAN State\r
1008 )\r
1009{\r
1010 mEchoState = State;\r
1011}\r
1012\r
1013/**\r
1014 Indicate that the current shell or script should exit.\r
1015\r
b6b22b13 1016 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.\r
1017 @param[in] ErrorCode The 64 bit error code to return.\r
a405b86d 1018**/\r
1019VOID\r
1020EFIAPI\r
1021ShellCommandRegisterExit (\r
b6b22b13 1022 IN BOOLEAN ScriptOnly,\r
1023 IN CONST UINT64 ErrorCode\r
a405b86d 1024 )\r
1025{\r
1026 mExitRequested = (BOOLEAN)(!mExitRequested);\r
1027 if (mExitRequested) {\r
1028 mExitScript = ScriptOnly;\r
1029 } else {\r
1030 mExitScript = FALSE;\r
1031 }\r
b6b22b13 1032 mExitCode = ErrorCode;\r
a405b86d 1033}\r
1034\r
1035/**\r
1036 Retrieve the Exit indicator.\r
1037\r
1038 @retval TRUE Exit was indicated.\r
1039 @retval FALSE Exis was not indicated.\r
1040**/\r
1041BOOLEAN\r
1042EFIAPI\r
1043ShellCommandGetExit (\r
1044 VOID\r
1045 )\r
1046{\r
1047 return (mExitRequested);\r
1048}\r
1049\r
b6b22b13 1050/**\r
1051 Retrieve the Exit code.\r
1052\r
1053 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
1054\r
1055 @return the value passed into RegisterExit.\r
1056**/\r
1057UINT64\r
1058EFIAPI\r
1059ShellCommandGetExitCode (\r
1060 VOID\r
1061 )\r
1062{\r
1063 return (mExitCode);\r
1064}\r
a405b86d 1065/**\r
1066 Retrieve the Exit script indicator.\r
1067\r
1068 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
1069\r
1070 @retval TRUE ScriptOnly was indicated.\r
1071 @retval FALSE ScriptOnly was not indicated.\r
1072**/\r
1073BOOLEAN\r
1074EFIAPI\r
1075ShellCommandGetScriptExit (\r
1076 VOID\r
1077 )\r
1078{\r
1079 return (mExitScript);\r
1080}\r
1081\r
1082/**\r
1083 Function to cleanup all memory from a SCRIPT_FILE structure.\r
1084\r
1085 @param[in] Script The pointer to the structure to cleanup.\r
1086**/\r
1087VOID\r
1088EFIAPI\r
1089DeleteScriptFileStruct (\r
1090 IN SCRIPT_FILE *Script\r
1091 )\r
1092{\r
1093 UINT8 LoopVar;\r
0ab85bef 1094\r
1095 if (Script == NULL) {\r
1096 return;\r
1097 }\r
1098\r
a405b86d 1099 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {\r
0ab85bef 1100 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);\r
a405b86d 1101 }\r
1102 if (Script->Argv != NULL) {\r
0ab85bef 1103 SHELL_FREE_NON_NULL(Script->Argv);\r
a405b86d 1104 }\r
1105 Script->CurrentCommand = NULL;\r
1106 while (!IsListEmpty (&Script->CommandList)) {\r
1107 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);\r
1108 if (Script->CurrentCommand != NULL) {\r
1109 RemoveEntryList(&Script->CurrentCommand->Link);\r
1110 if (Script->CurrentCommand->Cl != NULL) {\r
0ab85bef 1111 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);\r
a405b86d 1112 }\r
1113 if (Script->CurrentCommand->Data != NULL) {\r
0ab85bef 1114 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);\r
a405b86d 1115 }\r
0ab85bef 1116 SHELL_FREE_NON_NULL(Script->CurrentCommand);\r
a405b86d 1117 }\r
1118 }\r
0ab85bef 1119 SHELL_FREE_NON_NULL(Script->ScriptName);\r
1120 SHELL_FREE_NON_NULL(Script);\r
a405b86d 1121}\r
1122\r
1123/**\r
1124 Function to return a pointer to the currently running script file object.\r
1125\r
1126 @retval NULL A script file is not currently running.\r
1127 @return A pointer to the current script file object.\r
1128**/\r
1129SCRIPT_FILE*\r
1130EFIAPI\r
1131ShellCommandGetCurrentScriptFile (\r
1132 VOID\r
1133 )\r
1134{\r
1135 SCRIPT_FILE_LIST *List;\r
1136 if (IsListEmpty (&mScriptList.Link)) {\r
1137 return (NULL);\r
1138 }\r
1139 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));\r
1140 return (List->Data);\r
1141}\r
1142\r
1143/**\r
1144 Function to set a new script as the currently running one.\r
1145\r
1146 This function will correctly stack and unstack nested scripts.\r
1147\r
1148 @param[in] Script Pointer to new script information structure. if NULL\r
1149 will remove and de-allocate the top-most Script structure.\r
1150\r
1151 @return A pointer to the current running script file after this\r
1152 change. NULL if removing the final script.\r
1153**/\r
1154SCRIPT_FILE*\r
1155EFIAPI\r
1156ShellCommandSetNewScript (\r
1157 IN SCRIPT_FILE *Script OPTIONAL\r
1158 )\r
1159{\r
1160 SCRIPT_FILE_LIST *Node;\r
1161 if (Script == NULL) {\r
1162 if (IsListEmpty (&mScriptList.Link)) {\r
a405b86d 1163 return (NULL);\r
1164 }\r
1165 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
1166 RemoveEntryList(&Node->Link);\r
1167 DeleteScriptFileStruct(Node->Data);\r
1168 FreePool(Node);\r
1169 } else {\r
1170 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));\r
0ab85bef 1171 if (Node == NULL) {\r
1172 return (NULL);\r
1173 }\r
a405b86d 1174 Node->Data = Script;\r
1175 InsertHeadList(&mScriptList.Link, &Node->Link);\r
1176 }\r
1177 return (ShellCommandGetCurrentScriptFile());\r
1178}\r
1179\r
1180/**\r
1181 Function to generate the next default mapping name.\r
1182\r
1183 If the return value is not NULL then it must be callee freed.\r
1184\r
1185 @param Type What kind of mapping name to make.\r
1186\r
1187 @retval NULL a memory allocation failed.\r
1188 @return a new map name string\r
1189**/\r
1190CHAR16*\r
1191EFIAPI\r
1192ShellCommandCreateNewMappingName(\r
1193 IN CONST SHELL_MAPPING_TYPE Type\r
1194 )\r
1195{\r
1196 CHAR16 *String;\r
1197 ASSERT(Type < MappingTypeMax);\r
1198\r
1199 String = NULL;\r
1200\r
1201 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));\r
1202 UnicodeSPrint(\r
1203 String,\r
1204 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),\r
1205 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",\r
1206 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);\r
1207\r
1208 return (String);\r
1209}\r
1210\r
1211/**\r
1212 Function to add a map node to the list of map items and update the "path" environment variable (optionally).\r
1213\r
1214 If Path is TRUE (during initialization only), the path environment variable will also be updated to include\r
1215 default paths on the new map name...\r
1216\r
1217 Path should be FALSE when this function is called from the protocol SetMap function.\r
1218\r
1219 @param[in] Name The human readable mapped name.\r
1220 @param[in] DevicePath The Device Path for this map.\r
1221 @param[in] Flags The Flags attribute for this map item.\r
1222 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).\r
1223\r
1224 @retval EFI_SUCCESS The addition was sucessful.\r
1225 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
1226 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
1227**/\r
1228EFI_STATUS\r
1229EFIAPI\r
1230ShellCommandAddMapItemAndUpdatePath(\r
1231 IN CONST CHAR16 *Name,\r
1232 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1233 IN CONST UINT64 Flags,\r
1234 IN CONST BOOLEAN Path\r
1235 )\r
1236{\r
1237 EFI_STATUS Status;\r
1238 SHELL_MAP_LIST *MapListNode;\r
1239 CONST CHAR16 *OriginalPath;\r
1240 CHAR16 *NewPath;\r
1241 UINTN NewPathSize;\r
1242\r
1243 NewPathSize = 0;\r
1244 NewPath = NULL;\r
1245 OriginalPath = NULL;\r
1246 Status = EFI_SUCCESS;\r
1247\r
1248 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));\r
1249 if (MapListNode == NULL) {\r
1250 Status = EFI_OUT_OF_RESOURCES;\r
1251 } else {\r
1252 MapListNode->Flags = Flags;\r
3957a5a5 1253 MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);\r
a405b86d 1254 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
1255 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
1256 Status = EFI_OUT_OF_RESOURCES;\r
1257 } else {\r
a405b86d 1258 InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
1259 }\r
1260 }\r
1261 if (EFI_ERROR(Status)) {\r
1262 if (MapListNode != NULL) {\r
1263 if (MapListNode->DevicePath != NULL) {\r
1264 FreePool(MapListNode->DevicePath);\r
1265 }\r
1266 if (MapListNode->MapName != NULL) {\r
1267 FreePool(MapListNode->MapName);\r
1268 }\r
1269 FreePool(MapListNode);\r
1270 }\r
1271 } else if (Path) {\r
1272 //\r
1273 // Since there was no error and Path was TRUE\r
1274 // Now add the correct path for that mapping\r
1275 //\r
1276 OriginalPath = gEfiShellProtocol->GetEnv(L"path");\r
1277 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
1278 if (OriginalPath != NULL) {\r
1279 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
85b88deb 1280 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
a405b86d 1281 }\r
a405b86d 1282 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1283 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
1284 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1285 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);\r
1286 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1287 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);\r
1288\r
1289 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);\r
1290 ASSERT_EFI_ERROR(Status);\r
1291 FreePool(NewPath);\r
1292 }\r
1293 return (Status);\r
1294}\r
1295\r
1296/**\r
1297 Creates the default map names for each device path in the system with\r
1298 a protocol depending on the Type.\r
1299\r
1300 Creates the consistent map names for each device path in the system with\r
1301 a protocol depending on the Type.\r
1302\r
1303 Note: This will reset all mappings in the system("map -r").\r
1304\r
1305 Also sets up the default path environment variable if Type is FileSystem.\r
1306\r
1307 @retval EFI_SUCCESS All map names were created sucessfully.\r
1308 @retval EFI_NOT_FOUND No protocols were found in the system.\r
1309 @return Error returned from gBS->LocateHandle().\r
1310\r
1311 @sa LocateHandle\r
1312**/\r
1313EFI_STATUS\r
1314EFIAPI\r
1315ShellCommandCreateInitialMappingsAndPaths(\r
1316 VOID\r
1317 )\r
1318{\r
1319 EFI_STATUS Status;\r
1320 EFI_HANDLE *HandleList;\r
1321 UINTN Count;\r
1322 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1323 CHAR16 *NewDefaultName;\r
1324 CHAR16 *NewConsistName;\r
1325 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1326 SHELL_MAP_LIST *MapListNode;\r
055fafe1
HL
1327 CONST CHAR16 *CurDir;\r
1328 CHAR16 *SplitCurDir;\r
1329 CHAR16 *MapName;\r
1330 SHELL_MAP_LIST *MapListItem;\r
1331\r
1332 SplitCurDir = NULL;\r
1333 MapName = NULL;\r
1334 MapListItem = NULL;\r
a405b86d 1335 HandleList = NULL;\r
1336\r
1337 //\r
1338 // Reset the static members back to zero\r
1339 //\r
1340 mFsMaxCount = 0;\r
1341 mBlkMaxCount = 0;\r
1342\r
1343 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);\r
1344\r
1345 //\r
1346 // First empty out the existing list.\r
1347 //\r
1348 if (!IsListEmpty(&gShellMapList.Link)) {\r
1349 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1350 ; !IsListEmpty(&gShellMapList.Link)\r
1351 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1352 ){\r
1353 RemoveEntryList(&MapListNode->Link);\r
c8cfd83a
JY
1354 SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
1355 SHELL_FREE_NON_NULL(MapListNode->MapName);\r
1356 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
a405b86d 1357 FreePool(MapListNode);\r
1358 } // for loop\r
1359 }\r
1360\r
1361 //\r
1362 // Find each handle with Simple File System\r
1363 //\r
0ab85bef 1364 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
a405b86d 1365 if (HandleList != NULL) {\r
1366 //\r
1367 // Do a count of the handles\r
1368 //\r
1369 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1370\r
1371 //\r
1372 // Get all Device Paths\r
1373 //\r
1a63ec8f 1374 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
107d05a4
RN
1375 if (DevicePathList == NULL) {\r
1376 SHELL_FREE_NON_NULL (HandleList);\r
1377 return EFI_OUT_OF_RESOURCES;\r
1378 }\r
a405b86d 1379\r
1380 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1381 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1382 }\r
1383\r
1384 //\r
1385 // Sort all DevicePaths\r
1386 //\r
1387 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1388\r
1389 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1390 //\r
1391 // Assign new Mappings to all...\r
1392 //\r
1393 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1394 //\r
1395 // Get default name first\r
1396 //\r
1397 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
1398 ASSERT(NewDefaultName != NULL);\r
1399 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);\r
1400 ASSERT_EFI_ERROR(Status);\r
1401 FreePool(NewDefaultName);\r
1402\r
1403 //\r
1404 // Now do consistent name\r
1405 //\r
1406 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1407 if (NewConsistName != NULL) {\r
1408 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);\r
1409 ASSERT_EFI_ERROR(Status);\r
1410 FreePool(NewConsistName);\r
1411 }\r
1412 }\r
1413\r
1414 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1415\r
1416 SHELL_FREE_NON_NULL(HandleList);\r
1417 SHELL_FREE_NON_NULL(DevicePathList);\r
1418\r
1419 HandleList = NULL;\r
055fafe1
HL
1420\r
1421 //\r
1422 //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,\r
1423 //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,\r
1424 //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.\r
1425 //\r
1426 if (gShellCurMapping != NULL) {\r
1427 gShellCurMapping = NULL;\r
1428 CurDir = gEfiShellProtocol->GetEnv(L"cwd");\r
1429 if (CurDir != NULL) {\r
1430 MapName = AllocateCopyPool (StrSize(CurDir), CurDir);\r
1431 if (MapName == NULL) {\r
1432 return EFI_OUT_OF_RESOURCES;\r
1433 }\r
1434 SplitCurDir = StrStr (MapName, L":");\r
1435 if (SplitCurDir == NULL) {\r
1436 SHELL_FREE_NON_NULL (MapName);\r
1437 return EFI_UNSUPPORTED;\r
1438 }\r
1439 *(SplitCurDir + 1) = CHAR_NULL;\r
1440 MapListItem = ShellCommandFindMapItem (MapName);\r
1441 if (MapListItem != NULL) {\r
1442 gShellCurMapping = MapListItem;\r
1443 }\r
1444 SHELL_FREE_NON_NULL (MapName);\r
1445 }\r
1446 }\r
a405b86d 1447 } else {\r
1448 Count = (UINTN)-1;\r
1449 }\r
1450\r
1451 //\r
1452 // Find each handle with Block Io\r
1453 //\r
0ab85bef 1454 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);\r
a405b86d 1455 if (HandleList != NULL) {\r
1456 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1457\r
1458 //\r
1459 // Get all Device Paths\r
1460 //\r
1a63ec8f 1461 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
107d05a4
RN
1462 if (DevicePathList == NULL) {\r
1463 SHELL_FREE_NON_NULL (HandleList);\r
1464 return EFI_OUT_OF_RESOURCES;\r
1465 }\r
a405b86d 1466\r
1467 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1468 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1469 }\r
1470\r
1471 //\r
1472 // Sort all DevicePaths\r
1473 //\r
1474 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1475\r
1476 //\r
1477 // Assign new Mappings to all...\r
1478 //\r
1479 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1480 //\r
1481 // Get default name first\r
1482 //\r
1483 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);\r
1484 ASSERT(NewDefaultName != NULL);\r
1485 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);\r
1486 ASSERT_EFI_ERROR(Status);\r
1487 FreePool(NewDefaultName);\r
1488 }\r
1489\r
1490 SHELL_FREE_NON_NULL(HandleList);\r
1491 SHELL_FREE_NON_NULL(DevicePathList);\r
1492 } else if (Count == (UINTN)-1) {\r
1493 return (EFI_NOT_FOUND);\r
1494 }\r
1495\r
1496 return (EFI_SUCCESS);\r
cf812a20
JC
1497}\r
1498\r
1499/**\r
1500 Add mappings for any devices without one. Do not change any existing maps.\r
1501\r
1502 @retval EFI_SUCCESS The operation was successful.\r
1503**/\r
1504EFI_STATUS\r
1505EFIAPI\r
1506ShellCommandUpdateMapping (\r
1507 VOID\r
1508 )\r
1509{\r
1510 EFI_STATUS Status;\r
1511 EFI_HANDLE *HandleList;\r
1512 UINTN Count;\r
1513 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1514 CHAR16 *NewDefaultName;\r
1515 CHAR16 *NewConsistName;\r
1516 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1517\r
1518 HandleList = NULL;\r
1519 Status = EFI_SUCCESS;\r
1520\r
1521 //\r
1522 // remove mappings that represent removed devices.\r
1523 //\r
1524\r
1525 //\r
1526 // Find each handle with Simple File System\r
1527 //\r
1528 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
1529 if (HandleList != NULL) {\r
1530 //\r
1531 // Do a count of the handles\r
1532 //\r
1533 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1534\r
1535 //\r
1536 // Get all Device Paths\r
1537 //\r
1538 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
ae315cc2
JC
1539 if (DevicePathList == NULL) {\r
1540 return (EFI_OUT_OF_RESOURCES);\r
1541 }\r
cf812a20
JC
1542\r
1543 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1544 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1545 }\r
1546\r
1547 //\r
1548 // Sort all DevicePaths\r
1549 //\r
1550 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1551\r
1552 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1553\r
1554 //\r
1555 // Assign new Mappings to remainders\r
1556 //\r
ae315cc2 1557 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {\r
cf812a20
JC
1558 //\r
1559 // Skip ones that already have\r
1560 //\r
1561 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {\r
1562 continue;\r
1563 }\r
1564 //\r
1565 // Get default name\r
1566 //\r
1567 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
ae315cc2
JC
1568 if (NewDefaultName == NULL) {\r
1569 Status = EFI_OUT_OF_RESOURCES;\r
1570 break;\r
1571 }\r
cf812a20
JC
1572\r
1573 //\r
1574 // Call shell protocol SetMap function now...\r
1575 //\r
1576 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);\r
1577\r
1578 if (!EFI_ERROR(Status)) {\r
1579 //\r
1580 // Now do consistent name\r
1581 //\r
1582 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1583 if (NewConsistName != NULL) {\r
1584 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);\r
1585 FreePool(NewConsistName);\r
1586 }\r
1587 }\r
1588\r
1589 FreePool(NewDefaultName);\r
1590 }\r
1591 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1592 SHELL_FREE_NON_NULL(HandleList);\r
1593 SHELL_FREE_NON_NULL(DevicePathList);\r
1594\r
1595 HandleList = NULL;\r
1596 } else {\r
1597 Count = (UINTN)-1;\r
1598 }\r
1599 //\r
1600 // Do it all over again for gEfiBlockIoProtocolGuid\r
1601 //\r
1602\r
1603 return (Status);\r
1604}\r
1605\r
1606/**\r
1607 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
1608\r
1609 @param[in] Handle The SHELL_FILE_HANDLE to convert.\r
a405b86d 1610\r
1611 @return a EFI_FILE_PROTOCOL* representing the same file.\r
1612**/\r
1613EFI_FILE_PROTOCOL*\r
1614EFIAPI\r
1615ConvertShellHandleToEfiFileProtocol(\r
1616 IN CONST SHELL_FILE_HANDLE Handle\r
1617 )\r
1618{\r
1619 return ((EFI_FILE_PROTOCOL*)(Handle));\r
1620}\r
1621\r
1622/**\r
1623 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.\r
1624\r
1625 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.\r
1626 @param[in] Path The path to the file for verification.\r
1627\r
ff51746b 1628 @return A SHELL_FILE_HANDLE representing the same file.\r
1629 @retval NULL There was not enough memory.\r
a405b86d 1630**/\r
1631SHELL_FILE_HANDLE\r
1632EFIAPI\r
1633ConvertEfiFileProtocolToShellHandle(\r
1634 IN CONST EFI_FILE_PROTOCOL *Handle,\r
1635 IN CONST CHAR16 *Path\r
1636 )\r
1637{\r
1638 SHELL_COMMAND_FILE_HANDLE *Buffer;\r
1639 BUFFER_LIST *NewNode;\r
1640\r
1641 if (Path != NULL) {\r
1642 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));\r
ff51746b 1643 if (Buffer == NULL) {\r
1644 return (NULL);\r
1645 }\r
1a63ec8f 1646 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ff51746b 1647 if (NewNode == NULL) {\r
ae315cc2 1648 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1649 return (NULL);\r
1650 }\r
a405b86d 1651 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;\r
1652 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
ff51746b 1653 if (Buffer->Path == NULL) {\r
ae315cc2
JC
1654 SHELL_FREE_NON_NULL(NewNode);\r
1655 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1656 return (NULL);\r
1657 }\r
a405b86d 1658 NewNode->Buffer = Buffer;\r
1659\r
1660 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);\r
1661 }\r
1662 return ((SHELL_FILE_HANDLE)(Handle));\r
1663}\r
1664\r
1665/**\r
1666 Find the path that was logged with the specified SHELL_FILE_HANDLE.\r
1667\r
1668 @param[in] Handle The SHELL_FILE_HANDLE to query on.\r
1669\r
1670 @return A pointer to the path for the file.\r
1671**/\r
1672CONST CHAR16*\r
1673EFIAPI\r
1674ShellFileHandleGetPath(\r
1675 IN CONST SHELL_FILE_HANDLE Handle\r
1676 )\r
1677{\r
1678 BUFFER_LIST *Node;\r
1679\r
1680 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1681 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1682 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1683 ){\r
1684 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
1685 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1686 }\r
1687 }\r
1688 return (NULL);\r
1689}\r
1690\r
1691/**\r
1a63ec8f 1692 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.\r
a405b86d 1693\r
1694 @param[in] Handle The SHELL_FILE_HANDLE to remove.\r
1695\r
1696 @retval TRUE The item was removed.\r
1697 @retval FALSE The item was not found.\r
1698**/\r
1699BOOLEAN\r
1700EFIAPI\r
1701ShellFileHandleRemove(\r
1702 IN CONST SHELL_FILE_HANDLE Handle\r
1703 )\r
1704{\r
1705 BUFFER_LIST *Node;\r
1706\r
1707 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1708 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1709 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1710 ){\r
1711 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
a405b86d 1712 RemoveEntryList(&Node->Link);\r
ff51746b 1713 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1714 SHELL_FREE_NON_NULL(Node->Buffer);\r
1715 SHELL_FREE_NON_NULL(Node);\r
a405b86d 1716 return (TRUE);\r
1717 }\r
1718 }\r
1719 return (FALSE);\r
1720}\r
1721\r
1722/**\r
1723 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.\r
1724\r
1725 This will NOT work on directories.\r
1726\r
1727 If Handle is NULL, then ASSERT.\r
1728\r
1729 @param[in] Handle the file handle\r
1730\r
1731 @retval TRUE the position is at the end of the file\r
1732 @retval FALSE the position is not at the end of the file\r
1733**/\r
1734BOOLEAN\r
1735EFIAPI\r
1736ShellFileHandleEof(\r
1737 IN SHELL_FILE_HANDLE Handle\r
1738 )\r
1739{\r
1740 EFI_FILE_INFO *Info;\r
1741 UINT64 Pos;\r
1742 BOOLEAN RetVal;\r
1743\r
1744 //\r
1745 // ASSERT if Handle is NULL\r
1746 //\r
1747 ASSERT(Handle != NULL);\r
1748\r
1749 gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
1750 Info = gEfiShellProtocol->GetFileInfo (Handle);\r
a405b86d 1751 gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
1752\r
1753 if (Info == NULL) {\r
1754 return (FALSE);\r
1755 }\r
1756\r
1757 if (Pos == Info->FileSize) {\r
1758 RetVal = TRUE;\r
1759 } else {\r
1760 RetVal = FALSE;\r
1761 }\r
1762\r
1763 FreePool (Info);\r
1764\r
1765 return (RetVal);\r
1766}\r
1767\r
a405b86d 1768/**\r
1769 Frees any BUFFER_LIST defined type.\r
1a63ec8f 1770\r
1771 @param[in] List The BUFFER_LIST object to free.\r
a405b86d 1772**/\r
1773VOID\r
1774EFIAPI\r
1775FreeBufferList (\r
1776 IN BUFFER_LIST *List\r
1777 )\r
1778{\r
1779 BUFFER_LIST *BufferListEntry;\r
1780\r
1781 if (List == NULL){\r
1782 return;\r
1783 }\r
1784 //\r
1785 // enumerate through the buffer list and free all memory\r
1786 //\r
1787 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
1788 ; !IsListEmpty (&List->Link)\r
1789 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
1790 ){\r
1791 RemoveEntryList(&BufferListEntry->Link);\r
a405b86d 1792 if (BufferListEntry->Buffer != NULL) {\r
1793 FreePool(BufferListEntry->Buffer);\r
1794 }\r
1795 FreePool(BufferListEntry);\r
1796 }\r
1797}\r
1798\r
3bd89603
LE
1799/**\r
1800 Dump some hexadecimal data to the screen.\r
1801\r
1802 @param[in] Indent How many spaces to indent the output.\r
1803 @param[in] Offset The offset of the printing.\r
1804 @param[in] DataSize The size in bytes of UserData.\r
1805 @param[in] UserData The data to print out.\r
1806**/\r
1807VOID\r
667d7146 1808EFIAPI\r
3bd89603
LE
1809DumpHex (\r
1810 IN UINTN Indent,\r
1811 IN UINTN Offset,\r
1812 IN UINTN DataSize,\r
1813 IN VOID *UserData\r
1814 )\r
1815{\r
1816 UINT8 *Data;\r
1817\r
1818 CHAR8 Val[50];\r
1819\r
1820 CHAR8 Str[20];\r
1821\r
1822 UINT8 TempByte;\r
1823 UINTN Size;\r
1824 UINTN Index;\r
1825\r
1826 Data = UserData;\r
1827 while (DataSize != 0) {\r
1828 Size = 16;\r
1829 if (Size > DataSize) {\r
1830 Size = DataSize;\r
1831 }\r
1832\r
1833 for (Index = 0; Index < Size; Index += 1) {\r
1834 TempByte = Data[Index];\r
1835 Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
1836 Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
1837 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
4bf3b994 1838 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > '~') ? '.' : TempByte);\r
3bd89603
LE
1839 }\r
1840\r
1841 Val[Index * 3] = 0;\r
1842 Str[Index] = 0;\r
1843 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
1844\r
1845 Data += Size;\r
1846 Offset += Size;\r
1847 DataSize -= Size;\r
1848 }\r
1849}\r
cf041fd7
RN
1850\r
1851/**\r
1852 Dump HEX data into buffer.\r
1853\r
1854 @param[in] Buffer HEX data to be dumped in Buffer.\r
1855 @param[in] Indent How many spaces to indent the output.\r
1856 @param[in] Offset The offset of the printing.\r
1857 @param[in] DataSize The size in bytes of UserData.\r
1858 @param[in] UserData The data to print out.\r
1859**/\r
1860CHAR16*\r
667d7146 1861EFIAPI\r
cf041fd7
RN
1862CatSDumpHex (\r
1863 IN CHAR16 *Buffer,\r
1864 IN UINTN Indent,\r
1865 IN UINTN Offset,\r
1866 IN UINTN DataSize,\r
1867 IN VOID *UserData\r
1868 )\r
1869{\r
1870 UINT8 *Data;\r
1871 UINT8 TempByte;\r
1872 UINTN Size;\r
1873 UINTN Index;\r
1874 CHAR8 Val[50];\r
1875 CHAR8 Str[20];\r
1876 CHAR16 *RetVal;\r
1877 CHAR16 *TempRetVal;\r
1878\r
1879 Data = UserData;\r
1880 RetVal = Buffer;\r
1881 while (DataSize != 0) {\r
1882 Size = 16;\r
1883 if (Size > DataSize) {\r
1884 Size = DataSize;\r
1885 }\r
1886\r
1887 for (Index = 0; Index < Size; Index += 1) {\r
1888 TempByte = Data[Index];\r
1889 Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
1890 Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
1891 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
1892 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
1893 }\r
1894\r
1895 Val[Index * 3] = 0;\r
1896 Str[Index] = 0;\r
1897 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
1898 SHELL_FREE_NON_NULL (RetVal);\r
1899 RetVal = TempRetVal;\r
1900\r
1901 Data += Size;\r
1902 Offset += Size;\r
1903 DataSize -= Size;\r
1904 }\r
1905\r
1906 return RetVal;\r
1907}\r