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