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