2 Provides interface to shell internal functions for shell commands.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "UefiShellCommandLib.h"
14 // STATIC local variables
15 STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList
;
16 STATIC SCRIPT_FILE_LIST mScriptList
;
17 STATIC ALIAS_LIST mAliasList
;
18 STATIC BOOLEAN mEchoState
;
19 STATIC BOOLEAN mExitRequested
;
20 STATIC UINT64 mExitCode
;
21 STATIC BOOLEAN mExitScript
;
22 STATIC CHAR16
*mProfileList
;
23 STATIC UINTN mProfileListSize
;
24 STATIC UINTN mFsMaxCount
= 0;
25 STATIC UINTN mBlkMaxCount
= 0;
26 STATIC BUFFER_LIST mFileHandleList
;
28 STATIC CONST CHAR8 Hex
[] = {
47 // global variables required by library class.
48 EFI_UNICODE_COLLATION_PROTOCOL
*gUnicodeCollation
= NULL
;
49 SHELL_MAP_LIST gShellMapList
;
50 SHELL_MAP_LIST
*gShellCurMapping
= NULL
;
52 CONST CHAR16
* SupportLevel
[] = {
60 Function to make sure that the global protocol pointers are valid.
61 must be called after constructor before accessing the pointers.
71 EFI_UNICODE_COLLATION_PROTOCOL
*Uc
;
77 GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME
, (VOID
**)&PlatformLang
, NULL
);
78 if (PlatformLang
== NULL
) {
79 return EFI_UNSUPPORTED
;
82 if (gUnicodeCollation
== NULL
) {
83 Status
= gBS
->LocateHandleBuffer (
85 &gEfiUnicodeCollation2ProtocolGuid
,
90 if (EFI_ERROR (Status
)) {
94 for (Index
= 0; Index
< NumHandles
; Index
++) {
96 // Open Unicode Collation Protocol
98 Status
= gBS
->OpenProtocol (
100 &gEfiUnicodeCollation2ProtocolGuid
,
104 EFI_OPEN_PROTOCOL_GET_PROTOCOL
106 if (EFI_ERROR (Status
)) {
111 // Find the best matching matching language from the supported languages
112 // of Unicode Collation2 protocol.
114 BestLanguage
= GetBestLanguage (
115 Uc
->SupportedLanguages
,
120 if (BestLanguage
!= NULL
) {
121 FreePool (BestLanguage
);
122 gUnicodeCollation
= Uc
;
126 if (Handles
!= NULL
) {
129 FreePool (PlatformLang
);
132 return (gUnicodeCollation
== NULL
) ? EFI_UNSUPPORTED
: EFI_SUCCESS
;
136 Constructor for the Shell Command library.
138 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
140 @param ImageHandle the image handle of the process
141 @param SystemTable the EFI System Table pointer
143 @retval EFI_SUCCESS the initialization was complete sucessfully
147 ShellCommandLibConstructor (
148 IN EFI_HANDLE ImageHandle
,
149 IN EFI_SYSTEM_TABLE
*SystemTable
153 InitializeListHead(&gShellMapList
.Link
);
154 InitializeListHead(&mCommandList
.Link
);
155 InitializeListHead(&mAliasList
.Link
);
156 InitializeListHead(&mScriptList
.Link
);
157 InitializeListHead(&mFileHandleList
.Link
);
160 mExitRequested
= FALSE
;
162 mProfileListSize
= 0;
165 Status
= CommandInit ();
166 if (EFI_ERROR (Status
)) {
167 return EFI_DEVICE_ERROR
;
170 return (RETURN_SUCCESS
);
174 Frees list of file handles.
176 @param[in] List The list to free.
183 BUFFER_LIST
*BufferListEntry
;
189 // enumerate through the buffer list and free all memory
191 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
192 ; !IsListEmpty (&List
->Link
)
193 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
195 RemoveEntryList(&BufferListEntry
->Link
);
196 ASSERT(BufferListEntry
->Buffer
!= NULL
);
197 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)(BufferListEntry
->Buffer
))->Path
);
198 SHELL_FREE_NON_NULL(BufferListEntry
->Buffer
);
199 SHELL_FREE_NON_NULL(BufferListEntry
);
204 Destructor for the library. free any resources.
206 @param ImageHandle the image handle of the process
207 @param SystemTable the EFI System Table pointer
209 @retval RETURN_SUCCESS this function always returns success
213 ShellCommandLibDestructor (
214 IN EFI_HANDLE ImageHandle
,
215 IN EFI_SYSTEM_TABLE
*SystemTable
218 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
220 SCRIPT_FILE_LIST
*Node3
;
221 SHELL_MAP_LIST
*MapNode
;
223 // enumerate throught the list and free all the memory
225 while (!IsListEmpty (&mCommandList
.Link
)) {
226 Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
);
227 RemoveEntryList(&Node
->Link
);
228 SHELL_FREE_NON_NULL(Node
->CommandString
);
230 DEBUG_CODE(Node
= NULL
;);
234 // enumerate through the alias list and free all memory
236 while (!IsListEmpty (&mAliasList
.Link
)) {
237 Node2
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
);
238 RemoveEntryList(&Node2
->Link
);
239 SHELL_FREE_NON_NULL(Node2
->CommandString
);
240 SHELL_FREE_NON_NULL(Node2
->Alias
);
241 SHELL_FREE_NON_NULL(Node2
);
242 DEBUG_CODE(Node2
= NULL
;);
246 // enumerate throught the list and free all the memory
248 while (!IsListEmpty (&mScriptList
.Link
)) {
249 Node3
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
250 RemoveEntryList(&Node3
->Link
);
251 DeleteScriptFileStruct(Node3
->Data
);
256 // enumerate throught the mappings list and free all the memory
258 if (!IsListEmpty(&gShellMapList
.Link
)) {
259 for (MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
260 ; !IsListEmpty (&gShellMapList
.Link
)
261 ; MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
263 ASSERT(MapNode
!= NULL
);
264 RemoveEntryList(&MapNode
->Link
);
265 SHELL_FREE_NON_NULL(MapNode
->DevicePath
);
266 SHELL_FREE_NON_NULL(MapNode
->MapName
);
267 SHELL_FREE_NON_NULL(MapNode
->CurrentDirectoryPath
);
271 if (!IsListEmpty(&mFileHandleList
.Link
)){
272 FreeFileHandleList(&mFileHandleList
);
275 if (mProfileList
!= NULL
) {
276 FreePool(mProfileList
);
279 gUnicodeCollation
= NULL
;
280 gShellCurMapping
= NULL
;
282 return (RETURN_SUCCESS
);
286 Find a dynamic command protocol instance given a command name string.
288 @param CommandString the command name string
290 @return instance the command protocol instance, if dynamic command instance found
291 @retval NULL no dynamic command protocol instance found for name
293 CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*
294 ShellCommandFindDynamicCommand (
295 IN CONST CHAR16
*CommandString
299 EFI_HANDLE
*CommandHandleList
;
300 EFI_HANDLE
*NextCommand
;
301 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
303 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
304 if (CommandHandleList
== NULL
) {
306 // not found or out of resources
311 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
312 Status
= gBS
->HandleProtocol(
314 &gEfiShellDynamicCommandProtocolGuid
,
315 (VOID
**)&DynamicCommand
318 if (EFI_ERROR(Status
)) {
322 if (gUnicodeCollation
->StriColl(
324 (CHAR16
*)CommandString
,
325 (CHAR16
*)DynamicCommand
->CommandName
) == 0
327 FreePool(CommandHandleList
);
328 return (DynamicCommand
);
332 FreePool(CommandHandleList
);
337 Checks if a command exists as a dynamic command protocol instance
339 @param[in] CommandString The command string to check for on the list.
342 ShellCommandDynamicCommandExists (
343 IN CONST CHAR16
*CommandString
346 return (BOOLEAN
) ((ShellCommandFindDynamicCommand(CommandString
) != NULL
));
350 Checks if a command is already on the internal command list.
352 @param[in] CommandString The command string to check for on the list.
355 ShellCommandIsCommandOnInternalList(
356 IN CONST CHAR16
*CommandString
359 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
362 // assert for NULL parameter
364 ASSERT(CommandString
!= NULL
);
367 // check for the command
369 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
370 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
371 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
373 ASSERT(Node
->CommandString
!= NULL
);
374 if (gUnicodeCollation
->StriColl(
376 (CHAR16
*)CommandString
,
377 Node
->CommandString
) == 0
386 Checks if a command exists, either internally or through the dynamic command protocol.
388 @param[in] CommandString The command string to check for on the list.
392 ShellCommandIsCommandOnList(
393 IN CONST CHAR16
*CommandString
396 if (ShellCommandIsCommandOnInternalList(CommandString
)) {
400 return ShellCommandDynamicCommandExists(CommandString
);
404 Get the help text for a dynamic command.
406 @param[in] CommandString The command name.
408 @retval NULL No help text was found.
409 @return String of help text. Caller required to free.
412 ShellCommandGetDynamicCommandHelp(
413 IN CONST CHAR16
*CommandString
416 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
418 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
419 if (DynamicCommand
== NULL
) {
424 // TODO: how to get proper language?
426 return DynamicCommand
->GetHelp(DynamicCommand
, "en");
430 Get the help text for an internal command.
432 @param[in] CommandString The command name.
434 @retval NULL No help text was found.
435 @return String of help text. Caller reuiqred to free.
438 ShellCommandGetInternalCommandHelp(
439 IN CONST CHAR16
*CommandString
442 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
445 // assert for NULL parameter
447 ASSERT(CommandString
!= NULL
);
450 // check for the command
452 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
453 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
454 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
456 ASSERT(Node
->CommandString
!= NULL
);
457 if (gUnicodeCollation
->StriColl(
459 (CHAR16
*)CommandString
,
460 Node
->CommandString
) == 0
462 return (HiiGetString(Node
->HiiHandle
, Node
->ManFormatHelp
, NULL
));
469 Get the help text for a command.
471 @param[in] CommandString The command name.
473 @retval NULL No help text was found.
474 @return String of help text.Caller reuiqred to free.
478 ShellCommandGetCommandHelp (
479 IN CONST CHAR16
*CommandString
483 HelpStr
= ShellCommandGetInternalCommandHelp(CommandString
);
485 if (HelpStr
== NULL
) {
486 HelpStr
= ShellCommandGetDynamicCommandHelp(CommandString
);
494 Registers handlers of type SHELL_RUN_COMMAND and
495 SHELL_GET_MAN_FILENAME for each shell command.
497 If the ShellSupportLevel is greater than the value of the
498 PcdShellSupportLevel then return RETURN_UNSUPPORTED.
500 Registers the handlers specified by GetHelpInfoHandler and CommandHandler
501 with the command specified by CommandString. If the command named by
502 CommandString has already been registered, then return
503 RETURN_ALREADY_STARTED.
505 If there are not enough resources available to register the handlers then
506 RETURN_OUT_OF_RESOURCES is returned.
508 If CommandString is NULL, then ASSERT().
509 If GetHelpInfoHandler is NULL, then ASSERT().
510 If CommandHandler is NULL, then ASSERT().
511 If ProfileName is NULL, then ASSERT().
513 @param[in] CommandString Pointer to the command name. This is the
514 name to look for on the command line in
516 @param[in] CommandHandler Pointer to a function that runs the
518 @param[in] GetManFileName Pointer to a function that provides man
520 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
522 @param[in] ProfileName profile name to require for support of this
524 @param[in] CanAffectLE indicates whether this command's return value
525 can change the LASTERROR environment variable.
526 @param[in] HiiHandle Handle of this command's HII entry.
527 @param[in] ManFormatHelp HII locator for the help text.
529 @retval RETURN_SUCCESS The handlers were registered.
530 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
531 register the shell command.
532 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
533 currently allowed support level.
534 @retval RETURN_ALREADY_STARTED The CommandString represents a command that
535 is already registered. Only 1 handler set for
536 a given command is allowed.
537 @sa SHELL_GET_MAN_FILENAME
538 @sa SHELL_RUN_COMMAND
542 ShellCommandRegisterCommandName (
543 IN CONST CHAR16
*CommandString
,
544 IN SHELL_RUN_COMMAND CommandHandler
,
545 IN SHELL_GET_MAN_FILENAME GetManFileName
,
546 IN UINT32 ShellMinSupportLevel
,
547 IN CONST CHAR16
*ProfileName
,
548 IN CONST BOOLEAN CanAffectLE
,
549 IN CONST EFI_HANDLE HiiHandle
,
550 IN CONST EFI_STRING_ID ManFormatHelp
553 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
554 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Command
;
555 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*PrevCommand
;
556 INTN LexicalMatchValue
;
559 // Initialize local variables.
563 LexicalMatchValue
= 0;
566 // ASSERTs for NULL parameters
568 ASSERT(CommandString
!= NULL
);
569 ASSERT(GetManFileName
!= NULL
);
570 ASSERT(CommandHandler
!= NULL
);
571 ASSERT(ProfileName
!= NULL
);
574 // check for shell support level
576 if (PcdGet8(PcdShellSupportLevel
) < ShellMinSupportLevel
) {
577 return (RETURN_UNSUPPORTED
);
581 // check for already on the list
583 if (ShellCommandIsCommandOnList(CommandString
)) {
584 return (RETURN_ALREADY_STARTED
);
588 // allocate memory for new struct
590 Node
= AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY
));
592 return RETURN_OUT_OF_RESOURCES
;
594 Node
->CommandString
= AllocateCopyPool(StrSize(CommandString
), CommandString
);
595 if (Node
->CommandString
== NULL
) {
597 return RETURN_OUT_OF_RESOURCES
;
600 Node
->GetManFileName
= GetManFileName
;
601 Node
->CommandHandler
= CommandHandler
;
602 Node
->LastError
= CanAffectLE
;
603 Node
->HiiHandle
= HiiHandle
;
604 Node
->ManFormatHelp
= ManFormatHelp
;
606 if ( StrLen(ProfileName
)>0
607 && ((mProfileList
!= NULL
608 && StrStr(mProfileList
, ProfileName
) == NULL
) || mProfileList
== NULL
)
610 ASSERT((mProfileList
== NULL
&& mProfileListSize
== 0) || (mProfileList
!= NULL
));
611 if (mProfileList
== NULL
) {
613 // If this is the first make a leading ';'
615 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
617 StrnCatGrow(&mProfileList
, &mProfileListSize
, ProfileName
, 0);
618 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
622 // Insert a new entry on top of the list
624 InsertHeadList (&mCommandList
.Link
, &Node
->Link
);
627 // Move a new registered command to its sorted ordered location in the list
629 for (Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
),
630 PrevCommand
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
)
631 ; !IsNull (&mCommandList
.Link
, &Command
->Link
)
632 ; Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode (&mCommandList
.Link
, &Command
->Link
)) {
635 // Get Lexical Comparison Value between PrevCommand and Command list entry
637 LexicalMatchValue
= gUnicodeCollation
->StriColl (
639 PrevCommand
->CommandString
,
640 Command
->CommandString
644 // Swap PrevCommand and Command list entry if PrevCommand list entry
645 // is alphabetically greater than Command list entry
647 if (LexicalMatchValue
> 0){
648 Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*) SwapListEntries (&PrevCommand
->Link
, &Command
->Link
);
649 } else if (LexicalMatchValue
< 0) {
651 // PrevCommand entry is lexically lower than Command entry
657 return (RETURN_SUCCESS
);
661 Function to get the current Profile string.
663 @retval NULL There are no installed profiles.
664 @return A semi-colon delimited list of profiles.
668 ShellCommandGetProfileList (
672 return (mProfileList
);
676 Checks if a command string has been registered for CommandString and if so it runs
677 the previously registered handler for that command with the command line.
679 If CommandString is NULL, then ASSERT().
681 If Sections is specified, then each section name listed will be compared in a casesensitive
682 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
683 it will be appended to the returned help text. If the section does not exist, no
684 information will be returned. If Sections is NULL, then all help text information
685 available will be returned.
687 @param[in] CommandString Pointer to the command name. This is the name
688 found on the command line in the shell.
689 @param[in, out] RetVal Pointer to the return vaule from the command handler.
691 @param[in, out] CanAffectLE indicates whether this command's return value
692 needs to be placed into LASTERROR environment variable.
694 @retval RETURN_SUCCESS The handler was run.
695 @retval RETURN_NOT_FOUND The CommandString did not match a registered
697 @sa SHELL_RUN_COMMAND
701 ShellCommandRunCommandHandler (
702 IN CONST CHAR16
*CommandString
,
703 IN OUT SHELL_STATUS
*RetVal
,
704 IN OUT BOOLEAN
*CanAffectLE OPTIONAL
707 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
708 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
711 // assert for NULL parameters
713 ASSERT(CommandString
!= NULL
);
716 // check for the command
718 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
719 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
720 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
722 ASSERT(Node
->CommandString
!= NULL
);
723 if (gUnicodeCollation
->StriColl(
725 (CHAR16
*)CommandString
,
726 Node
->CommandString
) == 0
728 if (CanAffectLE
!= NULL
) {
729 *CanAffectLE
= Node
->LastError
;
731 if (RetVal
!= NULL
) {
732 *RetVal
= Node
->CommandHandler(NULL
, gST
);
734 Node
->CommandHandler(NULL
, gST
);
736 return (RETURN_SUCCESS
);
741 // An internal command was not found, try to find a dynamic command
743 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
744 if (DynamicCommand
!= NULL
) {
745 if (RetVal
!= NULL
) {
746 *RetVal
= DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
748 DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
750 return (RETURN_SUCCESS
);
753 return (RETURN_NOT_FOUND
);
757 Checks if a command string has been registered for CommandString and if so it
758 returns the MAN filename specified for that command.
760 If CommandString is NULL, then ASSERT().
762 @param[in] CommandString Pointer to the command name. This is the name
763 found on the command line in the shell.\
765 @retval NULL the commandString was not a registered command.
766 @return other the name of the MAN file.
767 @sa SHELL_GET_MAN_FILENAME
771 ShellCommandGetManFileNameHandler (
772 IN CONST CHAR16
*CommandString
775 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
778 // assert for NULL parameters
780 ASSERT(CommandString
!= NULL
);
783 // check for the command
785 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
786 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
787 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
789 ASSERT(Node
->CommandString
!= NULL
);
790 if (gUnicodeCollation
->StriColl(
792 (CHAR16
*)CommandString
,
793 Node
->CommandString
) == 0
795 return (Node
->GetManFileName());
802 Get the list of all available shell internal commands. This is a linked list
803 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
804 list functions. do not modify the values.
806 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
808 @return a Linked list of all available shell commands.
812 ShellCommandGetCommandList (
813 IN CONST BOOLEAN Sort
817 // return ((COMMAND_LIST*)(&mCommandList));
819 return ((COMMAND_LIST
*)(&mCommandList
));
823 Registers aliases to be set as part of the initialization of the shell application.
825 If Command is NULL, then ASSERT().
826 If Alias is NULL, then ASSERT().
828 @param[in] Command Pointer to the Command
829 @param[in] Alias Pointer to Alias
831 @retval RETURN_SUCCESS The handlers were registered.
832 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
833 register the shell command.
837 ShellCommandRegisterAlias (
838 IN CONST CHAR16
*Command
,
839 IN CONST CHAR16
*Alias
843 ALIAS_LIST
*CommandAlias
;
844 ALIAS_LIST
*PrevCommandAlias
;
845 INTN LexicalMatchValue
;
850 ASSERT(Command
!= NULL
);
851 ASSERT(Alias
!= NULL
);
854 // allocate memory for new struct
856 Node
= AllocateZeroPool(sizeof(ALIAS_LIST
));
858 return RETURN_OUT_OF_RESOURCES
;
860 Node
->CommandString
= AllocateCopyPool(StrSize(Command
), Command
);
861 if (Node
->CommandString
== NULL
) {
863 return RETURN_OUT_OF_RESOURCES
;
865 Node
->Alias
= AllocateCopyPool(StrSize(Alias
), Alias
);
866 if (Node
->Alias
== NULL
) {
867 FreePool (Node
->CommandString
);
869 return RETURN_OUT_OF_RESOURCES
;
872 InsertHeadList (&mAliasList
.Link
, &Node
->Link
);
875 // Move a new pre-defined registered alias to its sorted ordered location in the list
877 for ( CommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
),
878 PrevCommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
)
879 ; !IsNull (&mAliasList
.Link
, &CommandAlias
->Link
)
880 ; CommandAlias
= (ALIAS_LIST
*) GetNextNode (&mAliasList
.Link
, &CommandAlias
->Link
) ) {
882 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
884 LexicalMatchValue
= gUnicodeCollation
->StriColl (
886 PrevCommandAlias
->Alias
,
891 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
892 // is alphabetically greater than CommandAlias list entry
894 if (LexicalMatchValue
> 0) {
895 CommandAlias
= (ALIAS_LIST
*) SwapListEntries (&PrevCommandAlias
->Link
, &CommandAlias
->Link
);
896 } else if (LexicalMatchValue
< 0) {
898 // PrevCommandAlias entry is lexically lower than CommandAlias entry
904 return (RETURN_SUCCESS
);
908 Get the list of all shell alias commands. This is a linked list
909 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
910 list functions. do not modify the values.
912 @return a Linked list of all requested shell alias'.
916 ShellCommandGetInitAliasList (
920 return (&mAliasList
);
924 Determine if a given alias is on the list of built in alias'.
926 @param[in] Alias The alias to test for
928 @retval TRUE The alias is a built in alias
929 @retval FALSE The alias is not a built in alias
933 ShellCommandIsOnAliasList(
934 IN CONST CHAR16
*Alias
940 // assert for NULL parameter
942 ASSERT(Alias
!= NULL
);
945 // check for the Alias
947 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
)
948 ; !IsNull(&mAliasList
.Link
, &Node
->Link
)
949 ; Node
= (ALIAS_LIST
*)GetNextNode(&mAliasList
.Link
, &Node
->Link
)
951 ASSERT(Node
->CommandString
!= NULL
);
952 ASSERT(Node
->Alias
!= NULL
);
953 if (gUnicodeCollation
->StriColl(
956 Node
->CommandString
) == 0
960 if (gUnicodeCollation
->StriColl(
972 Function to determine current state of ECHO. Echo determines if lines from scripts
973 and ECHO commands are enabled.
975 @retval TRUE Echo is currently enabled
976 @retval FALSE Echo is currently disabled
980 ShellCommandGetEchoState(
988 Function to set current state of ECHO. Echo determines if lines from scripts
989 and ECHO commands are enabled.
991 If State is TRUE, Echo will be enabled.
992 If State is FALSE, Echo will be disabled.
994 @param[in] State How to set echo.
998 ShellCommandSetEchoState(
1006 Indicate that the current shell or script should exit.
1008 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
1009 @param[in] ErrorCode The 64 bit error code to return.
1013 ShellCommandRegisterExit (
1014 IN BOOLEAN ScriptOnly
,
1015 IN CONST UINT64 ErrorCode
1018 mExitRequested
= (BOOLEAN
)(!mExitRequested
);
1019 if (mExitRequested
) {
1020 mExitScript
= ScriptOnly
;
1022 mExitScript
= FALSE
;
1024 mExitCode
= ErrorCode
;
1028 Retrieve the Exit indicator.
1030 @retval TRUE Exit was indicated.
1031 @retval FALSE Exis was not indicated.
1035 ShellCommandGetExit (
1039 return (mExitRequested
);
1043 Retrieve the Exit code.
1045 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1047 @return the value passed into RegisterExit.
1051 ShellCommandGetExitCode (
1058 Retrieve the Exit script indicator.
1060 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1062 @retval TRUE ScriptOnly was indicated.
1063 @retval FALSE ScriptOnly was not indicated.
1067 ShellCommandGetScriptExit (
1071 return (mExitScript
);
1075 Function to cleanup all memory from a SCRIPT_FILE structure.
1077 @param[in] Script The pointer to the structure to cleanup.
1081 DeleteScriptFileStruct (
1082 IN SCRIPT_FILE
*Script
1087 if (Script
== NULL
) {
1091 for (LoopVar
= 0 ; LoopVar
< Script
->Argc
; LoopVar
++) {
1092 SHELL_FREE_NON_NULL(Script
->Argv
[LoopVar
]);
1094 if (Script
->Argv
!= NULL
) {
1095 SHELL_FREE_NON_NULL(Script
->Argv
);
1097 Script
->CurrentCommand
= NULL
;
1098 while (!IsListEmpty (&Script
->CommandList
)) {
1099 Script
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&Script
->CommandList
);
1100 if (Script
->CurrentCommand
!= NULL
) {
1101 RemoveEntryList(&Script
->CurrentCommand
->Link
);
1102 if (Script
->CurrentCommand
->Cl
!= NULL
) {
1103 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Cl
);
1105 if (Script
->CurrentCommand
->Data
!= NULL
) {
1106 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Data
);
1108 SHELL_FREE_NON_NULL(Script
->CurrentCommand
);
1111 SHELL_FREE_NON_NULL(Script
->ScriptName
);
1112 SHELL_FREE_NON_NULL(Script
);
1116 Function to return a pointer to the currently running script file object.
1118 @retval NULL A script file is not currently running.
1119 @return A pointer to the current script file object.
1123 ShellCommandGetCurrentScriptFile (
1127 SCRIPT_FILE_LIST
*List
;
1128 if (IsListEmpty (&mScriptList
.Link
)) {
1131 List
= ((SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
));
1132 return (List
->Data
);
1136 Function to set a new script as the currently running one.
1138 This function will correctly stack and unstack nested scripts.
1140 @param[in] Script Pointer to new script information structure. if NULL
1141 will remove and de-allocate the top-most Script structure.
1143 @return A pointer to the current running script file after this
1144 change. NULL if removing the final script.
1148 ShellCommandSetNewScript (
1149 IN SCRIPT_FILE
*Script OPTIONAL
1152 SCRIPT_FILE_LIST
*Node
;
1153 if (Script
== NULL
) {
1154 if (IsListEmpty (&mScriptList
.Link
)) {
1157 Node
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
1158 RemoveEntryList(&Node
->Link
);
1159 DeleteScriptFileStruct(Node
->Data
);
1162 Node
= AllocateZeroPool(sizeof(SCRIPT_FILE_LIST
));
1166 Node
->Data
= Script
;
1167 InsertHeadList(&mScriptList
.Link
, &Node
->Link
);
1169 return (ShellCommandGetCurrentScriptFile());
1173 Function to generate the next default mapping name.
1175 If the return value is not NULL then it must be callee freed.
1177 @param Type What kind of mapping name to make.
1179 @retval NULL a memory allocation failed.
1180 @return a new map name string
1184 ShellCommandCreateNewMappingName(
1185 IN CONST SHELL_MAPPING_TYPE Type
1189 ASSERT(Type
< MappingTypeMax
);
1193 String
= AllocateZeroPool(PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]));
1196 PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]),
1197 Type
== MappingTypeFileSystem
?L
"FS%d:":L
"BLK%d:",
1198 Type
== MappingTypeFileSystem
?mFsMaxCount
++:mBlkMaxCount
++);
1204 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
1206 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
1207 default paths on the new map name...
1209 Path should be FALSE when this function is called from the protocol SetMap function.
1211 @param[in] Name The human readable mapped name.
1212 @param[in] DevicePath The Device Path for this map.
1213 @param[in] Flags The Flags attribute for this map item.
1214 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
1216 @retval EFI_SUCCESS The addition was sucessful.
1217 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1218 @retval EFI_INVALID_PARAMETER A parameter was invalid.
1222 ShellCommandAddMapItemAndUpdatePath(
1223 IN CONST CHAR16
*Name
,
1224 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1225 IN CONST UINT64 Flags
,
1226 IN CONST BOOLEAN Path
1230 SHELL_MAP_LIST
*MapListNode
;
1231 CONST CHAR16
*OriginalPath
;
1237 OriginalPath
= NULL
;
1238 Status
= EFI_SUCCESS
;
1240 MapListNode
= AllocateZeroPool(sizeof(SHELL_MAP_LIST
));
1241 if (MapListNode
== NULL
) {
1242 Status
= EFI_OUT_OF_RESOURCES
;
1244 MapListNode
->Flags
= Flags
;
1245 MapListNode
->MapName
= AllocateCopyPool(StrSize(Name
), Name
);
1246 MapListNode
->DevicePath
= DuplicateDevicePath(DevicePath
);
1247 if ((MapListNode
->MapName
== NULL
) || (MapListNode
->DevicePath
== NULL
)){
1248 Status
= EFI_OUT_OF_RESOURCES
;
1250 InsertTailList(&gShellMapList
.Link
, &MapListNode
->Link
);
1253 if (EFI_ERROR(Status
)) {
1254 if (MapListNode
!= NULL
) {
1255 if (MapListNode
->DevicePath
!= NULL
) {
1256 FreePool(MapListNode
->DevicePath
);
1258 if (MapListNode
->MapName
!= NULL
) {
1259 FreePool(MapListNode
->MapName
);
1261 FreePool(MapListNode
);
1265 // Since there was no error and Path was TRUE
1266 // Now add the correct path for that mapping
1268 OriginalPath
= gEfiShellProtocol
->GetEnv(L
"path");
1269 ASSERT((NewPath
== NULL
&& NewPathSize
== 0) || (NewPath
!= NULL
));
1270 if (OriginalPath
!= NULL
) {
1271 StrnCatGrow(&NewPath
, &NewPathSize
, OriginalPath
, 0);
1272 StrnCatGrow(&NewPath
, &NewPathSize
, L
";", 0);
1274 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1275 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\tools\\;", 0);
1276 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1277 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\boot\\;", 0);
1278 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1279 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\", 0);
1281 Status
= gEfiShellProtocol
->SetEnv(L
"path", NewPath
, TRUE
);
1282 ASSERT_EFI_ERROR(Status
);
1289 Creates the default map names for each device path in the system with
1290 a protocol depending on the Type.
1292 Creates the consistent map names for each device path in the system with
1293 a protocol depending on the Type.
1295 Note: This will reset all mappings in the system("map -r").
1297 Also sets up the default path environment variable if Type is FileSystem.
1299 @retval EFI_SUCCESS All map names were created sucessfully.
1300 @retval EFI_NOT_FOUND No protocols were found in the system.
1301 @return Error returned from gBS->LocateHandle().
1307 ShellCommandCreateInitialMappingsAndPaths(
1312 EFI_HANDLE
*HandleList
;
1314 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1315 CHAR16
*NewDefaultName
;
1316 CHAR16
*NewConsistName
;
1317 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1318 SHELL_MAP_LIST
*MapListNode
;
1319 CONST CHAR16
*CurDir
;
1320 CHAR16
*SplitCurDir
;
1322 SHELL_MAP_LIST
*MapListItem
;
1330 // Reset the static members back to zero
1335 gEfiShellProtocol
->SetEnv(L
"path", L
"", TRUE
);
1338 // First empty out the existing list.
1340 if (!IsListEmpty(&gShellMapList
.Link
)) {
1341 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1342 ; !IsListEmpty(&gShellMapList
.Link
)
1343 ; MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1345 RemoveEntryList(&MapListNode
->Link
);
1346 SHELL_FREE_NON_NULL(MapListNode
->DevicePath
);
1347 SHELL_FREE_NON_NULL(MapListNode
->MapName
);
1348 SHELL_FREE_NON_NULL(MapListNode
->CurrentDirectoryPath
);
1349 FreePool(MapListNode
);
1354 // Find each handle with Simple File System
1356 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1357 if (HandleList
!= NULL
) {
1359 // Do a count of the handles
1361 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1364 // Get all Device Paths
1366 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1367 if (DevicePathList
== NULL
) {
1368 SHELL_FREE_NON_NULL (HandleList
);
1369 return EFI_OUT_OF_RESOURCES
;
1372 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1373 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1377 // Sort all DevicePaths
1379 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1381 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1383 // Assign new Mappings to all...
1385 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1387 // Get default name first
1389 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1390 ASSERT(NewDefaultName
!= NULL
);
1391 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, TRUE
);
1392 ASSERT_EFI_ERROR(Status
);
1393 FreePool(NewDefaultName
);
1396 // Now do consistent name
1398 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1399 if (NewConsistName
!= NULL
) {
1400 Status
= ShellCommandAddMapItemAndUpdatePath(NewConsistName
, DevicePathList
[Count
], 0, FALSE
);
1401 ASSERT_EFI_ERROR(Status
);
1402 FreePool(NewConsistName
);
1406 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1408 SHELL_FREE_NON_NULL(HandleList
);
1409 SHELL_FREE_NON_NULL(DevicePathList
);
1414 //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,
1415 //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,
1416 //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.
1418 if (gShellCurMapping
!= NULL
) {
1419 gShellCurMapping
= NULL
;
1420 CurDir
= gEfiShellProtocol
->GetEnv(L
"cwd");
1421 if (CurDir
!= NULL
) {
1422 MapName
= AllocateCopyPool (StrSize(CurDir
), CurDir
);
1423 if (MapName
== NULL
) {
1424 return EFI_OUT_OF_RESOURCES
;
1426 SplitCurDir
= StrStr (MapName
, L
":");
1427 if (SplitCurDir
== NULL
) {
1428 SHELL_FREE_NON_NULL (MapName
);
1429 return EFI_UNSUPPORTED
;
1431 *(SplitCurDir
+ 1) = CHAR_NULL
;
1432 MapListItem
= ShellCommandFindMapItem (MapName
);
1433 if (MapListItem
!= NULL
) {
1434 gShellCurMapping
= MapListItem
;
1436 SHELL_FREE_NON_NULL (MapName
);
1444 // Find each handle with Block Io
1446 HandleList
= GetHandleListByProtocol(&gEfiBlockIoProtocolGuid
);
1447 if (HandleList
!= NULL
) {
1448 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1451 // Get all Device Paths
1453 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1454 if (DevicePathList
== NULL
) {
1455 SHELL_FREE_NON_NULL (HandleList
);
1456 return EFI_OUT_OF_RESOURCES
;
1459 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1460 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1464 // Sort all DevicePaths
1466 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1469 // Assign new Mappings to all...
1471 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1473 // Get default name first
1475 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeBlockIo
);
1476 ASSERT(NewDefaultName
!= NULL
);
1477 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, FALSE
);
1478 ASSERT_EFI_ERROR(Status
);
1479 FreePool(NewDefaultName
);
1482 SHELL_FREE_NON_NULL(HandleList
);
1483 SHELL_FREE_NON_NULL(DevicePathList
);
1484 } else if (Count
== (UINTN
)-1) {
1485 return (EFI_NOT_FOUND
);
1488 return (EFI_SUCCESS
);
1492 Add mappings for any devices without one. Do not change any existing maps.
1494 @retval EFI_SUCCESS The operation was successful.
1498 ShellCommandUpdateMapping (
1503 EFI_HANDLE
*HandleList
;
1505 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1506 CHAR16
*NewDefaultName
;
1507 CHAR16
*NewConsistName
;
1508 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1511 Status
= EFI_SUCCESS
;
1514 // remove mappings that represent removed devices.
1518 // Find each handle with Simple File System
1520 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1521 if (HandleList
!= NULL
) {
1523 // Do a count of the handles
1525 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1528 // Get all Device Paths
1530 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1531 if (DevicePathList
== NULL
) {
1532 return (EFI_OUT_OF_RESOURCES
);
1535 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1536 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1540 // Sort all DevicePaths
1542 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1544 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1547 // Assign new Mappings to remainders
1549 for (Count
= 0 ; !EFI_ERROR(Status
) && HandleList
[Count
] != NULL
&& !EFI_ERROR(Status
); Count
++) {
1551 // Skip ones that already have
1553 if (gEfiShellProtocol
->GetMapFromDevicePath(&DevicePathList
[Count
]) != NULL
) {
1559 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1560 if (NewDefaultName
== NULL
) {
1561 Status
= EFI_OUT_OF_RESOURCES
;
1566 // Call shell protocol SetMap function now...
1568 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewDefaultName
);
1570 if (!EFI_ERROR(Status
)) {
1572 // Now do consistent name
1574 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1575 if (NewConsistName
!= NULL
) {
1576 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewConsistName
);
1577 FreePool(NewConsistName
);
1581 FreePool(NewDefaultName
);
1583 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1584 SHELL_FREE_NON_NULL(HandleList
);
1585 SHELL_FREE_NON_NULL(DevicePathList
);
1592 // Do it all over again for gEfiBlockIoProtocolGuid
1599 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1601 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1603 @return a EFI_FILE_PROTOCOL* representing the same file.
1607 ConvertShellHandleToEfiFileProtocol(
1608 IN CONST SHELL_FILE_HANDLE Handle
1611 return ((EFI_FILE_PROTOCOL
*)(Handle
));
1615 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1617 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1618 @param[in] Path The path to the file for verification.
1620 @return A SHELL_FILE_HANDLE representing the same file.
1621 @retval NULL There was not enough memory.
1625 ConvertEfiFileProtocolToShellHandle(
1626 IN CONST EFI_FILE_PROTOCOL
*Handle
,
1627 IN CONST CHAR16
*Path
1630 SHELL_COMMAND_FILE_HANDLE
*Buffer
;
1631 BUFFER_LIST
*NewNode
;
1634 Buffer
= AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE
));
1635 if (Buffer
== NULL
) {
1638 NewNode
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1639 if (NewNode
== NULL
) {
1640 SHELL_FREE_NON_NULL(Buffer
);
1643 Buffer
->FileHandle
= (EFI_FILE_PROTOCOL
*)Handle
;
1644 Buffer
->Path
= StrnCatGrow(&Buffer
->Path
, NULL
, Path
, 0);
1645 if (Buffer
->Path
== NULL
) {
1646 SHELL_FREE_NON_NULL(NewNode
);
1647 SHELL_FREE_NON_NULL(Buffer
);
1650 NewNode
->Buffer
= Buffer
;
1652 InsertHeadList(&mFileHandleList
.Link
, &NewNode
->Link
);
1654 return ((SHELL_FILE_HANDLE
)(Handle
));
1658 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1660 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1662 @return A pointer to the path for the file.
1666 ShellFileHandleGetPath(
1667 IN CONST SHELL_FILE_HANDLE Handle
1672 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1673 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1674 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1676 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1677 return (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1684 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1686 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1688 @retval TRUE The item was removed.
1689 @retval FALSE The item was not found.
1693 ShellFileHandleRemove(
1694 IN CONST SHELL_FILE_HANDLE Handle
1699 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1700 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1701 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1703 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1704 RemoveEntryList(&Node
->Link
);
1705 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1706 SHELL_FREE_NON_NULL(Node
->Buffer
);
1707 SHELL_FREE_NON_NULL(Node
);
1715 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1717 This will NOT work on directories.
1719 If Handle is NULL, then ASSERT.
1721 @param[in] Handle the file handle
1723 @retval TRUE the position is at the end of the file
1724 @retval FALSE the position is not at the end of the file
1729 IN SHELL_FILE_HANDLE Handle
1732 EFI_FILE_INFO
*Info
;
1737 // ASSERT if Handle is NULL
1739 ASSERT(Handle
!= NULL
);
1741 gEfiShellProtocol
->GetFilePosition(Handle
, &Pos
);
1742 Info
= gEfiShellProtocol
->GetFileInfo (Handle
);
1743 gEfiShellProtocol
->SetFilePosition(Handle
, Pos
);
1749 if (Pos
== Info
->FileSize
) {
1761 Frees any BUFFER_LIST defined type.
1763 @param[in] List The BUFFER_LIST object to free.
1768 IN BUFFER_LIST
*List
1771 BUFFER_LIST
*BufferListEntry
;
1777 // enumerate through the buffer list and free all memory
1779 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1780 ; !IsListEmpty (&List
->Link
)
1781 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1783 RemoveEntryList(&BufferListEntry
->Link
);
1784 if (BufferListEntry
->Buffer
!= NULL
) {
1785 FreePool(BufferListEntry
->Buffer
);
1787 FreePool(BufferListEntry
);
1792 Dump some hexadecimal data to the screen.
1794 @param[in] Indent How many spaces to indent the output.
1795 @param[in] Offset The offset of the printing.
1796 @param[in] DataSize The size in bytes of UserData.
1797 @param[in] UserData The data to print out.
1819 while (DataSize
!= 0) {
1821 if (Size
> DataSize
) {
1825 for (Index
= 0; Index
< Size
; Index
+= 1) {
1826 TempByte
= Data
[Index
];
1827 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1828 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1829 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1830 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> '~') ? '.' : TempByte
);
1835 ShellPrintEx(-1, -1, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1844 Dump HEX data into buffer.
1846 @param[in] Buffer HEX data to be dumped in Buffer.
1847 @param[in] Indent How many spaces to indent the output.
1848 @param[in] Offset The offset of the printing.
1849 @param[in] DataSize The size in bytes of UserData.
1850 @param[in] UserData The data to print out.
1873 while (DataSize
!= 0) {
1875 if (Size
> DataSize
) {
1879 for (Index
= 0; Index
< Size
; Index
+= 1) {
1880 TempByte
= Data
[Index
];
1881 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1882 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1883 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1884 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> 'z') ? '.' : TempByte
);
1889 TempRetVal
= CatSPrint (RetVal
, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1890 SHELL_FREE_NON_NULL (RetVal
);
1891 RetVal
= TempRetVal
;