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