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