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 if (gUnicodeCollation
== NULL
) {
79 GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME
, (VOID
**)&PlatformLang
, NULL
);
81 Status
= gBS
->LocateHandleBuffer (
83 &gEfiUnicodeCollation2ProtocolGuid
,
88 if (EFI_ERROR (Status
)) {
92 for (Index
= 0; Index
< NumHandles
; Index
++) {
94 // Open Unicode Collation Protocol
96 Status
= gBS
->OpenProtocol (
98 &gEfiUnicodeCollation2ProtocolGuid
,
102 EFI_OPEN_PROTOCOL_GET_PROTOCOL
104 if (EFI_ERROR (Status
)) {
109 // Without clue provided use the first Unicode Collation2 protocol.
111 if (PlatformLang
== NULL
) {
112 gUnicodeCollation
= Uc
;
117 // Find the best matching matching language from the supported languages
118 // of Unicode Collation2 protocol.
120 BestLanguage
= GetBestLanguage (
121 Uc
->SupportedLanguages
,
126 if (BestLanguage
!= NULL
) {
127 FreePool (BestLanguage
);
128 gUnicodeCollation
= Uc
;
132 if (Handles
!= NULL
) {
135 if (PlatformLang
!= NULL
) {
136 FreePool (PlatformLang
);
140 return (gUnicodeCollation
== NULL
) ? EFI_UNSUPPORTED
: EFI_SUCCESS
;
144 Constructor for the Shell Command library.
146 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
148 @param ImageHandle the image handle of the process
149 @param SystemTable the EFI System Table pointer
151 @retval EFI_SUCCESS the initialization was complete sucessfully
155 ShellCommandLibConstructor (
156 IN EFI_HANDLE ImageHandle
,
157 IN EFI_SYSTEM_TABLE
*SystemTable
161 InitializeListHead(&gShellMapList
.Link
);
162 InitializeListHead(&mCommandList
.Link
);
163 InitializeListHead(&mAliasList
.Link
);
164 InitializeListHead(&mScriptList
.Link
);
165 InitializeListHead(&mFileHandleList
.Link
);
168 mExitRequested
= FALSE
;
170 mProfileListSize
= 0;
173 Status
= CommandInit ();
174 if (EFI_ERROR (Status
)) {
175 return EFI_DEVICE_ERROR
;
178 return (RETURN_SUCCESS
);
182 Frees list of file handles.
184 @param[in] List The list to free.
191 BUFFER_LIST
*BufferListEntry
;
197 // enumerate through the buffer list and free all memory
199 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
200 ; !IsListEmpty (&List
->Link
)
201 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
203 RemoveEntryList(&BufferListEntry
->Link
);
204 ASSERT(BufferListEntry
->Buffer
!= NULL
);
205 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)(BufferListEntry
->Buffer
))->Path
);
206 SHELL_FREE_NON_NULL(BufferListEntry
->Buffer
);
207 SHELL_FREE_NON_NULL(BufferListEntry
);
212 Destructor for the library. free any resources.
214 @param ImageHandle the image handle of the process
215 @param SystemTable the EFI System Table pointer
217 @retval RETURN_SUCCESS this function always returns success
221 ShellCommandLibDestructor (
222 IN EFI_HANDLE ImageHandle
,
223 IN EFI_SYSTEM_TABLE
*SystemTable
226 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
228 SCRIPT_FILE_LIST
*Node3
;
229 SHELL_MAP_LIST
*MapNode
;
231 // enumerate throught the list and free all the memory
233 while (!IsListEmpty (&mCommandList
.Link
)) {
234 Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
);
235 RemoveEntryList(&Node
->Link
);
236 SHELL_FREE_NON_NULL(Node
->CommandString
);
238 DEBUG_CODE(Node
= NULL
;);
242 // enumerate through the alias list and free all memory
244 while (!IsListEmpty (&mAliasList
.Link
)) {
245 Node2
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
);
246 RemoveEntryList(&Node2
->Link
);
247 SHELL_FREE_NON_NULL(Node2
->CommandString
);
248 SHELL_FREE_NON_NULL(Node2
->Alias
);
249 SHELL_FREE_NON_NULL(Node2
);
250 DEBUG_CODE(Node2
= NULL
;);
254 // enumerate throught the list and free all the memory
256 while (!IsListEmpty (&mScriptList
.Link
)) {
257 Node3
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
258 RemoveEntryList(&Node3
->Link
);
259 DeleteScriptFileStruct(Node3
->Data
);
264 // enumerate throught the mappings list and free all the memory
266 if (!IsListEmpty(&gShellMapList
.Link
)) {
267 for (MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
268 ; !IsListEmpty (&gShellMapList
.Link
)
269 ; MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
271 ASSERT(MapNode
!= NULL
);
272 RemoveEntryList(&MapNode
->Link
);
273 SHELL_FREE_NON_NULL(MapNode
->DevicePath
);
274 SHELL_FREE_NON_NULL(MapNode
->MapName
);
275 SHELL_FREE_NON_NULL(MapNode
->CurrentDirectoryPath
);
279 if (!IsListEmpty(&mFileHandleList
.Link
)){
280 FreeFileHandleList(&mFileHandleList
);
283 if (mProfileList
!= NULL
) {
284 FreePool(mProfileList
);
287 gUnicodeCollation
= NULL
;
288 gShellCurMapping
= NULL
;
290 return (RETURN_SUCCESS
);
294 Find a dynamic command protocol instance given a command name string.
296 @param CommandString the command name string
298 @return instance the command protocol instance, if dynamic command instance found
299 @retval NULL no dynamic command protocol instance found for name
301 CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*
302 ShellCommandFindDynamicCommand (
303 IN CONST CHAR16
*CommandString
307 EFI_HANDLE
*CommandHandleList
;
308 EFI_HANDLE
*NextCommand
;
309 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
311 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
312 if (CommandHandleList
== NULL
) {
314 // not found or out of resources
319 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
320 Status
= gBS
->HandleProtocol(
322 &gEfiShellDynamicCommandProtocolGuid
,
323 (VOID
**)&DynamicCommand
326 if (EFI_ERROR(Status
)) {
330 if (gUnicodeCollation
->StriColl(
332 (CHAR16
*)CommandString
,
333 (CHAR16
*)DynamicCommand
->CommandName
) == 0
335 FreePool(CommandHandleList
);
336 return (DynamicCommand
);
340 FreePool(CommandHandleList
);
345 Checks if a command exists as a dynamic command protocol instance
347 @param[in] CommandString The command string to check for on the list.
350 ShellCommandDynamicCommandExists (
351 IN CONST CHAR16
*CommandString
354 return (BOOLEAN
) ((ShellCommandFindDynamicCommand(CommandString
) != NULL
));
358 Checks if a command is already on the internal command list.
360 @param[in] CommandString The command string to check for on the list.
363 ShellCommandIsCommandOnInternalList(
364 IN CONST CHAR16
*CommandString
367 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
370 // assert for NULL parameter
372 ASSERT(CommandString
!= NULL
);
375 // check for the command
377 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
378 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
379 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
381 ASSERT(Node
->CommandString
!= NULL
);
382 if (gUnicodeCollation
->StriColl(
384 (CHAR16
*)CommandString
,
385 Node
->CommandString
) == 0
394 Checks if a command exists, either internally or through the dynamic command protocol.
396 @param[in] CommandString The command string to check for on the list.
400 ShellCommandIsCommandOnList(
401 IN CONST CHAR16
*CommandString
404 if (ShellCommandIsCommandOnInternalList(CommandString
)) {
408 return ShellCommandDynamicCommandExists(CommandString
);
412 Get the help text for a dynamic command.
414 @param[in] CommandString The command name.
416 @retval NULL No help text was found.
417 @return String of help text. Caller required to free.
420 ShellCommandGetDynamicCommandHelp(
421 IN CONST CHAR16
*CommandString
424 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
426 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
427 if (DynamicCommand
== NULL
) {
432 // TODO: how to get proper language?
434 return DynamicCommand
->GetHelp(DynamicCommand
, "en");
438 Get the help text for an internal command.
440 @param[in] CommandString The command name.
442 @retval NULL No help text was found.
443 @return String of help text. Caller reuiqred to free.
446 ShellCommandGetInternalCommandHelp(
447 IN CONST CHAR16
*CommandString
450 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
453 // assert for NULL parameter
455 ASSERT(CommandString
!= NULL
);
458 // check for the command
460 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
461 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
462 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
464 ASSERT(Node
->CommandString
!= NULL
);
465 if (gUnicodeCollation
->StriColl(
467 (CHAR16
*)CommandString
,
468 Node
->CommandString
) == 0
470 return (HiiGetString(Node
->HiiHandle
, Node
->ManFormatHelp
, NULL
));
477 Get the help text for a command.
479 @param[in] CommandString The command name.
481 @retval NULL No help text was found.
482 @return String of help text.Caller reuiqred to free.
486 ShellCommandGetCommandHelp (
487 IN CONST CHAR16
*CommandString
491 HelpStr
= ShellCommandGetInternalCommandHelp(CommandString
);
493 if (HelpStr
== NULL
) {
494 HelpStr
= ShellCommandGetDynamicCommandHelp(CommandString
);
502 Registers handlers of type SHELL_RUN_COMMAND and
503 SHELL_GET_MAN_FILENAME for each shell command.
505 If the ShellSupportLevel is greater than the value of the
506 PcdShellSupportLevel then return RETURN_UNSUPPORTED.
508 Registers the handlers specified by GetHelpInfoHandler and CommandHandler
509 with the command specified by CommandString. If the command named by
510 CommandString has already been registered, then return
511 RETURN_ALREADY_STARTED.
513 If there are not enough resources available to register the handlers then
514 RETURN_OUT_OF_RESOURCES is returned.
516 If CommandString is NULL, then ASSERT().
517 If GetHelpInfoHandler is NULL, then ASSERT().
518 If CommandHandler is NULL, then ASSERT().
519 If ProfileName is NULL, then ASSERT().
521 @param[in] CommandString Pointer to the command name. This is the
522 name to look for on the command line in
524 @param[in] CommandHandler Pointer to a function that runs the
526 @param[in] GetManFileName Pointer to a function that provides man
528 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
530 @param[in] ProfileName profile name to require for support of this
532 @param[in] CanAffectLE indicates whether this command's return value
533 can change the LASTERROR environment variable.
534 @param[in] HiiHandle Handle of this command's HII entry.
535 @param[in] ManFormatHelp HII locator for the help text.
537 @retval RETURN_SUCCESS The handlers were registered.
538 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
539 register the shell command.
540 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
541 currently allowed support level.
542 @retval RETURN_ALREADY_STARTED The CommandString represents a command that
543 is already registered. Only 1 handler set for
544 a given command is allowed.
545 @sa SHELL_GET_MAN_FILENAME
546 @sa SHELL_RUN_COMMAND
550 ShellCommandRegisterCommandName (
551 IN CONST CHAR16
*CommandString
,
552 IN SHELL_RUN_COMMAND CommandHandler
,
553 IN SHELL_GET_MAN_FILENAME GetManFileName
,
554 IN UINT32 ShellMinSupportLevel
,
555 IN CONST CHAR16
*ProfileName
,
556 IN CONST BOOLEAN CanAffectLE
,
557 IN CONST EFI_HII_HANDLE HiiHandle
,
558 IN CONST EFI_STRING_ID ManFormatHelp
561 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
562 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Command
;
563 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*PrevCommand
;
564 INTN LexicalMatchValue
;
567 // Initialize local variables.
571 LexicalMatchValue
= 0;
574 // ASSERTs for NULL parameters
576 ASSERT(CommandString
!= NULL
);
577 ASSERT(GetManFileName
!= NULL
);
578 ASSERT(CommandHandler
!= NULL
);
579 ASSERT(ProfileName
!= NULL
);
582 // check for shell support level
584 if (PcdGet8(PcdShellSupportLevel
) < ShellMinSupportLevel
) {
585 return (RETURN_UNSUPPORTED
);
589 // check for already on the list
591 if (ShellCommandIsCommandOnList(CommandString
)) {
592 return (RETURN_ALREADY_STARTED
);
596 // allocate memory for new struct
598 Node
= AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY
));
600 return RETURN_OUT_OF_RESOURCES
;
602 Node
->CommandString
= AllocateCopyPool(StrSize(CommandString
), CommandString
);
603 if (Node
->CommandString
== NULL
) {
605 return RETURN_OUT_OF_RESOURCES
;
608 Node
->GetManFileName
= GetManFileName
;
609 Node
->CommandHandler
= CommandHandler
;
610 Node
->LastError
= CanAffectLE
;
611 Node
->HiiHandle
= HiiHandle
;
612 Node
->ManFormatHelp
= ManFormatHelp
;
614 if ( StrLen(ProfileName
)>0
615 && ((mProfileList
!= NULL
616 && StrStr(mProfileList
, ProfileName
) == NULL
) || mProfileList
== NULL
)
618 ASSERT((mProfileList
== NULL
&& mProfileListSize
== 0) || (mProfileList
!= NULL
));
619 if (mProfileList
== NULL
) {
621 // If this is the first make a leading ';'
623 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
625 StrnCatGrow(&mProfileList
, &mProfileListSize
, ProfileName
, 0);
626 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
630 // Insert a new entry on top of the list
632 InsertHeadList (&mCommandList
.Link
, &Node
->Link
);
635 // Move a new registered command to its sorted ordered location in the list
637 for (Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
),
638 PrevCommand
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
)
639 ; !IsNull (&mCommandList
.Link
, &Command
->Link
)
640 ; Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode (&mCommandList
.Link
, &Command
->Link
)) {
643 // Get Lexical Comparison Value between PrevCommand and Command list entry
645 LexicalMatchValue
= gUnicodeCollation
->StriColl (
647 PrevCommand
->CommandString
,
648 Command
->CommandString
652 // Swap PrevCommand and Command list entry if PrevCommand list entry
653 // is alphabetically greater than Command list entry
655 if (LexicalMatchValue
> 0){
656 Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*) SwapListEntries (&PrevCommand
->Link
, &Command
->Link
);
657 } else if (LexicalMatchValue
< 0) {
659 // PrevCommand entry is lexically lower than Command entry
665 return (RETURN_SUCCESS
);
669 Function to get the current Profile string.
671 @retval NULL There are no installed profiles.
672 @return A semi-colon delimited list of profiles.
676 ShellCommandGetProfileList (
680 return (mProfileList
);
684 Checks if a command string has been registered for CommandString and if so it runs
685 the previously registered handler for that command with the command line.
687 If CommandString is NULL, then ASSERT().
689 If Sections is specified, then each section name listed will be compared in a casesensitive
690 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
691 it will be appended to the returned help text. If the section does not exist, no
692 information will be returned. If Sections is NULL, then all help text information
693 available will be returned.
695 @param[in] CommandString Pointer to the command name. This is the name
696 found on the command line in the shell.
697 @param[in, out] RetVal Pointer to the return vaule from the command handler.
699 @param[in, out] CanAffectLE indicates whether this command's return value
700 needs to be placed into LASTERROR environment variable.
702 @retval RETURN_SUCCESS The handler was run.
703 @retval RETURN_NOT_FOUND The CommandString did not match a registered
705 @sa SHELL_RUN_COMMAND
709 ShellCommandRunCommandHandler (
710 IN CONST CHAR16
*CommandString
,
711 IN OUT SHELL_STATUS
*RetVal
,
712 IN OUT BOOLEAN
*CanAffectLE OPTIONAL
715 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
716 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
719 // assert for NULL parameters
721 ASSERT(CommandString
!= NULL
);
724 // check for the command
726 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
727 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
728 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
730 ASSERT(Node
->CommandString
!= NULL
);
731 if (gUnicodeCollation
->StriColl(
733 (CHAR16
*)CommandString
,
734 Node
->CommandString
) == 0
736 if (CanAffectLE
!= NULL
) {
737 *CanAffectLE
= Node
->LastError
;
739 if (RetVal
!= NULL
) {
740 *RetVal
= Node
->CommandHandler(NULL
, gST
);
742 Node
->CommandHandler(NULL
, gST
);
744 return (RETURN_SUCCESS
);
749 // An internal command was not found, try to find a dynamic command
751 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
752 if (DynamicCommand
!= NULL
) {
753 if (RetVal
!= NULL
) {
754 *RetVal
= DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
756 DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
758 return (RETURN_SUCCESS
);
761 return (RETURN_NOT_FOUND
);
765 Checks if a command string has been registered for CommandString and if so it
766 returns the MAN filename specified for that command.
768 If CommandString is NULL, then ASSERT().
770 @param[in] CommandString Pointer to the command name. This is the name
771 found on the command line in the shell.\
773 @retval NULL the commandString was not a registered command.
774 @return other the name of the MAN file.
775 @sa SHELL_GET_MAN_FILENAME
779 ShellCommandGetManFileNameHandler (
780 IN CONST CHAR16
*CommandString
783 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
786 // assert for NULL parameters
788 ASSERT(CommandString
!= NULL
);
791 // check for the command
793 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
794 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
795 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
797 ASSERT(Node
->CommandString
!= NULL
);
798 if (gUnicodeCollation
->StriColl(
800 (CHAR16
*)CommandString
,
801 Node
->CommandString
) == 0
803 return (Node
->GetManFileName());
810 Get the list of all available shell internal commands. This is a linked list
811 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
812 list functions. do not modify the values.
814 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
816 @return a Linked list of all available shell commands.
820 ShellCommandGetCommandList (
821 IN CONST BOOLEAN Sort
825 // return ((COMMAND_LIST*)(&mCommandList));
827 return ((COMMAND_LIST
*)(&mCommandList
));
831 Registers aliases to be set as part of the initialization of the shell application.
833 If Command is NULL, then ASSERT().
834 If Alias is NULL, then ASSERT().
836 @param[in] Command Pointer to the Command
837 @param[in] Alias Pointer to Alias
839 @retval RETURN_SUCCESS The handlers were registered.
840 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
841 register the shell command.
845 ShellCommandRegisterAlias (
846 IN CONST CHAR16
*Command
,
847 IN CONST CHAR16
*Alias
851 ALIAS_LIST
*CommandAlias
;
852 ALIAS_LIST
*PrevCommandAlias
;
853 INTN LexicalMatchValue
;
858 ASSERT(Command
!= NULL
);
859 ASSERT(Alias
!= NULL
);
862 // allocate memory for new struct
864 Node
= AllocateZeroPool(sizeof(ALIAS_LIST
));
866 return RETURN_OUT_OF_RESOURCES
;
868 Node
->CommandString
= AllocateCopyPool(StrSize(Command
), Command
);
869 if (Node
->CommandString
== NULL
) {
871 return RETURN_OUT_OF_RESOURCES
;
873 Node
->Alias
= AllocateCopyPool(StrSize(Alias
), Alias
);
874 if (Node
->Alias
== NULL
) {
875 FreePool (Node
->CommandString
);
877 return RETURN_OUT_OF_RESOURCES
;
880 InsertHeadList (&mAliasList
.Link
, &Node
->Link
);
883 // Move a new pre-defined registered alias to its sorted ordered location in the list
885 for ( CommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
),
886 PrevCommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
)
887 ; !IsNull (&mAliasList
.Link
, &CommandAlias
->Link
)
888 ; CommandAlias
= (ALIAS_LIST
*) GetNextNode (&mAliasList
.Link
, &CommandAlias
->Link
) ) {
890 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
892 LexicalMatchValue
= gUnicodeCollation
->StriColl (
894 PrevCommandAlias
->Alias
,
899 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
900 // is alphabetically greater than CommandAlias list entry
902 if (LexicalMatchValue
> 0) {
903 CommandAlias
= (ALIAS_LIST
*) SwapListEntries (&PrevCommandAlias
->Link
, &CommandAlias
->Link
);
904 } else if (LexicalMatchValue
< 0) {
906 // PrevCommandAlias entry is lexically lower than CommandAlias entry
912 return (RETURN_SUCCESS
);
916 Get the list of all shell alias commands. This is a linked list
917 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
918 list functions. do not modify the values.
920 @return a Linked list of all requested shell alias'.
924 ShellCommandGetInitAliasList (
928 return (&mAliasList
);
932 Determine if a given alias is on the list of built in alias'.
934 @param[in] Alias The alias to test for
936 @retval TRUE The alias is a built in alias
937 @retval FALSE The alias is not a built in alias
941 ShellCommandIsOnAliasList(
942 IN CONST CHAR16
*Alias
948 // assert for NULL parameter
950 ASSERT(Alias
!= NULL
);
953 // check for the Alias
955 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
)
956 ; !IsNull(&mAliasList
.Link
, &Node
->Link
)
957 ; Node
= (ALIAS_LIST
*)GetNextNode(&mAliasList
.Link
, &Node
->Link
)
959 ASSERT(Node
->CommandString
!= NULL
);
960 ASSERT(Node
->Alias
!= NULL
);
961 if (gUnicodeCollation
->StriColl(
964 Node
->CommandString
) == 0
968 if (gUnicodeCollation
->StriColl(
980 Function to determine current state of ECHO. Echo determines if lines from scripts
981 and ECHO commands are enabled.
983 @retval TRUE Echo is currently enabled
984 @retval FALSE Echo is currently disabled
988 ShellCommandGetEchoState(
996 Function to set current state of ECHO. Echo determines if lines from scripts
997 and ECHO commands are enabled.
999 If State is TRUE, Echo will be enabled.
1000 If State is FALSE, Echo will be disabled.
1002 @param[in] State How to set echo.
1006 ShellCommandSetEchoState(
1014 Indicate that the current shell or script should exit.
1016 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
1017 @param[in] ErrorCode The 64 bit error code to return.
1021 ShellCommandRegisterExit (
1022 IN BOOLEAN ScriptOnly
,
1023 IN CONST UINT64 ErrorCode
1026 mExitRequested
= (BOOLEAN
)(!mExitRequested
);
1027 if (mExitRequested
) {
1028 mExitScript
= ScriptOnly
;
1030 mExitScript
= FALSE
;
1032 mExitCode
= ErrorCode
;
1036 Retrieve the Exit indicator.
1038 @retval TRUE Exit was indicated.
1039 @retval FALSE Exis was not indicated.
1043 ShellCommandGetExit (
1047 return (mExitRequested
);
1051 Retrieve the Exit code.
1053 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1055 @return the value passed into RegisterExit.
1059 ShellCommandGetExitCode (
1066 Retrieve the Exit script indicator.
1068 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1070 @retval TRUE ScriptOnly was indicated.
1071 @retval FALSE ScriptOnly was not indicated.
1075 ShellCommandGetScriptExit (
1079 return (mExitScript
);
1083 Function to cleanup all memory from a SCRIPT_FILE structure.
1085 @param[in] Script The pointer to the structure to cleanup.
1089 DeleteScriptFileStruct (
1090 IN SCRIPT_FILE
*Script
1095 if (Script
== NULL
) {
1099 for (LoopVar
= 0 ; LoopVar
< Script
->Argc
; LoopVar
++) {
1100 SHELL_FREE_NON_NULL(Script
->Argv
[LoopVar
]);
1102 if (Script
->Argv
!= NULL
) {
1103 SHELL_FREE_NON_NULL(Script
->Argv
);
1105 Script
->CurrentCommand
= NULL
;
1106 while (!IsListEmpty (&Script
->CommandList
)) {
1107 Script
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&Script
->CommandList
);
1108 if (Script
->CurrentCommand
!= NULL
) {
1109 RemoveEntryList(&Script
->CurrentCommand
->Link
);
1110 if (Script
->CurrentCommand
->Cl
!= NULL
) {
1111 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Cl
);
1113 if (Script
->CurrentCommand
->Data
!= NULL
) {
1114 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Data
);
1116 SHELL_FREE_NON_NULL(Script
->CurrentCommand
);
1119 SHELL_FREE_NON_NULL(Script
->ScriptName
);
1120 SHELL_FREE_NON_NULL(Script
);
1124 Function to return a pointer to the currently running script file object.
1126 @retval NULL A script file is not currently running.
1127 @return A pointer to the current script file object.
1131 ShellCommandGetCurrentScriptFile (
1135 SCRIPT_FILE_LIST
*List
;
1136 if (IsListEmpty (&mScriptList
.Link
)) {
1139 List
= ((SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
));
1140 return (List
->Data
);
1144 Function to set a new script as the currently running one.
1146 This function will correctly stack and unstack nested scripts.
1148 @param[in] Script Pointer to new script information structure. if NULL
1149 will remove and de-allocate the top-most Script structure.
1151 @return A pointer to the current running script file after this
1152 change. NULL if removing the final script.
1156 ShellCommandSetNewScript (
1157 IN SCRIPT_FILE
*Script OPTIONAL
1160 SCRIPT_FILE_LIST
*Node
;
1161 if (Script
== NULL
) {
1162 if (IsListEmpty (&mScriptList
.Link
)) {
1165 Node
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
1166 RemoveEntryList(&Node
->Link
);
1167 DeleteScriptFileStruct(Node
->Data
);
1170 Node
= AllocateZeroPool(sizeof(SCRIPT_FILE_LIST
));
1174 Node
->Data
= Script
;
1175 InsertHeadList(&mScriptList
.Link
, &Node
->Link
);
1177 return (ShellCommandGetCurrentScriptFile());
1181 Function to generate the next default mapping name.
1183 If the return value is not NULL then it must be callee freed.
1185 @param Type What kind of mapping name to make.
1187 @retval NULL a memory allocation failed.
1188 @return a new map name string
1192 ShellCommandCreateNewMappingName(
1193 IN CONST SHELL_MAPPING_TYPE Type
1197 ASSERT(Type
< MappingTypeMax
);
1201 String
= AllocateZeroPool(PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]));
1204 PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]),
1205 Type
== MappingTypeFileSystem
?L
"FS%d:":L
"BLK%d:",
1206 Type
== MappingTypeFileSystem
?mFsMaxCount
++:mBlkMaxCount
++);
1212 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
1214 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
1215 default paths on the new map name...
1217 Path should be FALSE when this function is called from the protocol SetMap function.
1219 @param[in] Name The human readable mapped name.
1220 @param[in] DevicePath The Device Path for this map.
1221 @param[in] Flags The Flags attribute for this map item.
1222 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
1224 @retval EFI_SUCCESS The addition was sucessful.
1225 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1226 @retval EFI_INVALID_PARAMETER A parameter was invalid.
1230 ShellCommandAddMapItemAndUpdatePath(
1231 IN CONST CHAR16
*Name
,
1232 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1233 IN CONST UINT64 Flags
,
1234 IN CONST BOOLEAN Path
1238 SHELL_MAP_LIST
*MapListNode
;
1239 CONST CHAR16
*OriginalPath
;
1245 OriginalPath
= NULL
;
1246 Status
= EFI_SUCCESS
;
1248 MapListNode
= AllocateZeroPool(sizeof(SHELL_MAP_LIST
));
1249 if (MapListNode
== NULL
) {
1250 Status
= EFI_OUT_OF_RESOURCES
;
1252 MapListNode
->Flags
= Flags
;
1253 MapListNode
->MapName
= AllocateCopyPool(StrSize(Name
), Name
);
1254 MapListNode
->DevicePath
= DuplicateDevicePath(DevicePath
);
1255 if ((MapListNode
->MapName
== NULL
) || (MapListNode
->DevicePath
== NULL
)){
1256 Status
= EFI_OUT_OF_RESOURCES
;
1258 InsertTailList(&gShellMapList
.Link
, &MapListNode
->Link
);
1261 if (EFI_ERROR(Status
)) {
1262 if (MapListNode
!= NULL
) {
1263 if (MapListNode
->DevicePath
!= NULL
) {
1264 FreePool(MapListNode
->DevicePath
);
1266 if (MapListNode
->MapName
!= NULL
) {
1267 FreePool(MapListNode
->MapName
);
1269 FreePool(MapListNode
);
1273 // Since there was no error and Path was TRUE
1274 // Now add the correct path for that mapping
1276 OriginalPath
= gEfiShellProtocol
->GetEnv(L
"path");
1277 ASSERT((NewPath
== NULL
&& NewPathSize
== 0) || (NewPath
!= NULL
));
1278 if (OriginalPath
!= NULL
) {
1279 StrnCatGrow(&NewPath
, &NewPathSize
, OriginalPath
, 0);
1280 StrnCatGrow(&NewPath
, &NewPathSize
, L
";", 0);
1282 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1283 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\tools\\;", 0);
1284 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1285 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\boot\\;", 0);
1286 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1287 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\", 0);
1289 Status
= gEfiShellProtocol
->SetEnv(L
"path", NewPath
, TRUE
);
1290 ASSERT_EFI_ERROR(Status
);
1297 Creates the default map names for each device path in the system with
1298 a protocol depending on the Type.
1300 Creates the consistent map names for each device path in the system with
1301 a protocol depending on the Type.
1303 Note: This will reset all mappings in the system("map -r").
1305 Also sets up the default path environment variable if Type is FileSystem.
1307 @retval EFI_SUCCESS All map names were created sucessfully.
1308 @retval EFI_NOT_FOUND No protocols were found in the system.
1309 @return Error returned from gBS->LocateHandle().
1315 ShellCommandCreateInitialMappingsAndPaths(
1320 EFI_HANDLE
*HandleList
;
1322 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1323 CHAR16
*NewDefaultName
;
1324 CHAR16
*NewConsistName
;
1325 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1326 SHELL_MAP_LIST
*MapListNode
;
1327 CONST CHAR16
*CurDir
;
1328 CHAR16
*SplitCurDir
;
1330 SHELL_MAP_LIST
*MapListItem
;
1338 // Reset the static members back to zero
1343 gEfiShellProtocol
->SetEnv(L
"path", L
"", TRUE
);
1346 // First empty out the existing list.
1348 if (!IsListEmpty(&gShellMapList
.Link
)) {
1349 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1350 ; !IsListEmpty(&gShellMapList
.Link
)
1351 ; MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1353 RemoveEntryList(&MapListNode
->Link
);
1354 SHELL_FREE_NON_NULL(MapListNode
->DevicePath
);
1355 SHELL_FREE_NON_NULL(MapListNode
->MapName
);
1356 SHELL_FREE_NON_NULL(MapListNode
->CurrentDirectoryPath
);
1357 FreePool(MapListNode
);
1362 // Find each handle with Simple File System
1364 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1365 if (HandleList
!= NULL
) {
1367 // Do a count of the handles
1369 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1372 // Get all Device Paths
1374 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1375 if (DevicePathList
== NULL
) {
1376 SHELL_FREE_NON_NULL (HandleList
);
1377 return EFI_OUT_OF_RESOURCES
;
1380 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1381 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1385 // Sort all DevicePaths
1387 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1389 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1391 // Assign new Mappings to all...
1393 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1395 // Get default name first
1397 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1398 ASSERT(NewDefaultName
!= NULL
);
1399 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, TRUE
);
1400 ASSERT_EFI_ERROR(Status
);
1401 FreePool(NewDefaultName
);
1404 // Now do consistent name
1406 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1407 if (NewConsistName
!= NULL
) {
1408 Status
= ShellCommandAddMapItemAndUpdatePath(NewConsistName
, DevicePathList
[Count
], 0, FALSE
);
1409 ASSERT_EFI_ERROR(Status
);
1410 FreePool(NewConsistName
);
1414 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1416 SHELL_FREE_NON_NULL(HandleList
);
1417 SHELL_FREE_NON_NULL(DevicePathList
);
1422 //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,
1423 //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,
1424 //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.
1426 if (gShellCurMapping
!= NULL
) {
1427 gShellCurMapping
= NULL
;
1428 CurDir
= gEfiShellProtocol
->GetEnv(L
"cwd");
1429 if (CurDir
!= NULL
) {
1430 MapName
= AllocateCopyPool (StrSize(CurDir
), CurDir
);
1431 if (MapName
== NULL
) {
1432 return EFI_OUT_OF_RESOURCES
;
1434 SplitCurDir
= StrStr (MapName
, L
":");
1435 if (SplitCurDir
== NULL
) {
1436 SHELL_FREE_NON_NULL (MapName
);
1437 return EFI_UNSUPPORTED
;
1439 *(SplitCurDir
+ 1) = CHAR_NULL
;
1440 MapListItem
= ShellCommandFindMapItem (MapName
);
1441 if (MapListItem
!= NULL
) {
1442 gShellCurMapping
= MapListItem
;
1444 SHELL_FREE_NON_NULL (MapName
);
1452 // Find each handle with Block Io
1454 HandleList
= GetHandleListByProtocol(&gEfiBlockIoProtocolGuid
);
1455 if (HandleList
!= NULL
) {
1456 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1459 // Get all Device Paths
1461 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1462 if (DevicePathList
== NULL
) {
1463 SHELL_FREE_NON_NULL (HandleList
);
1464 return EFI_OUT_OF_RESOURCES
;
1467 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1468 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1472 // Sort all DevicePaths
1474 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1477 // Assign new Mappings to all...
1479 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1481 // Get default name first
1483 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeBlockIo
);
1484 ASSERT(NewDefaultName
!= NULL
);
1485 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, FALSE
);
1486 ASSERT_EFI_ERROR(Status
);
1487 FreePool(NewDefaultName
);
1490 SHELL_FREE_NON_NULL(HandleList
);
1491 SHELL_FREE_NON_NULL(DevicePathList
);
1492 } else if (Count
== (UINTN
)-1) {
1493 return (EFI_NOT_FOUND
);
1496 return (EFI_SUCCESS
);
1500 Add mappings for any devices without one. Do not change any existing maps.
1502 @retval EFI_SUCCESS The operation was successful.
1506 ShellCommandUpdateMapping (
1511 EFI_HANDLE
*HandleList
;
1513 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1514 CHAR16
*NewDefaultName
;
1515 CHAR16
*NewConsistName
;
1516 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1519 Status
= EFI_SUCCESS
;
1522 // remove mappings that represent removed devices.
1526 // Find each handle with Simple File System
1528 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1529 if (HandleList
!= NULL
) {
1531 // Do a count of the handles
1533 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1536 // Get all Device Paths
1538 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1539 if (DevicePathList
== NULL
) {
1540 return (EFI_OUT_OF_RESOURCES
);
1543 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1544 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1548 // Sort all DevicePaths
1550 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1552 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1555 // Assign new Mappings to remainders
1557 for (Count
= 0 ; !EFI_ERROR(Status
) && HandleList
[Count
] != NULL
&& !EFI_ERROR(Status
); Count
++) {
1559 // Skip ones that already have
1561 if (gEfiShellProtocol
->GetMapFromDevicePath(&DevicePathList
[Count
]) != NULL
) {
1567 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1568 if (NewDefaultName
== NULL
) {
1569 Status
= EFI_OUT_OF_RESOURCES
;
1574 // Call shell protocol SetMap function now...
1576 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewDefaultName
);
1578 if (!EFI_ERROR(Status
)) {
1580 // Now do consistent name
1582 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1583 if (NewConsistName
!= NULL
) {
1584 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewConsistName
);
1585 FreePool(NewConsistName
);
1589 FreePool(NewDefaultName
);
1591 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1592 SHELL_FREE_NON_NULL(HandleList
);
1593 SHELL_FREE_NON_NULL(DevicePathList
);
1600 // Do it all over again for gEfiBlockIoProtocolGuid
1607 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1609 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1611 @return a EFI_FILE_PROTOCOL* representing the same file.
1615 ConvertShellHandleToEfiFileProtocol(
1616 IN CONST SHELL_FILE_HANDLE Handle
1619 return ((EFI_FILE_PROTOCOL
*)(Handle
));
1623 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1625 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1626 @param[in] Path The path to the file for verification.
1628 @return A SHELL_FILE_HANDLE representing the same file.
1629 @retval NULL There was not enough memory.
1633 ConvertEfiFileProtocolToShellHandle(
1634 IN CONST EFI_FILE_PROTOCOL
*Handle
,
1635 IN CONST CHAR16
*Path
1638 SHELL_COMMAND_FILE_HANDLE
*Buffer
;
1639 BUFFER_LIST
*NewNode
;
1642 Buffer
= AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE
));
1643 if (Buffer
== NULL
) {
1646 NewNode
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1647 if (NewNode
== NULL
) {
1648 SHELL_FREE_NON_NULL(Buffer
);
1651 Buffer
->FileHandle
= (EFI_FILE_PROTOCOL
*)Handle
;
1652 Buffer
->Path
= StrnCatGrow(&Buffer
->Path
, NULL
, Path
, 0);
1653 if (Buffer
->Path
== NULL
) {
1654 SHELL_FREE_NON_NULL(NewNode
);
1655 SHELL_FREE_NON_NULL(Buffer
);
1658 NewNode
->Buffer
= Buffer
;
1660 InsertHeadList(&mFileHandleList
.Link
, &NewNode
->Link
);
1662 return ((SHELL_FILE_HANDLE
)(Handle
));
1666 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1668 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1670 @return A pointer to the path for the file.
1674 ShellFileHandleGetPath(
1675 IN CONST SHELL_FILE_HANDLE Handle
1680 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1681 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1682 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1684 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1685 return (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1692 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1694 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1696 @retval TRUE The item was removed.
1697 @retval FALSE The item was not found.
1701 ShellFileHandleRemove(
1702 IN CONST SHELL_FILE_HANDLE Handle
1707 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1708 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1709 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1711 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1712 RemoveEntryList(&Node
->Link
);
1713 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1714 SHELL_FREE_NON_NULL(Node
->Buffer
);
1715 SHELL_FREE_NON_NULL(Node
);
1723 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1725 This will NOT work on directories.
1727 If Handle is NULL, then ASSERT.
1729 @param[in] Handle the file handle
1731 @retval TRUE the position is at the end of the file
1732 @retval FALSE the position is not at the end of the file
1737 IN SHELL_FILE_HANDLE Handle
1740 EFI_FILE_INFO
*Info
;
1745 // ASSERT if Handle is NULL
1747 ASSERT(Handle
!= NULL
);
1749 gEfiShellProtocol
->GetFilePosition(Handle
, &Pos
);
1750 Info
= gEfiShellProtocol
->GetFileInfo (Handle
);
1751 gEfiShellProtocol
->SetFilePosition(Handle
, Pos
);
1757 if (Pos
== Info
->FileSize
) {
1769 Frees any BUFFER_LIST defined type.
1771 @param[in] List The BUFFER_LIST object to free.
1776 IN BUFFER_LIST
*List
1779 BUFFER_LIST
*BufferListEntry
;
1785 // enumerate through the buffer list and free all memory
1787 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1788 ; !IsListEmpty (&List
->Link
)
1789 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1791 RemoveEntryList(&BufferListEntry
->Link
);
1792 if (BufferListEntry
->Buffer
!= NULL
) {
1793 FreePool(BufferListEntry
->Buffer
);
1795 FreePool(BufferListEntry
);
1800 Dump some hexadecimal data to the screen.
1802 @param[in] Indent How many spaces to indent the output.
1803 @param[in] Offset The offset of the printing.
1804 @param[in] DataSize The size in bytes of UserData.
1805 @param[in] UserData The data to print out.
1827 while (DataSize
!= 0) {
1829 if (Size
> DataSize
) {
1833 for (Index
= 0; Index
< Size
; Index
+= 1) {
1834 TempByte
= Data
[Index
];
1835 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1836 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1837 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1838 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> '~') ? '.' : TempByte
);
1843 ShellPrintEx(-1, -1, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1852 Dump HEX data into buffer.
1854 @param[in] Buffer HEX data to be dumped in Buffer.
1855 @param[in] Indent How many spaces to indent the output.
1856 @param[in] Offset The offset of the printing.
1857 @param[in] DataSize The size in bytes of UserData.
1858 @param[in] UserData The data to print out.
1881 while (DataSize
!= 0) {
1883 if (Size
> DataSize
) {
1887 for (Index
= 0; Index
< Size
; Index
+= 1) {
1888 TempByte
= Data
[Index
];
1889 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1890 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1891 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1892 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> 'z') ? '.' : TempByte
);
1897 TempRetVal
= CatSPrint (RetVal
, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1898 SHELL_FREE_NON_NULL (RetVal
);
1899 RetVal
= TempRetVal
;