]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg/ConsistMapping.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
4f67c7ff 4 Copyright (c) 2009 - 2014, 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
a405b86d 549 ASSERT(Node != NULL);\r
53173337 550 Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);\r
a405b86d 551 ASSERT(Node->CommandString != NULL);\r
552\r
a405b86d 553 Node->GetManFileName = GetManFileName;\r
554 Node->CommandHandler = CommandHandler;\r
555 Node->LastError = CanAffectLE;\r
556 Node->HiiHandle = HiiHandle;\r
557 Node->ManFormatHelp = ManFormatHelp;\r
558\r
559 if ( StrLen(ProfileName)>0\r
560 && ((mProfileList != NULL\r
561 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)\r
562 ){\r
563 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));\r
564 if (mProfileList == NULL) {\r
565 //\r
566 // If this is the first make a leading ';'\r
567 //\r
568 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
569 }\r
570 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);\r
571 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
572 }\r
573\r
574 //\r
d51088b7 575 // Insert a new entry on top of the list\r
576 //\r
577 InsertHeadList (&mCommandList.Link, &Node->Link);\r
578\r
579 //\r
580 // Move a new registered command to its sorted ordered location in the list\r
a405b86d 581 //\r
d51088b7 582 for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),\r
583 PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)\r
584 ; !IsNull (&mCommandList.Link, &Command->Link)\r
585 ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {\r
586\r
587 //\r
588 // Get Lexical Comparison Value between PrevCommand and Command list entry\r
589 //\r
590 LexicalMatchValue = gUnicodeCollation->StriColl (\r
591 gUnicodeCollation,\r
592 PrevCommand->CommandString,\r
593 Command->CommandString\r
594 );\r
595\r
596 //\r
597 // Swap PrevCommand and Command list entry if PrevCommand list entry\r
598 // is alphabetically greater than Command list entry\r
599 //\r
600 if (LexicalMatchValue > 0){\r
601 Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);\r
602 } else if (LexicalMatchValue < 0) {\r
603 //\r
604 // PrevCommand entry is lexically lower than Command entry\r
605 //\r
606 break;\r
607 }\r
608 }\r
a405b86d 609\r
610 return (RETURN_SUCCESS);\r
611}\r
612\r
613/**\r
614 Function to get the current Profile string.\r
615\r
616 @retval NULL There are no installed profiles.\r
617 @return A semi-colon delimited list of profiles.\r
618**/\r
619CONST CHAR16 *\r
620EFIAPI\r
621ShellCommandGetProfileList (\r
622 VOID\r
623 )\r
624{\r
625 return (mProfileList);\r
626}\r
627\r
628/**\r
629 Checks if a command string has been registered for CommandString and if so it runs\r
630 the previously registered handler for that command with the command line.\r
631\r
632 If CommandString is NULL, then ASSERT().\r
633\r
634 If Sections is specified, then each section name listed will be compared in a casesensitive\r
635 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,\r
636 it will be appended to the returned help text. If the section does not exist, no\r
637 information will be returned. If Sections is NULL, then all help text information\r
638 available will be returned.\r
639\r
4ff7e37b
ED
640 @param[in] CommandString Pointer to the command name. This is the name\r
641 found on the command line in the shell.\r
642 @param[in, out] RetVal Pointer to the return vaule from the command handler.\r
a405b86d 643\r
4ff7e37b
ED
644 @param[in, out] CanAffectLE indicates whether this command's return value\r
645 needs to be placed into LASTERROR environment variable.\r
a405b86d 646\r
647 @retval RETURN_SUCCESS The handler was run.\r
648 @retval RETURN_NOT_FOUND The CommandString did not match a registered\r
649 command name.\r
650 @sa SHELL_RUN_COMMAND\r
651**/\r
652RETURN_STATUS\r
653EFIAPI\r
654ShellCommandRunCommandHandler (\r
655 IN CONST CHAR16 *CommandString,\r
656 IN OUT SHELL_STATUS *RetVal,\r
657 IN OUT BOOLEAN *CanAffectLE OPTIONAL\r
658 )\r
659{\r
cf812a20
JC
660 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
661 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
a405b86d 662\r
663 //\r
664 // assert for NULL parameters\r
665 //\r
666 ASSERT(CommandString != NULL);\r
667\r
668 //\r
669 // check for the command\r
670 //\r
671 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
672 ; !IsNull(&mCommandList.Link, &Node->Link)\r
673 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
674 ){\r
675 ASSERT(Node->CommandString != NULL);\r
676 if (gUnicodeCollation->StriColl(\r
677 gUnicodeCollation,\r
678 (CHAR16*)CommandString,\r
679 Node->CommandString) == 0\r
cf812a20 680 ){\r
a405b86d 681 if (CanAffectLE != NULL) {\r
682 *CanAffectLE = Node->LastError;\r
683 }\r
684 if (RetVal != NULL) {\r
685 *RetVal = Node->CommandHandler(NULL, gST);\r
686 } else {\r
687 Node->CommandHandler(NULL, gST);\r
688 }\r
689 return (RETURN_SUCCESS);\r
690 }\r
691 }\r
cf812a20
JC
692\r
693 //\r
694 // An internal command was not found, try to find a dynamic command\r
695 //\r
696 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
697 if (DynamicCommand != NULL) {\r
698 if (RetVal != NULL) {\r
699 *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
700 } else {\r
701 DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
702 }\r
703 return (RETURN_SUCCESS);\r
704 }\r
705\r
a405b86d 706 return (RETURN_NOT_FOUND);\r
707}\r
708\r
709/**\r
710 Checks if a command string has been registered for CommandString and if so it\r
711 returns the MAN filename specified for that command.\r
712\r
713 If CommandString is NULL, then ASSERT().\r
714\r
715 @param[in] CommandString Pointer to the command name. This is the name\r
716 found on the command line in the shell.\\r
717\r
718 @retval NULL the commandString was not a registered command.\r
719 @return other the name of the MAN file.\r
720 @sa SHELL_GET_MAN_FILENAME\r
721**/\r
722CONST CHAR16*\r
723EFIAPI\r
724ShellCommandGetManFileNameHandler (\r
725 IN CONST CHAR16 *CommandString\r
726 )\r
727{\r
728 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
729\r
730 //\r
731 // assert for NULL parameters\r
732 //\r
733 ASSERT(CommandString != NULL);\r
734\r
735 //\r
736 // check for the command\r
737 //\r
738 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
739 ; !IsNull(&mCommandList.Link, &Node->Link)\r
740 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
741 ){\r
742 ASSERT(Node->CommandString != NULL);\r
743 if (gUnicodeCollation->StriColl(\r
744 gUnicodeCollation,\r
745 (CHAR16*)CommandString,\r
746 Node->CommandString) == 0\r
747 ){\r
748 return (Node->GetManFileName());\r
749 }\r
750 }\r
751 return (NULL);\r
752}\r
753\r
754/**\r
755 Get the list of all available shell internal commands. This is a linked list\r
756 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
757 list functions. do not modify the values.\r
758\r
1a63ec8f 759 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.\r
760\r
a405b86d 761 @return a Linked list of all available shell commands.\r
762**/\r
763CONST COMMAND_LIST*\r
764EFIAPI\r
765ShellCommandGetCommandList (\r
1a63ec8f 766 IN CONST BOOLEAN Sort\r
a405b86d 767 )\r
768{\r
1a63ec8f 769// if (!Sort) {\r
770// return ((COMMAND_LIST*)(&mCommandList));\r
771// }\r
a405b86d 772 return ((COMMAND_LIST*)(&mCommandList));\r
773}\r
774\r
775/**\r
776 Registers aliases to be set as part of the initialization of the shell application.\r
777\r
778 If Command is NULL, then ASSERT().\r
779 If Alias is NULL, then ASSERT().\r
780\r
781 @param[in] Command Pointer to the Command\r
782 @param[in] Alias Pointer to Alias\r
783\r
784 @retval RETURN_SUCCESS The handlers were registered.\r
785 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
786 register the shell command.\r
787**/\r
788RETURN_STATUS\r
789EFIAPI\r
790ShellCommandRegisterAlias (\r
791 IN CONST CHAR16 *Command,\r
792 IN CONST CHAR16 *Alias\r
793 )\r
794{\r
795 ALIAS_LIST *Node;\r
4ba9b812
TS
796 ALIAS_LIST *CommandAlias;\r
797 ALIAS_LIST *PrevCommandAlias; \r
798 INTN LexicalMatchValue;\r
a405b86d 799\r
800 //\r
801 // Asserts for NULL\r
802 //\r
803 ASSERT(Command != NULL);\r
804 ASSERT(Alias != NULL);\r
805\r
806 //\r
807 // allocate memory for new struct\r
808 //\r
1a63ec8f 809 Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
a405b86d 810 ASSERT(Node != NULL);\r
53173337
JC
811 Node->CommandString = AllocateCopyPool(StrSize(Command), Command);\r
812 Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);\r
a405b86d 813 ASSERT(Node->CommandString != NULL);\r
814 ASSERT(Node->Alias != NULL);\r
815\r
4ba9b812
TS
816 InsertHeadList (&mAliasList.Link, &Node->Link);\r
817\r
a405b86d 818 //\r
4ba9b812 819 // Move a new pre-defined registered alias to its sorted ordered location in the list\r
a405b86d 820 //\r
4ba9b812
TS
821 for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),\r
822 PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)\r
823 ; !IsNull (&mAliasList.Link, &CommandAlias->Link)\r
824 ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {\r
825 //\r
826 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry\r
827 //\r
828 LexicalMatchValue = gUnicodeCollation->StriColl (\r
829 gUnicodeCollation,\r
830 PrevCommandAlias->Alias,\r
831 CommandAlias->Alias\r
832 );\r
833\r
834 //\r
835 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry\r
836 // is alphabetically greater than CommandAlias list entry\r
837 // \r
838 if (LexicalMatchValue > 0) {\r
839 CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);\r
840 } else if (LexicalMatchValue < 0) {\r
841 //\r
842 // PrevCommandAlias entry is lexically lower than CommandAlias entry\r
843 //\r
844 break;\r
845 }\r
846 }\r
a405b86d 847\r
848 return (RETURN_SUCCESS);\r
849}\r
850\r
851/**\r
852 Get the list of all shell alias commands. This is a linked list\r
853 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
854 list functions. do not modify the values.\r
855\r
856 @return a Linked list of all requested shell alias'.\r
857**/\r
858CONST ALIAS_LIST*\r
859EFIAPI\r
860ShellCommandGetInitAliasList (\r
861 VOID\r
862 )\r
863{\r
864 return (&mAliasList);\r
865}\r
866\r
867/**\r
1a63ec8f 868 Determine if a given alias is on the list of built in alias'.\r
a405b86d 869\r
870 @param[in] Alias The alias to test for\r
871\r
872 @retval TRUE The alias is a built in alias\r
873 @retval FALSE The alias is not a built in alias\r
874**/\r
875BOOLEAN\r
876EFIAPI\r
877ShellCommandIsOnAliasList(\r
878 IN CONST CHAR16 *Alias\r
879 )\r
880{\r
881 ALIAS_LIST *Node;\r
882\r
883 //\r
884 // assert for NULL parameter\r
885 //\r
886 ASSERT(Alias != NULL);\r
887\r
888 //\r
889 // check for the Alias\r
890 //\r
891 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)\r
892 ; !IsNull(&mAliasList.Link, &Node->Link)\r
893 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)\r
894 ){\r
895 ASSERT(Node->CommandString != NULL);\r
896 ASSERT(Node->Alias != NULL);\r
897 if (gUnicodeCollation->StriColl(\r
898 gUnicodeCollation,\r
899 (CHAR16*)Alias,\r
900 Node->CommandString) == 0\r
901 ){\r
902 return (TRUE);\r
903 }\r
904 if (gUnicodeCollation->StriColl(\r
905 gUnicodeCollation,\r
906 (CHAR16*)Alias,\r
907 Node->Alias) == 0\r
908 ){\r
909 return (TRUE);\r
910 }\r
911 }\r
912 return (FALSE);\r
913}\r
914\r
915/**\r
cceb4ebd 916 Function to determine current state of ECHO. Echo determines if lines from scripts\r
a405b86d 917 and ECHO commands are enabled.\r
918\r
919 @retval TRUE Echo is currently enabled\r
920 @retval FALSE Echo is currently disabled\r
921**/\r
922BOOLEAN\r
923EFIAPI\r
924ShellCommandGetEchoState(\r
925 VOID\r
926 )\r
927{\r
928 return (mEchoState);\r
929}\r
930\r
931/**\r
cceb4ebd 932 Function to set current state of ECHO. Echo determines if lines from scripts\r
a405b86d 933 and ECHO commands are enabled.\r
934\r
935 If State is TRUE, Echo will be enabled.\r
936 If State is FALSE, Echo will be disabled.\r
1a63ec8f 937\r
938 @param[in] State How to set echo.\r
a405b86d 939**/\r
940VOID\r
941EFIAPI\r
942ShellCommandSetEchoState(\r
943 IN BOOLEAN State\r
944 )\r
945{\r
946 mEchoState = State;\r
947}\r
948\r
949/**\r
950 Indicate that the current shell or script should exit.\r
951\r
b6b22b13 952 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.\r
953 @param[in] ErrorCode The 64 bit error code to return.\r
a405b86d 954**/\r
955VOID\r
956EFIAPI\r
957ShellCommandRegisterExit (\r
b6b22b13 958 IN BOOLEAN ScriptOnly,\r
959 IN CONST UINT64 ErrorCode\r
a405b86d 960 )\r
961{\r
962 mExitRequested = (BOOLEAN)(!mExitRequested);\r
963 if (mExitRequested) {\r
964 mExitScript = ScriptOnly;\r
965 } else {\r
966 mExitScript = FALSE;\r
967 }\r
b6b22b13 968 mExitCode = ErrorCode;\r
a405b86d 969}\r
970\r
971/**\r
972 Retrieve the Exit indicator.\r
973\r
974 @retval TRUE Exit was indicated.\r
975 @retval FALSE Exis was not indicated.\r
976**/\r
977BOOLEAN\r
978EFIAPI\r
979ShellCommandGetExit (\r
980 VOID\r
981 )\r
982{\r
983 return (mExitRequested);\r
984}\r
985\r
b6b22b13 986/**\r
987 Retrieve the Exit code.\r
988\r
989 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
990\r
991 @return the value passed into RegisterExit.\r
992**/\r
993UINT64\r
994EFIAPI\r
995ShellCommandGetExitCode (\r
996 VOID\r
997 )\r
998{\r
999 return (mExitCode);\r
1000}\r
a405b86d 1001/**\r
1002 Retrieve the Exit script indicator.\r
1003\r
1004 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
1005\r
1006 @retval TRUE ScriptOnly was indicated.\r
1007 @retval FALSE ScriptOnly was not indicated.\r
1008**/\r
1009BOOLEAN\r
1010EFIAPI\r
1011ShellCommandGetScriptExit (\r
1012 VOID\r
1013 )\r
1014{\r
1015 return (mExitScript);\r
1016}\r
1017\r
1018/**\r
1019 Function to cleanup all memory from a SCRIPT_FILE structure.\r
1020\r
1021 @param[in] Script The pointer to the structure to cleanup.\r
1022**/\r
1023VOID\r
1024EFIAPI\r
1025DeleteScriptFileStruct (\r
1026 IN SCRIPT_FILE *Script\r
1027 )\r
1028{\r
1029 UINT8 LoopVar;\r
0ab85bef 1030\r
1031 if (Script == NULL) {\r
1032 return;\r
1033 }\r
1034\r
a405b86d 1035 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {\r
0ab85bef 1036 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);\r
a405b86d 1037 }\r
1038 if (Script->Argv != NULL) {\r
0ab85bef 1039 SHELL_FREE_NON_NULL(Script->Argv);\r
a405b86d 1040 }\r
1041 Script->CurrentCommand = NULL;\r
1042 while (!IsListEmpty (&Script->CommandList)) {\r
1043 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);\r
1044 if (Script->CurrentCommand != NULL) {\r
1045 RemoveEntryList(&Script->CurrentCommand->Link);\r
1046 if (Script->CurrentCommand->Cl != NULL) {\r
0ab85bef 1047 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);\r
a405b86d 1048 }\r
1049 if (Script->CurrentCommand->Data != NULL) {\r
0ab85bef 1050 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);\r
a405b86d 1051 }\r
0ab85bef 1052 SHELL_FREE_NON_NULL(Script->CurrentCommand);\r
a405b86d 1053 }\r
1054 }\r
0ab85bef 1055 SHELL_FREE_NON_NULL(Script->ScriptName);\r
1056 SHELL_FREE_NON_NULL(Script);\r
a405b86d 1057}\r
1058\r
1059/**\r
1060 Function to return a pointer to the currently running script file object.\r
1061\r
1062 @retval NULL A script file is not currently running.\r
1063 @return A pointer to the current script file object.\r
1064**/\r
1065SCRIPT_FILE*\r
1066EFIAPI\r
1067ShellCommandGetCurrentScriptFile (\r
1068 VOID\r
1069 )\r
1070{\r
1071 SCRIPT_FILE_LIST *List;\r
1072 if (IsListEmpty (&mScriptList.Link)) {\r
1073 return (NULL);\r
1074 }\r
1075 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));\r
1076 return (List->Data);\r
1077}\r
1078\r
1079/**\r
1080 Function to set a new script as the currently running one.\r
1081\r
1082 This function will correctly stack and unstack nested scripts.\r
1083\r
1084 @param[in] Script Pointer to new script information structure. if NULL\r
1085 will remove and de-allocate the top-most Script structure.\r
1086\r
1087 @return A pointer to the current running script file after this\r
1088 change. NULL if removing the final script.\r
1089**/\r
1090SCRIPT_FILE*\r
1091EFIAPI\r
1092ShellCommandSetNewScript (\r
1093 IN SCRIPT_FILE *Script OPTIONAL\r
1094 )\r
1095{\r
1096 SCRIPT_FILE_LIST *Node;\r
1097 if (Script == NULL) {\r
1098 if (IsListEmpty (&mScriptList.Link)) {\r
a405b86d 1099 return (NULL);\r
1100 }\r
1101 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
1102 RemoveEntryList(&Node->Link);\r
1103 DeleteScriptFileStruct(Node->Data);\r
1104 FreePool(Node);\r
1105 } else {\r
1106 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));\r
0ab85bef 1107 if (Node == NULL) {\r
1108 return (NULL);\r
1109 }\r
a405b86d 1110 Node->Data = Script;\r
1111 InsertHeadList(&mScriptList.Link, &Node->Link);\r
1112 }\r
1113 return (ShellCommandGetCurrentScriptFile());\r
1114}\r
1115\r
1116/**\r
1117 Function to generate the next default mapping name.\r
1118\r
1119 If the return value is not NULL then it must be callee freed.\r
1120\r
1121 @param Type What kind of mapping name to make.\r
1122\r
1123 @retval NULL a memory allocation failed.\r
1124 @return a new map name string\r
1125**/\r
1126CHAR16*\r
1127EFIAPI\r
1128ShellCommandCreateNewMappingName(\r
1129 IN CONST SHELL_MAPPING_TYPE Type\r
1130 )\r
1131{\r
1132 CHAR16 *String;\r
1133 ASSERT(Type < MappingTypeMax);\r
1134\r
1135 String = NULL;\r
1136\r
1137 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));\r
1138 UnicodeSPrint(\r
1139 String,\r
1140 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),\r
1141 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",\r
1142 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);\r
1143\r
1144 return (String);\r
1145}\r
1146\r
1147/**\r
1148 Function to add a map node to the list of map items and update the "path" environment variable (optionally).\r
1149\r
1150 If Path is TRUE (during initialization only), the path environment variable will also be updated to include\r
1151 default paths on the new map name...\r
1152\r
1153 Path should be FALSE when this function is called from the protocol SetMap function.\r
1154\r
1155 @param[in] Name The human readable mapped name.\r
1156 @param[in] DevicePath The Device Path for this map.\r
1157 @param[in] Flags The Flags attribute for this map item.\r
1158 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).\r
1159\r
1160 @retval EFI_SUCCESS The addition was sucessful.\r
1161 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
1162 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
1163**/\r
1164EFI_STATUS\r
1165EFIAPI\r
1166ShellCommandAddMapItemAndUpdatePath(\r
1167 IN CONST CHAR16 *Name,\r
1168 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1169 IN CONST UINT64 Flags,\r
1170 IN CONST BOOLEAN Path\r
1171 )\r
1172{\r
1173 EFI_STATUS Status;\r
1174 SHELL_MAP_LIST *MapListNode;\r
1175 CONST CHAR16 *OriginalPath;\r
1176 CHAR16 *NewPath;\r
1177 UINTN NewPathSize;\r
1178\r
1179 NewPathSize = 0;\r
1180 NewPath = NULL;\r
1181 OriginalPath = NULL;\r
1182 Status = EFI_SUCCESS;\r
1183\r
1184 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));\r
1185 if (MapListNode == NULL) {\r
1186 Status = EFI_OUT_OF_RESOURCES;\r
1187 } else {\r
1188 MapListNode->Flags = Flags;\r
3957a5a5 1189 MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);\r
a405b86d 1190 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
1191 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
1192 Status = EFI_OUT_OF_RESOURCES;\r
1193 } else {\r
a405b86d 1194 InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
1195 }\r
1196 }\r
1197 if (EFI_ERROR(Status)) {\r
1198 if (MapListNode != NULL) {\r
1199 if (MapListNode->DevicePath != NULL) {\r
1200 FreePool(MapListNode->DevicePath);\r
1201 }\r
1202 if (MapListNode->MapName != NULL) {\r
1203 FreePool(MapListNode->MapName);\r
1204 }\r
1205 FreePool(MapListNode);\r
1206 }\r
1207 } else if (Path) {\r
1208 //\r
1209 // Since there was no error and Path was TRUE\r
1210 // Now add the correct path for that mapping\r
1211 //\r
1212 OriginalPath = gEfiShellProtocol->GetEnv(L"path");\r
1213 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
1214 if (OriginalPath != NULL) {\r
1215 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
1216 } else {\r
1217 StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);\r
1218 }\r
1219 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
1220 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1221 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
1222 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1223 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);\r
1224 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1225 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);\r
1226\r
1227 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);\r
1228 ASSERT_EFI_ERROR(Status);\r
1229 FreePool(NewPath);\r
1230 }\r
1231 return (Status);\r
1232}\r
1233\r
1234/**\r
1235 Creates the default map names for each device path in the system with\r
1236 a protocol depending on the Type.\r
1237\r
1238 Creates the consistent map names for each device path in the system with\r
1239 a protocol depending on the Type.\r
1240\r
1241 Note: This will reset all mappings in the system("map -r").\r
1242\r
1243 Also sets up the default path environment variable if Type is FileSystem.\r
1244\r
1245 @retval EFI_SUCCESS All map names were created sucessfully.\r
1246 @retval EFI_NOT_FOUND No protocols were found in the system.\r
1247 @return Error returned from gBS->LocateHandle().\r
1248\r
1249 @sa LocateHandle\r
1250**/\r
1251EFI_STATUS\r
1252EFIAPI\r
1253ShellCommandCreateInitialMappingsAndPaths(\r
1254 VOID\r
1255 )\r
1256{\r
1257 EFI_STATUS Status;\r
1258 EFI_HANDLE *HandleList;\r
1259 UINTN Count;\r
1260 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1261 CHAR16 *NewDefaultName;\r
1262 CHAR16 *NewConsistName;\r
1263 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1264 SHELL_MAP_LIST *MapListNode;\r
1265\r
1266 HandleList = NULL;\r
1267\r
1268 //\r
1269 // Reset the static members back to zero\r
1270 //\r
1271 mFsMaxCount = 0;\r
1272 mBlkMaxCount = 0;\r
1273\r
1274 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);\r
1275\r
1276 //\r
1277 // First empty out the existing list.\r
1278 //\r
1279 if (!IsListEmpty(&gShellMapList.Link)) {\r
1280 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1281 ; !IsListEmpty(&gShellMapList.Link)\r
1282 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1283 ){\r
1284 RemoveEntryList(&MapListNode->Link);\r
c8cfd83a
JY
1285 SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
1286 SHELL_FREE_NON_NULL(MapListNode->MapName);\r
1287 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
a405b86d 1288 FreePool(MapListNode);\r
1289 } // for loop\r
1290 }\r
1291\r
1292 //\r
1293 // Find each handle with Simple File System\r
1294 //\r
0ab85bef 1295 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
a405b86d 1296 if (HandleList != NULL) {\r
1297 //\r
1298 // Do a count of the handles\r
1299 //\r
1300 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1301\r
1302 //\r
1303 // Get all Device Paths\r
1304 //\r
1a63ec8f 1305 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
a405b86d 1306 ASSERT(DevicePathList != NULL);\r
1307\r
1308 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1309 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1310 }\r
1311\r
1312 //\r
1313 // Sort all DevicePaths\r
1314 //\r
1315 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1316\r
1317 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1318 //\r
1319 // Assign new Mappings to all...\r
1320 //\r
1321 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1322 //\r
1323 // Get default name first\r
1324 //\r
1325 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
1326 ASSERT(NewDefaultName != NULL);\r
1327 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);\r
1328 ASSERT_EFI_ERROR(Status);\r
1329 FreePool(NewDefaultName);\r
1330\r
1331 //\r
1332 // Now do consistent name\r
1333 //\r
1334 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1335 if (NewConsistName != NULL) {\r
1336 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);\r
1337 ASSERT_EFI_ERROR(Status);\r
1338 FreePool(NewConsistName);\r
1339 }\r
1340 }\r
1341\r
1342 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1343\r
1344 SHELL_FREE_NON_NULL(HandleList);\r
1345 SHELL_FREE_NON_NULL(DevicePathList);\r
1346\r
1347 HandleList = NULL;\r
1348 } else {\r
1349 Count = (UINTN)-1;\r
1350 }\r
1351\r
1352 //\r
1353 // Find each handle with Block Io\r
1354 //\r
0ab85bef 1355 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);\r
a405b86d 1356 if (HandleList != NULL) {\r
1357 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1358\r
1359 //\r
1360 // Get all Device Paths\r
1361 //\r
1a63ec8f 1362 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
a405b86d 1363 ASSERT(DevicePathList != NULL);\r
1364\r
1365 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1366 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1367 }\r
1368\r
1369 //\r
1370 // Sort all DevicePaths\r
1371 //\r
1372 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1373\r
1374 //\r
1375 // Assign new Mappings to all...\r
1376 //\r
1377 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1378 //\r
1379 // Get default name first\r
1380 //\r
1381 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);\r
1382 ASSERT(NewDefaultName != NULL);\r
1383 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);\r
1384 ASSERT_EFI_ERROR(Status);\r
1385 FreePool(NewDefaultName);\r
1386 }\r
1387\r
1388 SHELL_FREE_NON_NULL(HandleList);\r
1389 SHELL_FREE_NON_NULL(DevicePathList);\r
1390 } else if (Count == (UINTN)-1) {\r
1391 return (EFI_NOT_FOUND);\r
1392 }\r
1393\r
1394 return (EFI_SUCCESS);\r
cf812a20
JC
1395}\r
1396\r
1397/**\r
1398 Add mappings for any devices without one. Do not change any existing maps.\r
1399\r
1400 @retval EFI_SUCCESS The operation was successful.\r
1401**/\r
1402EFI_STATUS\r
1403EFIAPI\r
1404ShellCommandUpdateMapping (\r
1405 VOID\r
1406 )\r
1407{\r
1408 EFI_STATUS Status;\r
1409 EFI_HANDLE *HandleList;\r
1410 UINTN Count;\r
1411 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1412 CHAR16 *NewDefaultName;\r
1413 CHAR16 *NewConsistName;\r
1414 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1415\r
1416 HandleList = NULL;\r
1417 Status = EFI_SUCCESS;\r
1418\r
1419 //\r
1420 // remove mappings that represent removed devices.\r
1421 //\r
1422\r
1423 //\r
1424 // Find each handle with Simple File System\r
1425 //\r
1426 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
1427 if (HandleList != NULL) {\r
1428 //\r
1429 // Do a count of the handles\r
1430 //\r
1431 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1432\r
1433 //\r
1434 // Get all Device Paths\r
1435 //\r
1436 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
ae315cc2
JC
1437 if (DevicePathList == NULL) {\r
1438 return (EFI_OUT_OF_RESOURCES);\r
1439 }\r
cf812a20
JC
1440\r
1441 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1442 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1443 }\r
1444\r
1445 //\r
1446 // Sort all DevicePaths\r
1447 //\r
1448 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1449\r
1450 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1451\r
1452 //\r
1453 // Assign new Mappings to remainders\r
1454 //\r
ae315cc2 1455 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {\r
cf812a20
JC
1456 //\r
1457 // Skip ones that already have\r
1458 //\r
1459 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {\r
1460 continue;\r
1461 }\r
1462 //\r
1463 // Get default name\r
1464 //\r
1465 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
ae315cc2
JC
1466 if (NewDefaultName == NULL) {\r
1467 Status = EFI_OUT_OF_RESOURCES;\r
1468 break;\r
1469 }\r
cf812a20
JC
1470\r
1471 //\r
1472 // Call shell protocol SetMap function now...\r
1473 //\r
1474 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);\r
1475\r
1476 if (!EFI_ERROR(Status)) {\r
1477 //\r
1478 // Now do consistent name\r
1479 //\r
1480 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1481 if (NewConsistName != NULL) {\r
1482 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);\r
1483 FreePool(NewConsistName);\r
1484 }\r
1485 }\r
1486\r
1487 FreePool(NewDefaultName);\r
1488 }\r
1489 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1490 SHELL_FREE_NON_NULL(HandleList);\r
1491 SHELL_FREE_NON_NULL(DevicePathList);\r
1492\r
1493 HandleList = NULL;\r
1494 } else {\r
1495 Count = (UINTN)-1;\r
1496 }\r
1497 //\r
1498 // Do it all over again for gEfiBlockIoProtocolGuid\r
1499 //\r
1500\r
1501 return (Status);\r
1502}\r
1503\r
1504/**\r
1505 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
1506\r
1507 @param[in] Handle The SHELL_FILE_HANDLE to convert.\r
a405b86d 1508\r
1509 @return a EFI_FILE_PROTOCOL* representing the same file.\r
1510**/\r
1511EFI_FILE_PROTOCOL*\r
1512EFIAPI\r
1513ConvertShellHandleToEfiFileProtocol(\r
1514 IN CONST SHELL_FILE_HANDLE Handle\r
1515 )\r
1516{\r
1517 return ((EFI_FILE_PROTOCOL*)(Handle));\r
1518}\r
1519\r
1520/**\r
1521 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.\r
1522\r
1523 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.\r
1524 @param[in] Path The path to the file for verification.\r
1525\r
ff51746b 1526 @return A SHELL_FILE_HANDLE representing the same file.\r
1527 @retval NULL There was not enough memory.\r
a405b86d 1528**/\r
1529SHELL_FILE_HANDLE\r
1530EFIAPI\r
1531ConvertEfiFileProtocolToShellHandle(\r
1532 IN CONST EFI_FILE_PROTOCOL *Handle,\r
1533 IN CONST CHAR16 *Path\r
1534 )\r
1535{\r
1536 SHELL_COMMAND_FILE_HANDLE *Buffer;\r
1537 BUFFER_LIST *NewNode;\r
1538\r
1539 if (Path != NULL) {\r
1540 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));\r
ff51746b 1541 if (Buffer == NULL) {\r
1542 return (NULL);\r
1543 }\r
1a63ec8f 1544 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ff51746b 1545 if (NewNode == NULL) {\r
ae315cc2 1546 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1547 return (NULL);\r
1548 }\r
a405b86d 1549 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;\r
1550 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
ff51746b 1551 if (Buffer->Path == NULL) {\r
ae315cc2
JC
1552 SHELL_FREE_NON_NULL(NewNode);\r
1553 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1554 return (NULL);\r
1555 }\r
a405b86d 1556 NewNode->Buffer = Buffer;\r
1557\r
1558 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);\r
1559 }\r
1560 return ((SHELL_FILE_HANDLE)(Handle));\r
1561}\r
1562\r
1563/**\r
1564 Find the path that was logged with the specified SHELL_FILE_HANDLE.\r
1565\r
1566 @param[in] Handle The SHELL_FILE_HANDLE to query on.\r
1567\r
1568 @return A pointer to the path for the file.\r
1569**/\r
1570CONST CHAR16*\r
1571EFIAPI\r
1572ShellFileHandleGetPath(\r
1573 IN CONST SHELL_FILE_HANDLE Handle\r
1574 )\r
1575{\r
1576 BUFFER_LIST *Node;\r
1577\r
1578 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1579 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1580 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1581 ){\r
1582 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
1583 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1584 }\r
1585 }\r
1586 return (NULL);\r
1587}\r
1588\r
1589/**\r
1a63ec8f 1590 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.\r
a405b86d 1591\r
1592 @param[in] Handle The SHELL_FILE_HANDLE to remove.\r
1593\r
1594 @retval TRUE The item was removed.\r
1595 @retval FALSE The item was not found.\r
1596**/\r
1597BOOLEAN\r
1598EFIAPI\r
1599ShellFileHandleRemove(\r
1600 IN CONST SHELL_FILE_HANDLE Handle\r
1601 )\r
1602{\r
1603 BUFFER_LIST *Node;\r
1604\r
1605 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1606 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1607 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1608 ){\r
1609 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
a405b86d 1610 RemoveEntryList(&Node->Link);\r
ff51746b 1611 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1612 SHELL_FREE_NON_NULL(Node->Buffer);\r
1613 SHELL_FREE_NON_NULL(Node);\r
a405b86d 1614 return (TRUE);\r
1615 }\r
1616 }\r
1617 return (FALSE);\r
1618}\r
1619\r
1620/**\r
1621 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.\r
1622\r
1623 This will NOT work on directories.\r
1624\r
1625 If Handle is NULL, then ASSERT.\r
1626\r
1627 @param[in] Handle the file handle\r
1628\r
1629 @retval TRUE the position is at the end of the file\r
1630 @retval FALSE the position is not at the end of the file\r
1631**/\r
1632BOOLEAN\r
1633EFIAPI\r
1634ShellFileHandleEof(\r
1635 IN SHELL_FILE_HANDLE Handle\r
1636 )\r
1637{\r
1638 EFI_FILE_INFO *Info;\r
1639 UINT64 Pos;\r
1640 BOOLEAN RetVal;\r
1641\r
1642 //\r
1643 // ASSERT if Handle is NULL\r
1644 //\r
1645 ASSERT(Handle != NULL);\r
1646\r
1647 gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
1648 Info = gEfiShellProtocol->GetFileInfo (Handle);\r
a405b86d 1649 gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
1650\r
1651 if (Info == NULL) {\r
1652 return (FALSE);\r
1653 }\r
1654\r
1655 if (Pos == Info->FileSize) {\r
1656 RetVal = TRUE;\r
1657 } else {\r
1658 RetVal = FALSE;\r
1659 }\r
1660\r
1661 FreePool (Info);\r
1662\r
1663 return (RetVal);\r
1664}\r
1665\r
a405b86d 1666/**\r
1667 Frees any BUFFER_LIST defined type.\r
1a63ec8f 1668\r
1669 @param[in] List The BUFFER_LIST object to free.\r
a405b86d 1670**/\r
1671VOID\r
1672EFIAPI\r
1673FreeBufferList (\r
1674 IN BUFFER_LIST *List\r
1675 )\r
1676{\r
1677 BUFFER_LIST *BufferListEntry;\r
1678\r
1679 if (List == NULL){\r
1680 return;\r
1681 }\r
1682 //\r
1683 // enumerate through the buffer list and free all memory\r
1684 //\r
1685 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
1686 ; !IsListEmpty (&List->Link)\r
1687 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
1688 ){\r
1689 RemoveEntryList(&BufferListEntry->Link);\r
a405b86d 1690 if (BufferListEntry->Buffer != NULL) {\r
1691 FreePool(BufferListEntry->Buffer);\r
1692 }\r
1693 FreePool(BufferListEntry);\r
1694 }\r
1695}\r
1696\r
3bd89603
LE
1697/**\r
1698 Dump some hexadecimal data to the screen.\r
1699\r
1700 @param[in] Indent How many spaces to indent the output.\r
1701 @param[in] Offset The offset of the printing.\r
1702 @param[in] DataSize The size in bytes of UserData.\r
1703 @param[in] UserData The data to print out.\r
1704**/\r
1705VOID\r
1706DumpHex (\r
1707 IN UINTN Indent,\r
1708 IN UINTN Offset,\r
1709 IN UINTN DataSize,\r
1710 IN VOID *UserData\r
1711 )\r
1712{\r
1713 UINT8 *Data;\r
1714\r
1715 CHAR8 Val[50];\r
1716\r
1717 CHAR8 Str[20];\r
1718\r
1719 UINT8 TempByte;\r
1720 UINTN Size;\r
1721 UINTN Index;\r
1722\r
1723 Data = UserData;\r
1724 while (DataSize != 0) {\r
1725 Size = 16;\r
1726 if (Size > DataSize) {\r
1727 Size = DataSize;\r
1728 }\r
1729\r
1730 for (Index = 0; Index < Size; Index += 1) {\r
1731 TempByte = Data[Index];\r
1732 Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
1733 Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
1734 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
1735 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
1736 }\r
1737\r
1738 Val[Index * 3] = 0;\r
1739 Str[Index] = 0;\r
1740 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
1741\r
1742 Data += Size;\r
1743 Offset += Size;\r
1744 DataSize -= Size;\r
1745 }\r
1746}\r
cf6c1550
TS
1747
1748/**
1749 Dump HEX data into buffer.
1750
1751 @param[in] Buffer HEX data to be dumped in Buffer.
1752 @param[in] Indent How many spaces to indent the output.
1753 @param[in] Offset The offset of the printing.
1754 @param[in] DataSize The size in bytes of UserData.
1755 @param[in] UserData The data to print out.
1756**/
1757CHAR16*
1758CatSDumpHex (
1759 IN CHAR16 *Buffer,
1760 IN UINTN Indent,
1761 IN UINTN Offset,
1762 IN UINTN DataSize,
1763 IN VOID *UserData
1764 )
1765{
1766 UINT8 *Data;
1767 UINT8 TempByte;
1768 UINTN Size;
1769 UINTN Index;
1770 CHAR8 Val[50];
1771 CHAR8 Str[20];
1772 CHAR16 *RetVal;
1773 CHAR16 *TempRetVal;
1774
1775 Data = UserData;
1776 RetVal = Buffer;
1777 while (DataSize != 0) {
1778 Size = 16;
1779 if (Size > DataSize) {
1780 Size = DataSize;
1781 }
1782
1783 for (Index = 0; Index < Size; Index += 1) {
1784 TempByte = Data[Index];
1785 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1786 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1787 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1788 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1789 }
1790
1791 Val[Index * 3] = 0;
1792 Str[Index] = 0;
1793 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1794 SHELL_FREE_NON_NULL (RetVal);
1795 RetVal = TempRetVal;
1796
1797 Data += Size;
1798 Offset += Size;
1799 DataSize -= Size;
1800 }
1801
1802 return RetVal;
1803}